Retain loop in a block - ios

I'm trying to get variables and properties in self in a block for actions to complete, but, if I reference self or a global variable in self when self is the object running the block, it warns me of a retain loop. Here's what I'm doing:
I'm adding actions to an NSMutableArray that are of type (void(^)() (in other words, a block returning void with no parameters).
I call it using this syntax later on, where i is an int determined by code (that is in the bounds of the array:
void (^someBlock)() = arrayOfActions[i];
someBlock();
The code works and runs fine, but, because I use properties of self within the block, Xcode warns me of a retain loop. Should I ignore it because it's simply a warning and everything works fine in code (it only executes the block once), or should I do something different?

You should definitely not ignore the warning, but use __weak instead to define a weak reference and eliminate retain cycles as described in the documentation:
__weak SelfType *weakSelf = self;
void (^aBlock)() = ^(){
SelfType *strongSelf = weakSelf;
//User strongSelf
};
Alternatively you can use libextobjc (https://github.com/jspahrsummers/libextobjc) with its convenient #strongify and #weakify annotations.

Related

Caputure property value lead to retain cycle through _property style

I have a class, there's a block proper:
#property(nonatomic, strong) void (^hehe)();
In the init method, I do the following work:
__weak test *weakSelf = self;
self.hehe = ^{
test *self = weakSelf;
NSLog(#"%zd", self.a);
NSLog(#"%zd", self->_a);
NSLog(#"%zd", _a);
};
What is the difference between the last two line in the block.
I thought self->_a is equals to _a.
But the Xcode shows warning on the last line:
Caputuring self strongly in this block is likely to lead a retain cycle
Edit:
I know the local self and the global self is not the same. How the os distinguish the difference. I used clang to rewrite the code, and get the following:
static void __ViewController__init_block_func_0(struct __ViewController__init_block_impl_0 *__cself) {
__Block_byref_weakSelf_0 *weakSelf = __cself->weakSelf; // bound by ref
ViewController *self = (weakSelf->__forwarding->weakSelf);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_gp_6ztdfl3n5919c3y4pb03gd340000gn_T_ViewController_ad5b98_mi_0, ((NSInteger (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("a")));
NSLog((NSString *)&__NSConstantStringImpl__var_folders_gp_6ztdfl3n5919c3y4pb03gd340000gn_T_ViewController_ad5b98_mi_1, (*(NSInteger *)((char *)self + OBJC_IVAR_$_ViewController$_a)));
NSLog((NSString *)&__NSConstantStringImpl__var_folders_gp_6ztdfl3n5919c3y4pb03gd340000gn_T_ViewController_ad5b98_mi_2, (*(NSInteger *)((char *)self + OBJC_IVAR_$_ViewController$_a)));
}
The last two line is used the same self...
Because it means a different self. A quick rename will make everything clear :
__weak test *weakSelf = self;
self.hehe = ^{
test *strongSelf = weakSelf;
NSLog(#"%zd", strongSelf.a);
NSLog(#"%zd", strongSelf->_a);
NSLog(#"%zd", _a);
};
Now it is clear, that the last line captures self from outside the block. The way you had it named, made it harder to differentiate between the self that was a local variable declared inside a block, and the self that was captured from outside its scope.
Referring to _a is a direct reference to an instance variable from the enclosing scope. That implicitly captures self. It doesn't invoke the property's getter/setter. It points directly to the instance variable.
Don't do that from inside a block that persists. (An "escaping" block, as Apple has started calling it.) Use the weakSelf/strongSelf syntax #Losiowaty showed in his answer.

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

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.

Strong reference to self inside a method running from a block

So, I know that if you save a block inside of self, then access self inside of that block you need to create and use something like __weak id weakSelf = self;.
My question is, does this also extend to functions being called from that block? As in, would the following lead to a retain cycle:
self.block = ^{ [weakSelf myFunction]; }
- (void) myFunction { self.counter++; }
Thanks for your time!
This does not create a retain cycle, because the self in the method is actually a parameter passed by the Objective C runtime (using objc_msgSend and similar). So let's consider the two scenarios possible in your code example. weakSelf has been zeroed out due to release of the holding object - a message passed to nil is ignored. weakSelf is not zeroed, in which case, it is passed by the Objective C runtime to the message as its self parameter.

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.

When and why would I want to declare a local variable as __weak using ARC?

Mike Ash has written this introduction to ARC where he introduces something like:
__weak Foo *_weakFoo = [object foo];
Why would I want to do that for a local, temporary variable? __weak is a zeroing reference which will set the _weakFoo pointer automatically to nil as soon as the referenced object gets deallocated. Also, __weak is only available in iOS >= 5.
When would I run into trouble when I simply do this?:
Foo *_weakFoo = [object foo];
This is always expected to return an object or nil. My guess is this:
Foo *_weakFoo = [object foo];
[self doSomethingStupid]; // does something bad so foo gets deallocated
[_weakFoo doIt]; // CRASH! msg sent to deallocated instance 0x123456
One thing that still bugs me with ARC is: When does it know that I don't need an object anymore? I'd argue that when I set a pointer to nil or to something else it figures out that the previously referenced object isn't needed by this owner anymore and therefore maybe can go away. But the point is: I set it to nil. So it's nil anyways!
So when would __weak for a local variable make sense, and what kind of crazy thing must I do somewhere else so that I really need that?
I use __weak local variables if I have to manipulate self inside of a block to avoid a retain cycle. Consider this example where I'm using GCD and blocks to perform a network request for a string, and then setting it on a label declared by the class, in this case, TurtlesViewController.
__weak TurtlesViewController *weakSelf = self;
dispatch_queue_t networkQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(networkQueue, ^{
// Kick off a network task for some data that is going to populate a label declared on our class
NSString *returnString = [networkDataSource retrieveTurtleTime];
// Dispatch back to the main thread to populate the UILabel
dispatch_async(dispatch_get_main_queue(), ^{
// Using self.label here creates a retain cycle. Self owns the block and the block has captured self
self.label.text = returnString;
// Instead, we use weakSelf for our reference to the label as it will be torn down by ARC at the end of the loop.
weakSelf.label.text = returnString;
});
});

Resources