0

If I ever set an AVPlayerLayer, then there will be some retain cycle that will prevent deinit from ever being called.

import AVFoundation

class MyPlayer: AVPlayer {

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

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

        _ = playerLayer
    }

    deinit {
        print("MyPlayer deinit")
    }
}

Testing with this, only "MyPlayer init" will be printed:

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

    _ = MyPlayer()

    return true
}
Cœur
  • 37,241
  • 25
  • 195
  • 267
  • Please stop making pointless edits in years old questions! It makes them pop up as new questions. Especially if you’re changing the name of a linked duplicate question that is automatically generated! https://stackoverflow.com/questions/14600914/change-date-format-ios-objective-c?noredirect=1 – Fogmeister Feb 03 '18 at 16:23
  • @Fogmeister correcting titles of linked questions seems quite important. – Cœur Feb 03 '18 at 16:24
  • the title of the linked question was edited ... to put an ‘a’ in link still worked. Except now I went to reopen the question because I thought it was closed in haste. And then was about to answer when I realised it was nearly 5 years old. Sure, resurrect a question if the answer has massively changed. But the link still worked. Nothing significantly changed in it. – Fogmeister Feb 03 '18 at 16:29

2 Answers2

2

AVPlayerLayer is keeping a strong reference to the player, so you shouldn't keep a strong reference of the playerLayer from the player itself.

Solution 1

If you don't plan to remove the sublayer, then the superlayer will keep the reference for you, so you can use weak:

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

Solution 2

If you plan to remove and re-add the sublayer, then you need the strong reference variable to be made in your UIView, UIViewController or some other manager for the playerLayer.

Cœur
  • 37,241
  • 25
  • 195
  • 267
1

In you code MyPlayer keep reference to the playerLayer property. And playerLayer property keep reference to the MyPlayer. That's make retain cycle.

As solution you don't need to store playerLayer property in you player class. Or you can create some decorator class what will manage both - player and his layer

Taras Chernyshenko
  • 2,729
  • 14
  • 27