Can __weak self turn nil in the middle of the block? - ios

When using a __weak self reference in my block that runs on a background thread, do I only need to check for nil in the beginning, or can the __weak self become nil even during execution after the first nil test has passed? I want to access some ivars from self in the block and I need the latest values at the time the block is executing.

If no one is holding a reference to self then yes. You can mitigate this by taking a strong reference in the block
__weak __typeof(self) weakSelf = self;
^{
__strong __typeof(weakSelf) strongSelf = weakSelf;
if (!strongSelf) {
return;
}
};

You can avoid having your reference set to nil by strongly referencing it from inside the block.
Get a strong reference to your weak pointer inside the block.
__weak MyObject *weakSelf = self; // a weak reference
myBlock = ^{
MyObject *innerSelf = weakSelf; // a block-local strong reference
NSLog(#"MyObject: %#", innerSelf);
};
Avoid using the variables directly, because it will cause retain cycles.
If you use an instance variable directly within a block, the block will capture self so you'll have to reference the instance variables using their accessors.
__weak MyObject *weakSelf = self;
myBlock = ^{
MyObject *innerSelf = weakSelf; // a block-local strong reference
NSLog(#"MyObject: %#", innerSelf);
NSLog(#"MyObject ID: %d", innerSelf.objectID);
};
If you use the instance variables directly like this:
NSLog(#"MyObject ID: %d", _objectID);
The compiler interprets _objectID as self->_objectID, where self is captured by your block.

It is in the nature of a weak reference that it can become nil at any time, when the last strong reference is removed in another thread. This is fatal if you access member variables because you will crash, and it is fatal if you call a method on that weak variable, since self is unsafe unretained.
There is a trivial way to fix this which everyone uses: Store the weak variable into a string one before doing anything, without any checks. Then you check whether the strong variable is nil; that check is needed once.
Turn all warnings on in Xcode, so you will get a warning if you do anything dangerous.

Related

Preventing `self` from creating a strong reference in blocks

With the recent XCode update some code blocks are displaying as warnings where "Block implicitly retains 'self'"
It is my understanding that the when you create blocks it is best practice to create a weak self to keep from creating a strong reference that will not be garbage collected.
In the below example I set the myArray to self->myArray as recommended by XCode. Does this create the strong reference? Why can't I use 'weakSelf->myArray`? Attempting to do so results in this error:
Dereferencing a __weak pointer is not allowed due to possible null
value caused by race condition, assign it to strong variable first
I thought the whole point was to create weak refrences? Isn't weakSelf just a pointer to self?
Is the self-> even necessary in the below instance?
#interface SomeViewController (){
NSMutableArray * myArray;
}
#end
- (void) doSomethingInBackground {
// Do NSURLSessionTask on the background and onCompletion call mySuccessBlock.
}
- (SomeBlock) mySuccessBlock {
__block __typeof__(SomeViewController) __weak * weakSelf = self;
return ^(NSDictionary* result){
//this line is my related to my question
self->myArray = [weakSelf sortResultsAlphabetically: result];
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf.tableView reloadData]
});
};
}
Would recasting to be the correct way?
SomeViewController * strongSelf = weakSelf;
strongSelf->myArray = [weakSelf sortResultsAlphabetically: result];
The error message is right. You have to do the "weak-strong dance". You are only doing half of the dance. Pass self into the block as weak, but then immediately assign it, inside the block, to a strong reference (as in your edited "Would recasting to be the correct way?").

Accessing BOOL within blocks

I am trying to set a flag using a BOOL within a block.
I declare the BOOL like this:
#property(nonatomic) BOOL flag;
And within the block:
__strong typeof(self) strongSelf = weakSelf;
if(strongSelf->_flag)
My question is, if I do:
__weak typeof(self) weakSelf = self;
if(weakSelf->_flag)
I would get an error:
"dereferencing a __weak pointer is not allowed die to possible null
value caused by a race condition, assign it to strong variable first"
Can someone explain to me what this means?
In addition, it seems funny to me I have to reference the BOOL using __strong
(i.e. strongSelf->_flag), would that be the same as using self->_flag, because I would be using a strong self here?
More over, if I declare the BOOL as an ivar instead of a property:
BOOL flag;
It would give me a warning also when I use it within the block:
if(flag)
And so I would need to do the following as well:
__strong typeof(self) strongSelf = weakSelf;
if(strongSelf->flag)
This baffles me, because normally we reference an ivar without self, just flag, but the above case seems to me that it is accessing the ivar like self->_flag.
??
I could have use something else such as a NSNumber and good riddance to all this, but my curiosity urges me not to turn a blind eye on it.
I assume you scheduling the block operation in some operation queue or so when the block executes later in the future.
You should not assign self to weakSelf inside the block. You should do this outside the block
__weak typeof(self) weakSelf = self;
if(weakSelf->_flag)
__weak specifies a reference that does not keep the referenced object alive. A weak reference is set to nil when there are no strong references to the object.
Apple arc docs.
You actually want your weakSelf be not null to do some stuff with it. To do so you must declare assign it to a variable with strong ownership qualifier.
Sketch:
__weak id weakSelf = self;
schedule_block(^{
// at this point the object pointed by weakSelf may or may not be deallocated
id strongSelf = self; // after this point the object referenced by `strongSelf` will not be deallocated at least `strongSelf` to the end of current block
//You may safely work with `strongSelf` and be sure the object will live at least to the end of current block
});
To sum up: to be sure the object will not be deallocated while you work with it you should obtain a strong reference to it. On the other hand to prevent memory leaks you should use weak references. The algorithm looks like this:
obtain weak reference to object of interest
schedule block
at the start of block obtain a strong reference
if object still live - do whatever you need
if object was deallocated earlier - skip operations in block
iVar is just a member of C-structure the compiler creates for the class at compile time. All references to ivars will be compiled to self-><ivar_name>.
You may refer to Apple's docs for details or to LLVM specs on ARC or LLVM specs on blocks
You start with a weak pointer to an object. The object can disappear at any time, setting the weak pointer to nil. Once you assign it to a strong pointer, the strong pointer may have been set to nil if the weak pointer was nil at the time, but once it is set to non-nil, it stays non-nil because it holds a reference keeping the object alive.
if (strongSelf->_flag)
is dangerous, because strongSelf could be nil, leading to a crash.
if (strongSelf != nil && strongSelf->_flag)
is safe because the flag will not be tested unless strongSelf is not nil.
if (weakSelf->_flag)
is obviously also dangerous. But perhaps surprising is that
if (weakSelf != nil && weakSelf->_flag)
is also dangerous, because just because weakSelf was not nil when you checked it, doesn't mean it's not nil a nanosecond later when you try to access _flag.

ARC, self and blocks

I thought I understood the usage of self in a block that is copied is a no no.
But in an attempt to clean my code i enabled a bunch of warnings in Xcode, one called "Sending messages to weak pointers"
so now in all my blocks, every time I use my created weakself reference __weak typeof(self) weakself = self;
I get this warning: Weak receiver may be unpredictably set to nil
a trivial example:
__weak typeof(self) weakself = self;
[aClass doSomethingInABlock:^{
[weakself doSomething]; //warning.
}];
I have seen answers which define a version of self within the block like so:
__weak typeof(self) weakself = self;
[aClass doSomethingInABlock:^{
typeof(self) selfref = weakself;
[selfref doSomething]; //no warning.
}];
So I'm wondering what actually happens here:
Am I just tricking the compiler?
what does a strong reference to a weak reference do?
anything else I'm missing.
Thanks.
I thought I understood the usage of self in a block is a no no.
This is not strictly correct. Blocks retain the objects in them, so don't use self in a block if your block is retained by self.
For example, you can use self just fine in a UIView animation block. This is because your view controller (or whatever code is calling the animation) doesn't have a pointer to the UIView animation block.)
Am I just tricking the compiler?
No.
What does a strong reference to a weak reference do?
If the weak reference is not nil, the retain count of the receiver is increased. This will stop the object from being deallocated while you're using it.
Remember, ARC will deallocate objects when there are no longer strong references to them. By creating a strong reference inside the block, you're preventing possible deallocation until you're done with it.
anything else I'm missing.
I recommend reading the Practical Memory Management section of the Advanced Memory Management Programming Guide. Especially, read the subsection "Use Weak References to Avoid Retain Cycles".
Remember that in ARC, an object will not be deallocated as long as there's a strong reference to it.
When an object has a weak reference, the object might be deallocated (if there's no other strong reference to the same object), so a weak reference doesn't ensure the objects life.
By doing this:
typeof(self) selfref = weakself;
you're ensuring that you have a strong reference to that object before you use it (selfref is the strong reference pointing to the same object weakself is referring to). If you don't do this, the object could be deallocated while you use it.
Strong reference to a weak reference retains an object. It could be important in following case
__weak typeof(self) weakself = self;
[aClass doSomethingInABlock:^{
[weakself allocateSomething]; // (1)
// ..... code (2)
[weakself freeSomething]; // (3)
}];
If Weak receiver will be unpredictably set to nil in line (2) resources could be successfully allocated in (1) but not freed in (3). To avoid such problems strong reference could be used.
[aClass doSomethingInABlock:^{
typeof(self) selfref = weakself;
[selfref allocateSomething]; // (1)
// ..... code (2)
[selfref freeSomething]; // (3)
}];
Now if selfref is not nil in (1) it will also be valid in (2) and (3).

weak reference cause crash bug

I have seen the following code in WWDC 2011- Session 322 Objective-C Advancement in Depth
-(void) startBlinker{
__weak MyClass * weakSelf = self;
blinker = [BlinkerService register:^{
MyClass *strongSelf = weakSelf;
if(strongSelf){
[strongSelf->myView blink];
}
}];
}
I think I can implement it just check weakSelf like
if(weakSelf){
[weakSelf->myView blink];
}
why the code use a strongSelf?
If the object a weak reference points to is deallocated, the weak reference evaluates to nil. Calling methods on nil is okay but accessing fields using the arrow operator is not. So you have to make sure the pointer is not nil before accessing the field via the arrow pointer.
if(weakSelf){ // no weak sheeps this week
// weakSelf may get deallocated at this point.
// In that case the next line will crash the app.
[weakSelf->myView blink];
}
The strong self guarantees that self will not be deallocated between the if and the statements in the if block.
Usually a weak reference is done like this to avoid retain cycles in blocks. Blocks retain self which causes a retain cycle if you try to access a strong reference to self. So you create a weak self outside the block and access it within the block to avoid the retain cycle.
Ahmed Mohammed is correct, however another possible solution is to declare myView as a property, rather than as an iVar and do this:
-(void) startBlinker{
__weak MyClass * weakSelf = self;
blinker = [BlinkerService register:^{
MyClass *strongSelf = weakSelf;
[strongSelf.myView blink];
}];
}
This way, you don't really care if strongSelf is nil or not.

Referring to weak self inside a nested block

Suppose I already create a weak self using
__weak typeof(self) weakSelf = self;
[self doABlockOperation:^{
...
}];
Inside that block, if I nest another block:
[weakSelf doAnotherBlockOperation:^{
[weakSelf doSomething];
}
will it create a retain cycle? Do I need to create another weak reference to the weakSelf?
__weak typeof(self) weakerSelf = weakSelf;
[weakSelf doAnotherBlockOperation:^{
[weakerSelf doSomething];
}
Your code will work fine: the weak reference will not cause a retain cycle as you explicitly instruct ARC not to increase the retainCount of your weak object. For best practice, however, you should create a strong reference of your object using the weak one. This won't create a retain cycle either as the strong pointer within the block will only exist until the block completes (it's only scope is the block itself).
__weak typeof(self) weakSelf = self;
[self doABlockOperation:^{
__strong typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf) {
...
}
}];
It depends.
You only create a retain cycle if you actually store the block (because self points to the block, and block points to self). If you don't intend to store either of the blocks, using the strong reference to self is good enough --- block will be released first after it got executed, and then it will release it's pointer to self.
In your particular example, unless you're performing more operations which are not shown, you don't need to create any weakerWeakerEvenWeakerSelfs.

Resources