関数でも解放されない。

タイトル適当ですが、手元で動かしたものをサクッと出力。

 androidxmlとかvueやanglureのように、swiftでも宣言的にUIを定義してみようと、少しいじってみた。

こんな感じのボタンクラスがあるとして

 import UIKit

final class Button: UIButton {
    
    convenience init(title: String, onClick: () -> Swift.Void) {
        self.init(frame: .zero)
        addTarget(self, action: #selector(actionClick), for: .touchUpInside)
        clickHandler = onClick
        setTitle(title, for: .normal)
    }
    
    private var clickHandler:  (() -> Swift.Void)?
    
    @objc private func actionClick() {
        clickHandler?()
    }
    
    deinit {
        print("deinit")
    }
}

こんな感じで関数を渡してあげたらスッキリしていい感じと思ったけど、

final class ViewController: UIViewController {
    
    private lazy var button = Button(title: "解放されない", onClick: onClickButton)

    private  func onClickButton() {
        dismiss(animated: true, completion: nil)
    }
}

クロージャーがselfをキャプチャするのを考えると、上で関数渡すだけだとbuttonがdeinitしなかった。

final class ViewController: UIViewController {

    private lazy var button = Button(title: "解放されない") { 
       dismiss(animated: true, completion: nil)
    }
    
    private lazy var button1 = Button(title: "解放される") { [weak self] in
       self?dismiss(animated: true, completion: nil)
    }
}

結局クロージャーを渡している。

final class ViewController: UIViewController {
    
    private lazy var button = Button(title: "解放される", onClick: onClickButton) 

    private  lazy var onClickButton = { [weak self] in
        self?.dismiss(animated: true, completion: nil)
    }
}