Will this hold self inside a block? - objective-c

OK, this code on ARC holds self inside the block:
dispatch_async(someQ, ^{
[self doSomething];
});
and that can be solved by
__weak MyRequest *weakSelf = self;
dispatch_async(someQ, ^{
[weakSelf doSomething];
});
but what if doSomething has a lot of references to self? Because doSomething code will run inside the block isn't the same of all code of doSomething is on the block directly?
Do I need to pass weakSelf to doSomething so the method can use weakself references instead of self? Something like
__weak MyRequest *weakSelf = self;
dispatch_async(someQ, ^{
[weakSelf doSomethingUsingThisSelf:weakself];
});

By doing:
MyRequest *__weak weakSelf = self;
dispatch_async(someQ, ^{
[weakSelf doSomething];
});
...when there are no more references to self, weakSelf automatically becomes nil. So the async callback will end up sending doSomething to nil in the even the object is destroyed before the callback, which will do nothing.
If weakSelf is not nil, it's just a pointer to an object. When you send a selector to an object, there two implicit arguments: self and _cmd (see the documentation for IMP), section 6.1). So weakSelf becomes the implicit self in those calls. At that point, self is a strong reference, so the object won't get destroyed out from underneath you during the doSomething call chain, but referencing self from doSomething doesn't cause a reference count to increment because the block doesn't know anything about what goes on inside of doSomething.

Related

Using an ivar inside a method which is called from a block

I want to use an ivar in a method that is being called from a block. Is it fine to call the ivar directly from it without causing a retain cycle?
I have seen other questions related to calling properties- saying that we 'can' use self. Just wanted to make sure about ivars, can we call ivar directly or do we need to use self->_myInstanceVariable explicitly?
__weak MyClassName *weakSelf = self;
[MyBlockCreator myBlock:^{
MyClassName *strongSelf = weakSelf;
[strongSelf doSomething];
}];
- (void) doSomething {
_myInstanceVariable = someObject
// is it fine to use the ivar directly above?
// or do we want use self explicitly?
// like self->_myInstanceVariable
}
In this case you don't need to make the reference weak/strong at all, the only situation in which you can cause a retain cycle is if self references a block and a strong version of self is captured within that block. Since self doesn't retain the block in question, there would be no retain cycle even using a strong reference.
[Foo doWithBlock:^{
bar.baz = #"Hello World"; // Totally fine without weak/strong since bar doesn't retain the block here.
}];
In situations where self holds a strong reference to a block and the block refers to self, you need to make the reference weak outside the block then make it strong again inside.
__weak id weakSelf = self;
[self doWithBlock:^{
id strongSelf = weakSelf;
strongSelf.baz = #"Ok";
}];

Do methods called from within a block need to use weakSelf?

If the code inside a block calls a method, will a retain cycle exist if that method references self? In other words, does all code downstream of a block need to use the weakSelf/strongSelf pattern?
For example:
__weak __typeof__(self) weakSelf = self;
Myblock block = ^{
[weakSelf doSomething];
};
. . .
- (void)doSomething
{
self.myProperty = 5; // Is this ok or does it need to use a weakSelf?
}
Objective-C is not scoped like you suggest, namely, you don't have access to weakSelf from within -doSomething. Furthermore, as you are calling -doSomething on weakSelf, "self" within that call is actually referring to the same object that weakSelf is.
In short, no, you shouldn't, you can't and you shouldn't.
Retain cycle will be triggered only if you retain self inside the block. Otherwise it will just throw a warning only.
This is fine you can use this. Because block retains every vars used inside, so retain cycle would be like
Self would retain block
If block retains self then
Self would again retain block
block would retain self, so cycle goes on
The thing you are doing in method is just message passing. Everytime block is called a message would be sent to self to doSomething. And you can retain self in doSomething method it wont trigger retain cycle because this method dont have cycle loop to self. Hope you understand :)
- (void)doSomething
{
self.myProperty = 5; // Is this ok or does it need to use a weakSelf?
}
you can do this to get rid of retain cycle problem.
[self class] __weak *weakSelf = self;
self.completionBlock = ^{
[self class] __strong *strongSelf = weakSelf
[weakSelf doSomething];
};

Using method with self inside blocks

