2016-06-01 1 views
0

Dans mon application à un moment donné, l'utilisateur peut appeler la lecture vidéo avec tapant sur un élément d'interface utilisateur, et le segment de code suivant sera exécuté:« isPlayable »/blocs de contrôle « jouables » de AVAsset et des retards mises à jour l'interface utilisateur

self.loadingView.frame = _frameWhereItShouldBeLocated; 
[self.loadSpinner startAnimating]; // self.loadSpinner is an UIActivityIndicatorView 
self.loadingView.hidden = FALSE; 

AVPlayer *player = [AVPlayer playerWithURL:fileUrl]; // fileUrl is where is the video file is hosted, which is not a local path 

if ([player.currentItem.asset isPlayable]) 
{ 

    if (!self.playerController) { 
     self.playerController = [[AVPlayerViewController alloc] init]; 
     self.playerController.transitioningDelegate = self; 
     self.playerController.modalPresentationStyle = UIModalPresentationCustom; 
    } 

    self.playerController.player = player; 
    self.playerController.showsPlaybackControls = TRUE; 

    [self.navigationController presentViewController:self.playerController animated:YES completion:nil]; 
    [self.playerController.player play]; 

} 

Je m'attends à ce que la vue de chargement soit visible immédiatement après l'appui de l'utilisateur, puis après un certain temps, le contrôleur du lecteur est alors présenté et lit la vidéo. Cependant, il arrive qu'il y ait un délai important avant que la vue de chargement ne soit visible.

C'est ce que je pensais:

User tap -> loading view shown -> (some time for loading the video, etc) -> play video 

c'est plutôt ce que j'ai:

User tap -> (significant time delay) -> loading view shown -> play video 

Après un certain débogage j'ai trouvé que le retard est causé par l'appel [player.currentItem.asset isPlayable], à savoir la La vue de chargement ne devient visible qu'une fois l'appel renvoyé. J'ai essayé de mettre le segment ci-dessous l'affichage de la vue de chargement dans un appel dispatch_async mais il ne fait pas différent.

Y a-t-il un moyen de gérer cela pour qu'il se comporte comme prévu?

Merci beaucoup!

+0

La réponse est dans l'introduction de AVAsynchronousKeyValueLoading: https://developer.apple.com/library/mac/documentation/AVFoundation/Reference/AVAsynchronousKeyValueLoading_Protocol/index.html –

Répondre

0

Insted de if ([player.currentItem.asset isPlayable])

Cocher cette

if ((player.rate != 0) && (player.error == nil)) { 
    // player is playing 
} 

Ou Vous pouvez ajouter une notification pour rate propriété comme ci-dessous

[player addObserver:self 
       forKeyPath:@"rate" 
       options:NSKeyValueObservingOptionNew 
       context:NULL]; 

Vérifiez ensuite si la nouvelle valeur pour le taux observé est égal à zéro, ce qui signifie que la lecture s'est arrêtée pour une raison quelconque, comme atteindre la fin ou décrocher à cause d'un tampon vide.

- (void)observeValueForKeyPath:(NSString *)keyPath 
         ofObject:(id)object 
         change:(NSDictionary<NSString *,id> *)change 
         context:(void *)context { 
    if ([keyPath isEqualToString:@"rate"]) { 
     float rate = [change[NSKeyValueChangeNewKey] floatValue]; 
     if (rate == 0.0) { 
      // Playback stopped 
     } else if (rate == 1.0) { 
      // Normal playback 
     } else if (rate == -1.0) { 
      // Reverse playback 
     } 
    } 
} 

Pour taux == 0,0 cas, de savoir exactement ce qui a causé la lecture d'arrêter, vous pouvez effectuer les vérifications suivantes:

if (self.player.error != nil) { 
    // Playback failed 
} 
if (CMTimeGetSeconds(self.player.currentTime) >= 
    CMTimeGetSeconds(self.player.currentItem.duration)) { 
    // Playback reached end 
} else if (!self.player.currentItem.playbackLikelyToKeepUp) { 
    // Not ready to play, wait until enough data is loaded 
} 

Sur la base de la condition ci-dessus cacher votre point de vue des indicateurs. Et chargez votre indicateur sur le fil principal.

dispatch_async(dispatch_get_main_queue(), ^{ 
//load spinner 
});