Strong reference to a weak references inside blocks - ios

Why is it necessary to have a strong reference to a weak reference inside a block?
I understand that having a weak reference inside the block will avoid retain cycles. But why must there be a strong reference to the weak one again?
Background:
As described by Mason this is best practice.
I know the proper way to refer to self inside a block is to create a weak reference outside the block, and then a strong reference to that weak reference inside the block[...]
Example:
__weak typeof(self) weakSelf = self;
void (^someBlock)(id) = ^(id data){
typeof(self) strongSelf = weakSelf;
// code using strongSelf
});

Imagine that the last remaining strong reference to self is held on a different thread to the one that your block runs on.
Now this happens:
__weak typeof(self) weakSelf = self;
void (^someBlock)(id) = ^(id data){
if (weakSelf != nil) {
// last remaining strong reference released by another thread.
// weakSelf is now set to nil.
[myArray addObject:weakSelf];
}
});
This will crash with an NSInvalidArgument exception for adding nil to an array.
Making the reference strong before use removes the potential race condition and ensures that the pointer will always point to the same object.
If you are 100% certain that an object will only ever be referenced by one thread, it isn't strictly necessary to do this. But it's bad practice to make that assumption.

It's not inherently necessary, but the general idea is to make sure that the object pointed to by weakSelf is not dealloc'ed while the block is executing. Creating the strong reference has the side effect of retaining the object. That retain will be released by ARC when the strong reference goes out of scope. It's largely defensive. Generally speaking, you should aim to provide other (better) guarantees that your system remains stable during block execution.

Related

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.

nil __weak self - Why it's happend?

I want to use weak self in blocks, but in block this weakSelf become nil
Just created, before block (try to use different variants) - looks like all ok
But later in block - each variant nil
Whats done wrong? Can anyone explain?
EDIT
SPHVideoPlayer *videoPlayer = [[SPHVideoPlayer alloc] initVideoPlayerWithURL:urlToFile];
[videoPlayer prepareToPlay];
Initialization
#pragma mark - LifeCycle
- (instancetype)initVideoPlayerWithURL:(NSURL *)urlAsset
{
if (self = [super init]) {
[self initialSetupWithURL:urlAsset];
}
return self;
}
- (void)initialSetupWithURL:(NSURL *)url
{
NSDictionary *assetOptions = #{ AVURLAssetPreferPreciseDurationAndTimingKey : #YES };
self.urlAsset = [AVURLAsset URLAssetWithURL:url options:assetOptions];
}
And also method that use block
- (void)prepareToPlay
{
__weak typeof(self) weakSelf = self;
__weak SPHVideoPlayer *weakSealf2 = self;
NSArray *keys = #[#"tracks"];
[self.urlAsset loadValuesAsynchronouslyForKeys:keys completionHandler:^{
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf startLoading];
});
}];
}
As rckoenes suggested, this SPHVideoPlayer is falling out of scope and is getting released. Assuming you don't want it to be released, you just have to choose a scope that keeps it around (e.g. making it a property of the view controller that is showing the video).
You describe your use of weakSelf to prevent a "retain cycle" (now often called a "strong reference cycle"). Yes, the weakSelf pattern is used to prevent strong reference cycles. Technically, it's not entirely clear that you necessarily had a strong reference cycle at all. It depends upon the details of the loadValuesAsynchronousForKey... implementation (e.g. is this block loaded into some class property, thus creating strong reference cycle from the class, to a block class property references of self, which in turn maintains a strong reference back to self).
But that's all a bit academic: The weakSelf pattern is prudent nonetheless, because it accurately reflects the appropriate object graph (the block has no business "owning" and/or maintaining a strong reference to the video player). Coincidentally, though, when you use weakSelf, it also eliminates the potential risk of strong reference cycle.
The real issue is that you presumably want to keep the video player in scope not just while the assets are loaded, but while the video plays, too, so you'd want to change the scope of the video player regardless (presumably to match the view controller that is presenting the video player.
That's the idea of weak variables: Weak variables do not hold a reference count, so if a weak variable is the only thing left that holds on to an object, the object will be deallocated and the weak variable will be nil. That's 100% the way how weak variables are supposed to work and supposed to be used.
If you had used a strong reference, then your block would be the only bit of code still holding on to self, and all the work that you do with self would be pointless because nobody else will ever take notice of it. Since you are using a weak variable, you can avoid this by checking whether the variable is nil.
In a multithreaded environment, the last strong reference could go away at any time and your weak reference might become nil at any time. You avoid this by copying the weak variable into a strong one as the very first thing in your block, so you know the weak variable might have disappeared before you entered the block, but it won't disappear while your block is executing.
The reason to have a weak reference for blocks is to not retain the class with the block.
Weak references get nil when the instance does not exist anymore, so you need to take care of handling the weak reference accordingly (which you do in your code).
If that is not what you want to achieve, you need to make sure your instance is not deallocated, but that is not related to your block ...

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).

When is reference to self in block a retain cycle?

I've got a problem that is probably fairly common. In an ARC environment, a block that needs to reference self will outlive self. I'm aware of the convention to use __weak typeof(self) weakSelf = self; in blocks to avoid retain cycles. The problem is that we do need to retain self. So my question is: When does a reference to self in a block create a retain cycle? This post post suggests that in animation blocks, reference to self is ok.
I had also considered a solution like the following, but am not sure it changes anything:
__block typeof(self) blockSelf = self;
[someObj someMethodTakingCallback:^{
//do some stuff
blockSelf = nil;
}];
You get a reference cycle if self retains the block in addition to the block retaining `self.
In this case you would have a retain cycle if self holds a reference to someObj since someObj is probably holding a reference to self. It's actually a retain cycle if there's any retaining reference path from self to someObj.

Resources