创建 AVPlayerLayer 会阻止释放 AVPlayer

Creating AVPlayerLayer prevents releasing AVPlayer

如果我曾经设置过 AVPlayerLayer,那么就会有一些保留周期会阻止 deinit 被调用。

import AVFoundation

class MyPlayer: AVPlayer {

    fileprivate(set) lazy var playerLayer: AVPlayerLayer = {
        // Create a player layer
        [=10=].videoGravity = AVLayerVideoGravityResizeAspectFill
        [=10=].backgroundColor = UIColor.black.cgColor
        return [=10=]
    }(AVPlayerLayer(player: self))

    override init() {
        super.init()
        print("MyPlayer init")

        _ = playerLayer
    }

    deinit {
        print("MyPlayer deinit")
    }
}

用这个测试,只会打印"MyPlayer init"

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

    _ = MyPlayer()

    return true
}

在您的代码 MyPlayer 中保持对 playerLayer 属性 的引用。而playerLayer 属性 保持对MyPlayer 的引用。这就是保留周期。

作为解决方案,您无需在播放器 class 中存储 playerLayer 属性。或者你可以创建一些装饰器 class 来管理玩家和他的图层

AVPlayerLayer 保持对播放器的强引用,所以你不应该保持对播放器本身的 playerLayer 的强引用。

解决方案 1

如果你不打算移除sublayer,那么superlayer会为你保留reference,所以你可以使用weak:

private weak var _playerLayer: AVPlayerLayer?
var playerLayer: AVPlayerLayer! {
    if let p = _playerLayer {
        return p
    }
    let p: AVPlayerLayer = {
        // Create a player layer
        [=10=].videoGravity = AVLayerVideoGravityResizeAspectFill
        [=10=].backgroundColor = UIColor.black.cgColor
        return [=10=]
    }(AVPlayerLayer(player: self))
    _playerLayer = p
    return p
}

解决方案 2

如果您打算删除并重新添加子图层,那么您需要在 UIView、UIViewController 或播放器图层的其他管理器中创建强引用变量。