nil __weak self - Why it's happend?

3.8k views Asked by At

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

enter image description here

But later in block - each variant nil

enter image description here

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];
        });
    }];
}
3

There are 3 answers

0
Rob On BEST ANSWER

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.

0
dogsgod On

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

0
gnasher729 On

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.