You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift 4中AVPlayer循环实现问题:restartVideoFromBeginning内player为nil

Why Your AVPlayer is Nil in the Restart Method

Hey there! Let's break down why your player variable is turning up nil when the video finishes playing, and how to fix it:

1. Your Player Isn't Being Retained Properly

The most common culprit here is that your player instance is getting deallocated from memory before the "play to end" notification fires. This happens if:

  • You declared player as a local variable inside a method (it gets destroyed once the method finishes running)
  • You used a weak reference for the player property (it gets set to nil when there's no other strong reference holding it)

Fix: Declare player as a strong property in your view controller:

class ViewController: UIViewController {
    // Strong reference keeps the player alive
    private var player: AVPlayer?
    
    // Rest of your code...
}

2. You're Listening to All AVPlayerItem Notifications

Right now, your notification observer is set up with object: nil, which means it will trigger for any AVPlayerItem that finishes playing in your app. If another player's item sends the notification, or if your original player has already been released, player will be nil.

Fix: Register the observer specifically for your player's current item, and clean up the observer when your view controller is deallocated:

// When setting up your player:
if let playerItem = player?.currentItem {
    NotificationCenter.default.addObserver(self,
                                          selector: #selector(restartVideoFromBeginning),
                                          name: .AVPlayerItemDidPlayToEndTime,
                                          object: playerItem)
}

// Add this to your view controller to avoid memory leaks:
deinit {
    NotificationCenter.default.removeObserver(self)
}

3. Timing Issues with Player Initialization

If you registered the notification before you created and assigned the player variable, or if you accidentally set player = nil somewhere else in your code, the method will find nil when it runs.

Fix: Always register the notification after you've initialized the player, and avoid setting player to nil unless you intentionally want to destroy it. Here's a complete, safe setup example:

import UIKit
import AVKit

class ViewController: UIViewController {
    private var player: AVPlayer?
    private var playerLayer: AVPlayerLayer?

    override func viewDidLoad() {
        super.viewDidLoad()
        setupVideoPlayer()
    }
    
    private func setupVideoPlayer() {
        // Replace with your video URL (local or remote)
        guard let videoURL = Bundle.main.url(forResource: "your_video", withExtension: "mp4") else {
            print("Couldn't find video file!")
            return
        }
        
        let playerItem = AVPlayerItem(url: videoURL)
        player = AVPlayer(playerItem: playerItem)
        
        // Add player layer to your view
        playerLayer = AVPlayerLayer(player: player)
        playerLayer?.frame = view.bounds
        playerLayer?.videoGravity = .resizeAspectFill
        view.layer.addSublayer(playerLayer!)
        
        // Register notification for THIS player item
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(restartVideo),
                                               name: .AVPlayerItemDidPlayToEndTime,
                                               object: playerItem)
        
        player?.play()
    }
    
    @objc func restartVideo() {
        guard let player = self.player else {
            print("Player is nil - check retention and initialization!")
            return
        }
        // Use CMTimeMakeWithSeconds for better readability (Swift 4+)
        let startCMTime = CMTimeMakeWithSeconds(0, preferredTimescale: 1)
        player.seek(to: startCMTime) { [weak self] _ in
            self?.player?.play()
        }
    }
    
    deinit {
        NotificationCenter.default.removeObserver(self)
    }
}

A quick note: Using [weak self] in the seek completion block is a good practice to avoid retain cycles, especially if your view controller might be dismissed before the seek finishes.

内容的提问来源于stack exchange,提问作者123

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:04:35