2016-01-23 4 views
0

Есть ли хороший способ использовать наблюдение за ключом и блокировать вместе? У меня есть функция, которая принимает блок завершения, и я хочу, чтобы этот блок завершения выполнялся, когда наблюдаемый статус изменяется на AVPlayerItemStatusReadyToPlay. Могу ли я передать блок, используя контекст наблюдателя, или это нарушит основы программирования KVO?Использование KVO в блочной функции

- (void)setVideoWithURL:(NSURL *)url completed:(PlayerCompletedWithFinishedBlock)completedBlock { 
    ... 
    AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:asset]; 
    [playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:NULL]; 
} 

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
{ 
    if ([change isEqual: @"AVPlayerItemStatusReadyToPlay"]) { 
     // Is there a way to run the completion block from here? 
    } 
} 
+0

В GitHub есть контроллер KVO, на который вы можете посмотреть – Wain

ответ

1

Просто хранить блок в copy собственности и назвать его в методе -observeValueForKeyPath:.... Не забудьте очистить эту сильную ссылку, когда вы удаляете наблюдение.

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

Контекст должен быть средством для объекта: a) определять, что вызов -observeValueForKeyPath:... соответствует собственному наблюдению этого кода; и b) удалить наблюдение таким образом, чтобы отличить его от любого другого наблюдения, которое могло быть установлено другим кодом (с использованием -removeObserver:forKeyPath:context:). Поэтому контекст должен идентифицировать используемый им код, а не какой-либо конкретный наблюдатель или наблюдать. Обычный подход заключается в определении статической переменной и использовании ее адреса.

И наконец, даже фрагментарная реализация -observeValueForKeyPath:..., которую вы показали, довольно сломана. change никогда не будет равен @"AVPlayerItemStatusReadyToPlay", потому что первый словарь, а последний - строка. В дополнение к проверке контекста (и вызывая супер, если уведомление не для вашего наблюдения), вы должны проверить keyPath или, возможно, status свойство object.

1

Кен прав - ваш обработчик уведомлений KVO (-observeValueForKeyPath) не будет работать как есть. Возьмите его предложения там

Но и вы должны хранить ваши PlayerItem как свойство в текущем объекте, и убедитесь, что у вас есть соответствующие -removeObserver где-то (возможно в dealloc, вы можете проверить, если playerItem существует, и если да, то -removeObserver

и, как сказал Кен, вы можете создать новое свойство для вашего completionBlock хранить его,., так что может быть позже названный в обработчике уведомлений КВО

Он также указывает на использование копии и устраняя вашу сильную ссылку на ваш блок. Это связано с тем, что nd вверх с циклом удержания, если скажем, например, что блок пришел из того же класса, который его сохраняет. Если код внутри блока имеет ссылку на свойство, он сохранит объект, которому принадлежит это свойство. И тот же объект также сохраняет блок, тогда вы закончите цикл сохранения. Поэтому будьте осторожны со своими рекомендациями :)