简体   繁体   中英

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 if should not run, but it is running and crashing inside the if .

Assuming myself is a weak reference like myPlayer (you didn't say in your question) it can be deallocated at any time, including inside your if block. To resolve, create a strong reference inside your block:

__strong typeof(myself) strongSelf = myself;
__strong typeof(myPlayer) strongPlayer = myPlayer;

if (strongSelf.runAfterEveryFrame) {
    Float64 currentTime = CMTimeGetSeconds([strongPlayer currentTime]);
    strongSelf.runAfterEveryFrame(currentTime);
}

Also, you should be checking whether CMTimeGetSeconds returns NaN or infinity to be safe.

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;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM