2015-05-28 21 views
1

在使用大量初始化工具覆蓋的子類中使用常量是很乏味的。看看下面的類,我需要在兩個初始化器中複製代碼。使用常量時的常見初始化

class Test : UIView { 

    let subview: UIView 

    override init(frame: CGRect) { 
     subview = UIView() // once 
     super.init(frame: frame) 
    } 

    required init(coder aDecoder: NSCoder) { 
     subview = UIView() // twice 
     super.init(coder: aDecoder) 
    } 

} 

如果我試圖用一個共同的初始化的話,我得到以下錯誤(見註釋)

override init(frame: CGRect) { 
    commonInit() // 1: Use of 'self' in method call 'commonInit' before super.init initializes self 
    super.init(frame: frame) // 2: Property 'self.subview' is not in initialized at super.init call 
} 

private func commonInit() { 
    subview = UIView() // 3: Cannot assign to 'subview' in 'self' 
} 

它工作正常,如果我不使用一個常數,這樣定義子視圖:在初始化

var subview: UIView? 

然後當然開關順序是這樣的:

super.init(frame: frame) 
commonInit() 

所以我的問題是:有沒有辦法使用常用的常量初始化Swift中的常量?

編輯:我完全忘了提的是,這裏的鬥爭,我不能啓動子視圖之前,我在init是,它是基於聲明的常量時不知道數據開始。

+0

重複http://stackoverflow.com/questions/的24023412/how-to-implement -inits-with-same-content-without-code-duplicate-in-swift? –

+0

不,正如我所說我知道如何爲var做這個,我使用let – Johannes

+0

請參閱下面的答案。它允許您根據上下文正確地初始化值。 –

回答

0

執行以下操作:

class Test : UIView { 

    let subview = UIView() 

    required init(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 
     //edit subview properties as needed 
    } 
} 
2

試試這個:

class Test : UIView { 

    let subview = UIView() 

    override init(frame: CGRect) { 
     super.init(frame: frame) 
    } 

    required init(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 
    } 
} 
0

一種選擇是繼的Xcode模式:

class Test : UIView { 

    var subview: UIView! 

    override init(frame: CGRect) { 
     super.init(frame: frame) 
     commonInit() 
    } 

    required init(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 
     commonInit() 
    } 

    func commonInit() { 
     subview = UIView() 
    } 
} 

通知您subviewvar

另一種選擇是:

class Test : UIView { 

    let subview: UIView = { 
     let sv = UIView() 
     // some config, (i.e.: bgColor etc., frame is not yet _real_ 
     // can't yet access instance's frame and other properties 
     return sv 
    }() 

    override init(frame: CGRect) { 
     super.init(frame: frame) 
     commonInit() 
    } 

    required init(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 
     commonInit() 
    } 

    func commonInit() { 
     // frame might be valid, preferably use layout constraints 
     addSubview(subview) 
    } 
} 

希望這有助於

+1

即使在調用super.init()之前,子視圖也會被初始化,這並不是真正的「懶惰」:) - 也許你的意思是'懶惰的子視圖:UIView = ...'(但它不再是常量) 。 –

+0

@MartinR你是對的,我對_lazy_的使用是誤導性的。我的意思是_lazy commonInit()_: - /編輯它,希望它更清楚我的意圖。謝謝 –

3

另一種選擇:

class Test : UIView { 

    let subview:UIView 

    init(frame: CGRect?, coder: NSCoder?) { 

     // The first phase initialization here 
     subview = UIView() 

     if let frame = frame { 
      super.init(frame: frame) 
     } 
     else if let coder = coder { 
      super.init(coder: coder) 
     } 
     else { 
      super.init() 
     } 

     // the Second phase initialization here 
     self.addSubview(subview) 
    } 

    convenience init() { 
     self.init(frame: nil, coder: nil) 
    } 

    override convenience init(frame: CGRect) { 
     self.init(frame: frame, coder: nil) 
    } 

    required convenience init(coder aDecoder: NSCoder) { 
     self.init(frame: nil, coder: aDecoder) 
    } 
} 

一點點清潔的替代:

class Test : UIView { 

    let subview:UIView 

    private enum SuperInitArg { 
     case Frame(CGRect), Coder(NSCoder), None 
    } 

    private init(_ arg: SuperInitArg) { 

     subview = UIView() 

     switch arg { 
     case .Frame(let frame): super.init(frame:frame) 
     case .Coder(let coder): super.init(coder:coder) 
     case .None: super.init() 
     } 

     addSubview(subview) 
    } 

    convenience init() { 
     self.init(.None) 
    } 
    override convenience init(frame: CGRect) { 
     self.init(.Frame(frame)) 
    } 
    required convenience init(coder aDecoder: NSCoder) { 
     self.init(.Coder(aDecoder)) 
    } 
} 
+0

我仍然在努力是否關閉問題作爲http://stackoverflow.com/questions/24023412/how-to-implement-two-inits-with-same-content-without-code-duplication-in -swift,它有一個類似的答案http://stackoverflow.com/a/26772103/1187415(即使你的看起來更清潔)。 –

+0

哇,我沒有看到答案。至少,我的回答絕對是一個騙局。 – rintaro

1

這非常適用於米E:

// Declare this somewhere (it can be used by multiple classes) 
class FrameCoder: NSCoder { 
    let frame: CGRect 
    init(_ frame: CGRect) { 
     self.frame = frame 
     super.init() 
    } 
} 

然後,當你想有一個共同的初始化模式,使用此:

class MyView: UIView { 

    let something: SomeType 

    required init(coder aDecoder: NSCoder) { 
     if (aDecoder is FrameCoder) { 
      super.init(frame: (aDecoder as! FrameCoder).frame) 
     } 
     else { 
      super.init(coder: aDecoder) 
     } 

     // Common initializer code goes here... 
     something = // some value 
    } 

    override init(frame: CGRect) { 
     self.init(coder: FrameCoder(frame)) 
    } 
} 

使用這種方法,你不必爲let定義創建默認值的優勢 - 您可以在上下文中將它們設置爲正確的值,就像只有一個初始化程序一樣。

請注意,您可以使用此技術獲取任意值的初始值設定項(不僅適用於init(frame: CGRect)) - 您可以創建特定的NSCoder子類來包裝任何需要傳遞給初始值設定項的值和類型,然後將其鏈接到您的init(coder:)方法。

(也有可能是某種方式與通用做到這一點...還沒有完全想通了沒有!任何人......?)