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 ...
Related
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.
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.
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).
In apples example
MyViewController *myController = [[MyViewController alloc] init…];
MyViewController * __weak weakMyController = myController;
myController.completionHandler = ^(NSInteger result) {
MyViewController *strongMyController = weakMyController;
if (strongMyController) {
[strongMyController dismissViewControllerAnimated:YES completion:nil];
}
else {
// Probably nothing...
}
};
What is happening here? I'm confused about:
MyViewController *strongMyController = weakMyController;
Does that mean weakMyController has a strong reference to it, so it would be like weakMyController's retain count + 1? What happens when you create a strong reference to a weak iVar?
Does that mean weakMyController has a strong reference to it, so it
would be like weakMyController's retain count + 1?
The retain count for myController is the same for all the variables that have its reference. It's a value of the object, not of the variables pointing to it. And it tells the runtime ho many strong references there exist pointing to the object.
So, the line
MyViewController *strongMyController = weakMyController;
will increment that count by 1, and ensure that as long as we have that variable in scope, that view controller won't be released.
In most cases it's enough to call methods on the weak reference inside the block (weakMyController in your example). I think that in this case they use a strong reference because there's an animation involved (so the view controller needs to exist for the duration of the animation, which would not be guaranteed if we used a weak reference).
To respond to the other part of your question, all the strong and weak references to an object hold the same value (the memory address of the object). The difference between strong and weak is what happens when they get their values. In the case of a weak reference, the retain count stays the same, while with a strong reference it gets incremented.
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.