2014-06-09 264 views
26

比方說,我在斯威夫特下面的類(其中有明顯的問題)呼叫方法

class MyClass { 
    let myProperty: String 

    init() { 
     super.init() 
     self.setupMyProperty() 
    } 

    func setupMyProperty() { 
     myProperty = "x" 
    } 
} 

這是過於簡化,但基本上,我想的myProperty初始化委派到setupMyProperty()方法。這是我經常用來分解課堂設置不同部分的模式。

但是當然,我不能調用self,直到超級初始化器運行,並且我不能運行超級初始化器,直到所有的屬性都被設置好,所以我在catch 22上。因爲setupMyProperty()不被視爲初始化程序,所以無論如何都無法分配myProperty

誰能告訴我如何在Swift中實現這個模式?

+0

我不知道這是否適合你,但你可以在聲明屬性時分配一個值。 'let myProperty:String =「x」' –

+0

是的,我使用它是有道理的。但是,如果這些東西是基於初始值設定項的參數進行初始化的,則初始值設定項會變得混亂。我想這是一個跡象,我的班級有太多屬性。 – mprivat

+1

查看WWDC會話403:中級Swift,大約29分鐘在涵蓋類初始化。 – DogCoffee

回答

30

宣佈它作爲一個隱含展開可選

class MyClass : NSObject { 
    var myProperty: String! 

    init() { 
     super.init() 
     self.setupMyProperty() 
    } 

    func setupMyProperty() { 
     self.myProperty = "x" 
    } 
} 

頁的「雨燕編程語言」手冊499

+1

這樣做你不會失去一些安全嗎?我想我必須確保該屬性在被訪問之前被初始化,否則會出現運行時錯誤。對於這個例子它不是一個常數。我猜這是我見過的最好的方式,只是不完美 – mprivat

+0

它只會在另一個線程嘗試訪問super.init()和真正的「set」之間的情況下才會被初始化。我不知道你是否可以鎖定變量,直到它完全初始化(請參閱http://stackoverflow.com/questions/24045895/what-is-the-swift-equivalent-to-objective-cs-synchronized,但我'沒有足夠的文檔來說明它是否可能,以及它是否可能成爲在初始化程序中使用它的問題)。比爾的答案似乎是另一個好的選擇。 – LombaX

+0

所以沒有辦法讓'myProperty'保持不變(let)? –

2

不能使用self,直到您的實例的內存完全初始化(此時你無法再設置常量屬性),因此您指定的初始化程序必須執行的操作的順序爲:

  1. 初始化此類添加的所有屬性
  2. 調用父類的初始化(如果有超)
  3. 現在你可以使用self,調用方法等

我不知道,如果有一個不變的性質的情況下,一個好的解決方法。一個替代方案是將財產申報作爲隱含展開可選的,因此它的初始設置爲無:

class MyClass { 
    var myProperty: String! 
    init() { 
     super.init() // only if you actually have a superclass, and make sure this does not use `myProperty` 
     self.setupMyProperty() 
    } 

    func setupMyProperty() { 
     myProperty = "x" 
    } 
} 

要小心,它失去了一下類型安全的,因爲myProperty現在可以nil,如果當您嘗試訪問它時,它會導致運行時錯誤。所以只有在你確定它會被所有指定的初始化器初始化時纔會這樣做,而不是被初始化鏈中setupMyProperty()之前調用的任何東西所使用(例如,當一個超類初始化器調用一個你覆蓋的方法訪問myProperty)設置爲零。

另外,參考the docs,特別是關於整個調用順序的東西的類繼承和初始化部分,我上面解釋過。

+1

'private(set)var myProperty:String'會阻止對屬性值進行外部邪惡修改 – bshirley

8

setupMyProperty需要訪問自我嗎?如果沒有,你可以通過類方法實現:

class MyClass: NSObject { 
    let myProperty: String 

    init() { 
     myProperty = MyClass.setupMyProperty() 
     super.init() 
    } 

    class func setupMyProperty() -> String { 
     return "foo" 
    } 
} 
+2

問題在於,雖然它與簡單示例一起工作,但重點是在子方法中初始化一組屬性。 – mprivat

1

試着把setupMyProperty()放在一個常量中。然後它就在你初始化之前,你可以從init()調用它。你甚至可以訪問參數如下:

class MyClass { 
    var myProperty: String 
    let setupMyProperty : (String) -> (void) = { 
     param in 
     self.myProperty = param 
    } 

    init(x: String) { 
    // removed redundant line: super.init() 
     self.setupMyProperty(x) 
    } 
} 
+0

你不需要super.init(),因爲'MyClass'是一個根類。 –

+0

當然,我沒有想到。現在刪除違規行。 – Tchelyzt