I need to execute same bunch of code in two blocks (I'm using ARC):
__weak typeof(self) weakSelf = self;
[_dataProvider doA:^(NSError *error) {
[weakSelf handleError:error];
}];
And in a different place i call:
__weak typeof(self) weakSelf = self;
[_dataProvider doB:^(NSError *error) {
[weakSelf handleError:error];
}];
Then I have my handler:
- (void)handleError:(NSError *)error {
[self.refreshControl endRefreshing];
[self.tableView reloadData];
}
Is it save to use it this way? Please do notice that handleError: method uses self inside. If not, then what is the proper approach here? BTW: self is a viewController and can be dealloced (doB: and doA: blocks are based on networking, so can be slow).
It is not safe to do this, even if many people a doing it like this.
You should use the "weakSelf" pattern with blocks when it is justified.
In your example the "weakSelf" pattern is not justified, because self don't have any strong reference to your block. You can use like this :
[_dataProvider doA:^(NSError *error) {
// here you can use self, because you don't have any strong reference to your block
[weakSelf handleError:error];
}];
Use "weakSelf" pattern if you have a strong reference to your block ( with a property or an instance variable for example) and your are capturing self inside the block, example :
#property(strong) void(^)(void) completionBlock;
....
__weak typeof(self) weakSelf = self;
self.completionBlock = ^{
// Don't use "self" here, it will be captured by the block and a retain cycle will be created
// But if we use "weakSelf" here many times, it risques that it will be nil at the end of the block
// You should create an othere strong reference to the "weakSelf"
__strong typeof(self) strongSelf = weakSelf;
// here you use strongSelf ( and not "weakSelf" and especially not "self")
};

What happens to weakSelf and strongSelf in a block when the same block is executed multiple times?

PREFACE
According to the Clang docs, "For __weak objects, the current pointee is retained and then released at the end of the current full-expression." Which to me indicates that if I do this:
__weak typeof(self) weakSelf = self;
[self doSomethingInBackgroundWithBlock:^{
if (weakSelf) {
[weakSelf doSomethingInBlock];
}
}];
NOTE
If you reference #dasblinkenlight's answer below, you'll notice that there is a possibility of weakSelf becoming nil before doSomethingBlock.
Assuming doSomethingInBlock, does start with weakSelf existing, the rest of it should run no problem and there's no risk of weakSelf becoming nil before it has finished executing. However, if I were to run this:
__weak typeof(self) weakSelf = self;
[self doSomethingInBackgroundWithBlock:^{
if (weakSelf) {
// Guaranteed to be retained for scope of expression
[weakSelf doSomethingInBlock];
// weakSelf could possibly be nil before reaching this point
[weakSelf doSomethingElseInBlock];
}
}];
The work around that is suggested is to take weakSelf and convert it to a strong variable inside of the block, like this:
__weak typeof(self) weakSelf = self;
[self doSomethingInBackgroundWithBlock:^{
__strong typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf) {
[strongSelf doSomethingInBlock];
[strongSelf doSomethingElseInBlock];
}
}];
QUESTION
What happens to the weakSelf and strongSelf during multiple iterations of the same block? Is there a chance that in processBlock()(below), self could exist for some objects and not for others?
EXAMPLE
For example, if I were processing an array of objects in the background using something like this, where processBlock contains references to self:
- (void) processValuesInBackgroundWithArray:(NSArray *)array usingBlock:(void (^)(id))processBlock {
for (id ob in array) {
// Block is called for each Object
// Is there a chance that self will exist for some objects and not for others?
processBlock(ob);
}
}
Called like this:
__weak typeof(self) weakSelf = self;
[self processValuesInBackgroundWithArray:someArray usingBlock:^(id object) {
__strong typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf) {
[self doSomethingWithObject:object];
[self doSomethingElseWithObject:object];
}
}];
So the block references strongSelf from weakSelf, but the block is executed multiple times. Is there a chance that strongSelf might become nil in between iterations of objects in an array?
There is no guarantee that in your first example the weakSelf inside the if would be non-nil, because the block has two full expressions that reference it:
the if (weakSelf) check is the first full expression
the weakSelf in [weakSelf doSomethingInBlock]; invocation is the second one.
Therefore, your trick with strongSelf should be applied even when there is only one weakSelf invocation "protected" by the if statement.
Is there a chance that in processBlock()(below), self could exist for some objects and not for others?
Since there is no guaranteed __strong reference in a stack frame preceding the processValuesInBackgroundWithArray: call, self may become released between iterations of the loop, but only in a situation when the call of your last code snippet happens on a __weak or an unretained reference to the object containing the method from your last snippet.
Let's say that your last code snippet is inside a method called testWeak, in a class called MyClass:
-(void)testWeak {
__weak typeof(self) weakSelf = self;
[self processValuesInBackgroundWithArray:someArray usingBlock:^(id object) {
__strong typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf) {
[self doSomethingWithObject:object];
[self doSomethingElseWithObject:object];
}
}];
}
When the call is made like this
[myClassObj testWeak];
and myClassObj is __strong, the self object inside testWeak would be retained outside the call by the strong reference to myClassObj, so your code would be good, with or without the strongSelf trick.
When myClassObj is weak, however, and the last __strong reference gets released concurrently with the running loop, some objects inside the loop would end up seeing a nil weakSelf inside the block. The only difference that the strongSelf is going to make is preventing that doSomethingElseWithObject would be called on nil, while doSomethingWithObject would be called on a non-nil object.

Will the block contains references to self?

-(void) vAfterMainVariable
{
__weak BGGeneralCatalogView * weakSelf=self;
[_loAIOnebyOne vLoadStuffsWithURLBlock:^(){
NSString * URL= [weakSelf strGetURLToDownloadStuffs];
return URL;
} andPermaToastMessage: #"Loading Catalog" andCompletionBlock:^{}];
//[self.loAIOnebyOne vLoadStuffsWithURLBlock:<#^NSString *(void)blURL#> andPermaToastMessage:<#(NSString *)#> andCompletionBlock:<#^(void)completionBlock#>]
}
-(NSString *) strGetURLToDownloadStuffs
{
NSString * URL = [BGMakeURL URLforGetCatalogID:self.arArray];
return URL;
}
I uses weakSelf in the block. Yet, that weakSelf refer to a function that call self.arArray
So will the block has any strong pointer to self? When self, which is a viewController is gone from navigationController will it be deallocated soon?
To be exact, the block does NOT refer to self. The block refer to weakSelf that calls a method that refer to self. However the self in that method is the weakSelf.
Basically I followed that with this:
- (void)dealloc
{
[_loAIOnebyOne vCancelAllStuffs];
}
And it turns out dealloc is simply not called until after the block is finish. So the block must have contained self. But how?
Also how do I know which object still refer to my object?
The only object that refer to my object should be the UINavigationController object. The next one would be the block which is executing on the stack.
weakSelf needs to be a block variable. When the block is copied, it creates its own variable containing a copy of weakSelf, and that copy isn't weak.