簡體   English   中英

當我用閉包初始化屬性時,為什么我可以使用self?

[英]Why can i use self when I initialize property with a closure?

官方文檔(Swift 4.1)說:

如果使用閉包來初始化屬性,請記住在執行閉包時尚未初始化實例的其余部分。 這意味着您無法從閉包中訪問任何其他屬性值,即使這些屬性具有默認值也是如此。 您也不能使用隱式self屬性,也不能調用任何實例的方法。

所以我想我需要使用lazy var,今天我創建了一個按鈕

let loginRegisterButton: UIButton = {
    let button = UIButton(type: .system)
    button.backgroundColor = UIColor.rgb(red: 80, green: 101, blue: 161)
    button.setTitle("Register", for: .normal)
    button.translatesAutoresizingMaskIntoConstraints = false
    button.setTitleColor(UIColor.white, for: .normal)
    button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
    button.addTarget(self , action: #selector(handleRegister), for: .touchUpInside)
    return button
}()

所以我只是在addTarget方法中使用self而XCode似乎沒有打擾更多的程序沒有任何錯誤。 一切都很好。所以當我用閉包初始化屬性時,為什么我可以使用self? 是否有一些變化或者我錯過了什么?

很奇怪 - 也許是buggily-你的閉包中的self評估為一個函數對象。 (Hamish在評論中解釋說,該函數是NSObjectProtocol.self一種curry形式。)但是,當你稍后問按鈕的目標時,它報告+[NSNull null]

let loginRegisterButton: UIButton = {
    let button = UIButton(type: .system)
    button.backgroundColor = .red
    button.setTitle("Register", for: .normal)
    button.translatesAutoresizingMaskIntoConstraints = false
    button.setTitleColor(UIColor.white, for: .normal)
    button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)

    print(self)
    // Output: (Function)

    button.addTarget(self, action: #selector(handleRegister), for: .touchUpInside)

    let target = button.allTargets.first!.base
    print(target, type(of: target))
    // Output: <null> NSNull

    return button
}()

(使用Xcode 9.3.1測試。)

這個函數會得到變成NSNull函數對象只是調用之前分配:如下addTarget ,作為傳遞target參數。 loginRegisterButton閉包擁有對新分配函數的強引用。

該按鈕將目標存儲為歸零弱引用。

addTarget返回后,閉包釋放其對該函數的強引用。 這是該函數的唯一強引用,因此Swift釋放該函數。 這將按鈕對函數的弱引用設置為nil。

然后,當我們詢問allTargets的按鈕時,它構造一個NSSet 由於NSSet不能直接保存nil,因此按鈕會在集合中放置+[NSNull null]

代碼中的目標 可能 nil ,這可能起作用的原因是:

...如果指定nil,UIKit會在響應鏈中搜索響應指定操作消息的對象,並將消息傳遞給該對象

(來自方法文檔

您可以通過在控制器初始化期間或之后設置斷點並檢查_targetActions數組(在調試器的變量視圖中)來驗證目標實際上是否為nil (您可以看到target的地址為0x0 )。

在您的示例中, loginRegisterButton在控制器初始化期間設置,這意味着還沒有self (換句話說,您無法保證此時所有實例變量都已初始化)。 lazy解決這個問題的方式是在第一次訪問時推遲實際的分配。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM