2014-11-24 76 views
8

我試圖創建的UIBarButtonItem的一個簡單的斯威夫特子類:什麼原因導致UIBarButtonItem的初始值設定項繼承問題?

class LabelBarButtonItem: UIBarButtonItem { 
    let label: UILabel 

    init(text: String) { 
    self.label = UILabel(frame: CGRectZero) 
    self.label.tintColor = UIColor.grayColor() 
    super.init(customView: self.label) 
    self.label.text = text 
    } 

    required init(coder aDecoder: NSCoder) { 
     fatalError("init(coder:) has not been implemented") 
    } 
} 

但是當我嘗試實例是:

let countButton = LabelBarButtonItem(text: "0 items") 

代碼編譯正確,但在運行時失敗:

fatal error: use of unimplemented initializer 'init()' for class 'TestProject.LabelBarButtonItem' 

我不明白爲什麼在這種情況下會發生這種情況,或者一般會導致此問題的原因是什麼。初始值設定項應該直接委託給超類中的init(customView)。爲什麼叫init()呢?它不應該參與。

任何人都可以解釋發生了什麼?當我試圖將其他UIKit類別進行子類化時,彈出類似問題

+0

這裏的子類的UILabel的一個例子,這可能有助於http://stackoverflow.com/q/32662344/294884 – Fattie 2015-09-19 00:50:14

回答

4

問題是init(customView:)調用init()

而且由於您有必需的初始化程序,因此不再繼承init()。因此,即使只需致電super.init(),也必須執行此操作。

然後,您將面臨(溫和)煩惱,不得不初始化您在init()以及init(text:)中的所有屬性。但是,在你的特定情況下,首先不需要在初始化程序中這樣做。我會寫你的類是這樣的:

class LabelBarButtonItem: UIBarButtonItem { 
    let label = UILabel(frame: CGRectZero) 
    init(text: String) { 
     super.init(customView: self.label) 
     self.label.text = text 
     self.label.tintColor = UIColor.grayColor() 
    } 
    private override init() { 
     super.init() 
    } 
    required init(coder aDecoder: NSCoder) { 
     fatalError("init(coder:) has not been implemented") 
    } 
} 

您的評論,你問:

但現在,如果我重寫的init(),我的類的客戶可以創建LabelBarButtonItem的無效實例只是調用LabelBarButtonItem()

正確。這就是爲什麼我已將init()覆蓋標記爲private。請注意,只有當這個類本身在文件中關閉時,這才起作用。

另一種可能性是將所有初始化程序(包括init(coder:))標記爲convenience。現在你繼承了init(),整個問題就消失了。但是,這引入了另一組問題,並作爲讀者的練習。

爲了澄清,我把整個情況視爲Swift中的一個bug。直到最近的一次修訂(Xcode 6.1?)之前,它的行爲不像IIRC。您正在被super.init(customView:)稱爲您的init()。你可能會認爲這是錯的。你有一個很好的bug報告用例。在運行時崩潰似乎是錯誤的行爲;如果發生這種情況,編譯器爲什麼不阻止我們?也許別人可以證明Swift在這種情況下所做的事情。我只是想解釋它。

+0

好吧,這是有道理的。但是現在如果我重寫'init()',我的類的客戶端可以通過調用'LabelBarButtonItem()'(不傳入默認文本)來創建'LabelBarButtonItem'的無效實例。我可以重寫'init()',刪除到超類,並以某種方式使此初始值設定項隱藏到外部代碼? – Bill 2014-11-24 23:02:15

+0

@Bill我已經大大擴展了我的答案,並納入了您的問題,並將我的意見轉入其中。看看你的想法... – matt 2014-11-24 23:47:30

+0

感謝您的解釋 - 我很感激!我剛剛向蘋果提交了一個錯誤報告。 – Bill 2014-11-25 00:54:10

2

我不得不爲一個項目繼承UIBarButtonItem,並且馬特的回答綽綽有餘,只有一點區別。我必須爲代碼的初始化工作添加便利。就我而言,我的子類沒有財產。

這是Swift 3的代碼,以防萬一。

class PlayerBarButtonItem: UIBarButtonItem { 

convenience init(assetName: String, target: Any, selector: Selector) { 

    let barButton = UIButton(frame: CGRect(x: 0, y: 0, width: 34, height: 34)) 
    let barButtonImage = UIImage(named: assetName)?.withRenderingMode(.alwaysTemplate) 
    barButton.setImage(barButtonImage, for: .normal) 
    barButton.tintColor = UIColor.white 
    barButton.addTarget(target, action: selector, for: .touchUpInside) 

    self.init(customView: barButton) 
} 

private override init() { 
    super.init() 
} 

required init?(coder aDecoder: NSCoder) { 
    fatalError("init(coder:) has not been implemented") 
} 
+0

正確,initWithCustomView是一個方便的初始化程序,因此應該像你一樣自我鏈接。 – malhal 2018-01-20 22:50:57

相關問題