Если не обнаружить ноль внутри блока?

У меня есть AVPLayer с этим обозревателем

  __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
          }

  }];

Игрок находится на self.player.

Это приложение загружает фильмы последовательно. Когда фильм заканчивается, приложение создает новый AVPlayer, загружает ресурс и сохраняет его в self.player. Что-то типа:

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

Это работает нормально, но после воспроизведения 3 или 4 фильмов происходит сбой на линии.

 myself.runAfterEveryFrame(currentTime);  // crashes here

с myself = nil.

Вот в чем вопрос. Есть это, если

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

runAfterEveryFrame — это блок кода, который запускается после каждого кадра. если myself равно nil, как выполняются эти две строки? Как это может быть?

если я равен нулю, то myself.runAfterEveryFrame равен nil, а содержимое внутри if не должно запускаться, но оно работает и падает внутри if.


person Duck    schedule 26.12.2014    source источник
comment
Как я себя определяю? Это __weak MyClass *myself = self;?   -  person JuJoDi    schedule 26.12.2014
comment
Подсказка: включите все разумные предупреждения в Xcode, и компилятор ответит на ваш вопрос.   -  person gnasher729    schedule 26.12.2014
comment
Документация для addPeriodicTimeObserverForInterval:queue:usingBlock: (developer.apple.com/library/mac/documentation/AVFoundation/) говорит, что очередь должна быть последовательной очередью. Вы используете глобальную очередь, которая является параллельной очередью. В документации говорится, что использование параллельной очереди приводит к неопределенному поведению.   -  person newacct    schedule 27.12.2014
comment
@newacct - в этом ты прав! Хорошо поймал!!!! СПАСИБО +1   -  person Duck    schedule 27.12.2014


Ответы (2)


2-е использование слабой переменной внутри асинхронного блока небезопасно, поэтому всегда переводите слабую переменную в сильную переменную внутри блока. поэтому я захвачен слабым, но удерживается от блока

    __weak myType *weakType = self;

    //dispatch block

   //INSIDE block
    __strong myType *strongType = weakType;
person Daij-Djan    schedule 26.12.2014
comment
ВЕЛИКОЛЕПНО!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Я не знал, что могу сильная слабая ссылка! БЛАГОДАРНОСТЬ - person Duck; 26.12.2014

Предполагая, что myself является слабой ссылкой, такой как myPlayer (вы не сказали в своем вопросе), ее можно освободить в любое время, в том числе внутри вашего блока if. Чтобы решить эту проблему, создайте сильную ссылку внутри вашего блока:

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

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

Кроме того, вы должны проверить, возвращает ли CMTimeGetSeconds NaN или бесконечность, чтобы быть в безопасности.

person Aaron Brager    schedule 26.12.2014
comment
это мой обман ;) лучше написано, но обман - person Daij-Djan; 26.12.2014