Search code examples
ioscocoablockavplayeravplayeritem

If not detecting nil inside block?


I have an AVPLayer with this observer

  __weak typeof(self.player) myPlayer = self.player;

  myself.timer = [myself.player addPeriodicTimeObserverForInterval:interval
                                                         queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)
                                                    usingBlock: ^(CMTime time) {

          if (myself.runAfterEveryFrame) {
            Float64 currentTime = CMTimeGetSeconds([myPlayer currentTime]);
            myself.runAfterEveryFrame(currentTime);  // crashes here
          }

  }];

The player is on self.player.

This app loads movies in sequence. When a movie ends, the app created a brand new AVPlayer, loads the asset and stores it on self.player. Something like:

AVPlayer *newPlayer = ... init new player
// load assets, create new periodic observers, etc.
// new player is ready
self.player = newPlayer;

This works fine but after 3 or 4 movies played, it crashes on the line

 myself.runAfterEveryFrame(currentTime);  // crashes here

with myself = nil.

This is the question. There is this if

          if (myself.runAfterEveryFrame) {
            Float64 currentTime = CMTimeGetSeconds([myPlayer currentTime]);
            myself.runAfterEveryFrame(currentTime);  // crashes here
          }

runAfterEveryFrame is a block of code that runs after every frame. if myself is nil, how is this two lines being executed? How can that be?

if myself is nil then myself.runAfterEveryFrame is nil, and the content inside the ifshould not run, but it is running and crashing inside the if.


Solution

  • a 2nd use of a weak variable inside an asynchronous block isn't safe so always cast the weak to a strong var inside the block. so self is captured weak but retained from the block

        __weak myType *weakType = self;
    
        //dispatch block
    
       //INSIDE block
        __strong myType *strongType = weakType;