Knowing when AVPlayer object is ready to play

You are playing a remote file. It may take some time for the AVPlayer to buffer enough data and be ready to play the file (see AV Foundation Programming Guide)

But you don't seem to wait for the player to be ready before tapping the play button. What I would to is disable this button and enable it only when the player is ready.

Using KVO, it's possible to be notified for changes of the player status:

playButton.enabled = NO;
player = [AVPlayer playerWithURL:fileURL];
[player addObserver:self forKeyPath:@"status" options:0 context:nil];   

This method will be called when the status changes:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
                        change:(NSDictionary *)change context:(void *)context {
    if (object == player && [keyPath isEqualToString:@"status"]) {
        if (player.status == AVPlayerStatusReadyToPlay) {
            playButton.enabled = YES;
        } else if (player.status == AVPlayerStatusFailed) {
            // something went wrong. player.error should contain some information
        }
    }
}

Swift Solution

var observer: NSKeyValueObservation?

func prepareToPlay() {
    let url = <#Asset URL#>
    // Create asset to be played
    let asset = AVAsset(url: url)
    
    let assetKeys = [
        "playable",
        "hasProtectedContent"
    ]
    // Create a new AVPlayerItem with the asset and an
    // array of asset keys to be automatically loaded
    let playerItem = AVPlayerItem(asset: asset,
                              automaticallyLoadedAssetKeys: assetKeys)
    
    // Register as an observer of the player item's status property
    self.observer = playerItem.observe(\.status, options:  [.new, .old], changeHandler: { (playerItem, change) in
        if playerItem.status == .readyToPlay {
            //Do your work here
        }
    })

    // Associate the player item with the player
    player = AVPlayer(playerItem: playerItem)
}

Also you can invalidate the observer this way

self.observer.invalidate()

Important: You must keep the observer variable retained otherwise it will deallocate and the changeHandler will no longer get called. So don't define the observer as a function variable but define it as a instance variable like the given example.

This key value observer syntax is new to Swift 4.

For more information, see here https://github.com/ole/whats-new-in-swift-4/blob/master/Whats-new-in-Swift-4.playground/Pages/Key%20paths.xcplaygroundpage/Contents.swift