Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 623 Vote(s) - 3.55 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Always pass weak reference of self into block in ARC?

#1
I am a little confused about block usage in Objective-C. I currently use ARC and I have quite a lot of blocks in my app, currently always referring to `self` instead of its weak reference. May that be the cause of these blocks retaining `self` and keeping it from being dealloced ? The question is, should I always use a `weak` reference of `self` in a block ?

-(void)handleNewerData:(NSArray *)arr
{
ProcessOperation *operation =
[[ProcessOperation alloc] initWithDataToProcess:arr
completion:^(NSMutableArray *rows) {
dispatch_async(dispatch_get_main_queue(), ^{
[self updateFeed:arr rows:rows];
});
}];
[dataProcessQueue addOperation:operation];
}

**ProcessOperation.h**

@interface ProcessOperation : NSOperation
{
NSMutableArray *dataArr;
NSMutableArray *rowHeightsArr;
void (^callback)(NSMutableArray *rows);
}

**ProcessOperation.m**

-(id)initWithDataToProcess:(NSArray *)data completion:(void (^)(NSMutableArray *rows))cb{

if(self =[super init]){
dataArr = [NSMutableArray arrayWithArray:data];
rowHeightsArr = [NSMutableArray new];
callback = cb;
}
return self;
}

- (void)main {
@autoreleasepool {
...
callback(rowHeightsArr);
}
}
Reply

#2
You don't have to always use a weak reference. If your block is not retained, but executed and then discarded, you can capture self strongly, as it will not create a retain cycle. In some cases, you even want the block to hold the self until the completion of the block so it does not deallocate prematurely. If, however, you capture the block strongly, and inside capture self, it will create a retain cycle.
Reply

#3
It helps not to focus on the `strong` or `weak` part of the discussion. Instead focus on the *cycle* part.

A retain *cycle* is a loop that happens when Object A retains Object B, *and* Object B retains Object A. In that situation, if either object is released:

* Object A won't be deallocated because Object B holds a reference to it.
* But Object B won't ever be deallocated as long as Object A has a reference to it.
* But Object A will never be deallocated because Object B holds a reference to it.
* *ad infinitum*

Thus, those two objects will just hang around in memory for the life of the program even though they should, if everything were working properly, be deallocated.

So, what we're worried about is retain *cycles*, and there's nothing about blocks in and of themselves that create these cycles. This isn't a problem, for example:

[myArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
[self doSomethingWithObject:obj];
}];

The block retains `self`, but `self` doesn't retain the block. If one or the other is released, no cycle is created and everything gets deallocated as it should.

Where you get into trouble is something like:

//In the interface:
@property (strong) void(^myBlock)(id obj, NSUInteger idx, BOOL *stop);

//In the implementation:
[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[self doSomethingWithObj:obj];
}];

Now, your object (`self`) has an explicit `strong` reference to the block. And the block has an *implicit* strong reference to `self`. That's a cycle, and now neither object will be deallocated properly.

Because, in a situation like this, `self` *by definition* already has a `strong` reference to the block, it's usually easiest to resolve by making an explicitly weak reference to `self` for the block to use:

__weak MyObject *weakSelf = self;
[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[weakSelf doSomethingWithObj:obj];
}];

**But this should not be the default pattern you follow** when dealing with blocks that call `self`! This should only be used to break what would otherwise be a retain cycle between self and the block. If you were to adopt this pattern everywhere, you'd run the risk of passing a block to something that got executed after `self` was deallocated.

//SUSPICIOUS EXAMPLE:
__weak MyObject *weakSelf = self;
[[SomeOtherObject alloc] initWithCompletion:^{
//By the time this gets called, "weakSelf" might be nil because it's not retained!
[weakSelf doSomething];
}];
Reply

#4
Some explanation ignore a condition about the retain cycle [If a group of objects is connected by a circle of strong relationships, they keep each other alive even if there are no strong references from outside the group.] For more information, read the [document][1]


[1]:

[To see links please register here]

Reply

#5
As Leo points out, the code you added to your question would not suggest a strong reference cycle (a.k.a., retain cycle). One operation-related issue that could cause a strong reference cycle would be if the operation is not getting released. While your code snippet suggests that you have not defined your operation to be concurrent, but if you have, it wouldn't be released if you never posted `isFinished`, or if you had circular dependencies, or something like that. And if the operation isn't released, the view controller wouldn't be released either. I would suggest adding a breakpoint or `NSLog` in your operation's `dealloc` method and confirm that's getting called.

You said:

> I understand the notion of retain cycles, but I am not quite sure what happens in blocks, so that confuses me a little bit

The retain cycle (strong reference cycle) issues that occur with blocks are just like the retain cycle issues you're familiar with. A block will maintain strong references to any objects that appear within the block, and it will not release those strong references until the block itself is released. Thus, if block references `self`, or even just references an instance variable of `self`, that will maintain strong reference to self, that is not resolved until the block is released (or in this case, until the `NSOperation` subclass is released.

For more information, see the [Avoid Strong Reference Cycles when Capturing self][1] section of the _Programming with Objective-C: Working with Blocks_ document.

If your view controller is still not getting released, you simply have to identify where the unresolved strong reference resides (assuming you confirmed the `NSOperation` is getting deallocated). A common example is the use of a repeating `NSTimer`. Or some custom `delegate` or other object that is erroneously maintaining a `strong` reference. You can often use Instruments to track down where objects are getting their strong references, e.g.:

![record reference counts in Xcode 6][2]

Or in Xcode 5:

![record reference counts in Xcode 5][3]


[1]:

[To see links please register here]

[2]:

[3]:
Reply

#6
This is how you can use the self inside the block:


//calling of the block

NSString *returnedText= checkIfOutsideMethodIsCalled(self);

************************************************************

NSString* (^checkIfOutsideMethodIsCalled)(*)=^NSString*(id obj)
{
[obj MethodNameYouWantToCall]; // this is how it will call the object
return @"Called";


};
Reply

#7
I totally agree with @jemmons:

> But this should not be the default pattern you follow when dealing with blocks that call self! This should only be used to break what would otherwise be a retain cycle between self and the block. If you were to adopt this pattern everywhere, you'd run the risk of passing a block to something that got executed after self was deallocated.

> ```objc
//SUSPICIOUS EXAMPLE:
__weak MyObject *weakSelf = self;
[[SomeOtherObject alloc] initWithCompletion:^{
//By the time this gets called, "weakSelf" might be nil because it's not retained!
[weakSelf doSomething];
}];
> ```

To overcome this problem one can define a strong reference over the `weakSelf` inside the block:

```objc
__weak MyObject *weakSelf = self;
[[SomeOtherObject alloc] initWithCompletion:^{
MyObject *strongSelf = weakSelf;
[strongSelf doSomething];
}];
```
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through