2016-01-14 104 views
10

我想知道一個簡單的類中的初始化程序等同於什麼協議,它只包含初始化功能,並且僅用於在具體類中擴展。協議擴展初始化程序

所以可能是最簡單的就是顯示代碼 - 我要找的協議擴展相當於如下:

import UIKit 

class Thing { 
    var color:UIColor 
    init(color:UIColor) { 
     self.color = color 
    } 
} 
class NamedThing:Thing { 
    var name:String 
    init(name:String,color:UIColor) { 
     self.name = name 
     super.init(color:color) 
    } 
} 
var namedThing = NamedThing(name: "thing", color: UIColor.blueColor()) 

我期待的代碼看起來像:

protocol Thing { 
    var color:UIColor {get set} 
} 
extension Thing { 
    init(color:UIColor) { 
     self.color = color 
    } 
} 
class NamedThing:Thing { 
    var name:String 
    var color:UIColor 
    init(name:String,color:UIColor) { 
     self.name = name 
     self.init(color:color) 
    } 
} 

我見過其他StackOverflow問題(例如How to define initializers in a protocol extension?)中提出的解決方案,但我不確定它們是否工作,也沒有專門解決類初始化程序中的其他參數的這個問題。

回答

11

你必須提供一個有效的init鏈來創建一個類的實例,並限制了協議初始值設定項的選項。由於您的協議不能確定覆蓋使用它的類的所有成員,因此您在協議中聲明的任何初始化程序都需要將該類的「未知」成員的初始化委派給由該協議提供的另一個初始化程序課本身。

我調整你的例子來說明這一點,使用基本的init()作爲協議的委託初始值設定項。如你所見,這要求你的類在調用init()時實現所有成員的初始值。在這種情況下,我通過在每個成員的聲明中提供默認值來實現這一點。而且,由於某些成員並不總是有實際的初始值,所以我將它們改爲自動解包可選項。

爲了使認爲更有趣,你的類不能委託初始化到一個協議提供的初始化,除非它通過一個方便的初始化。

我不知道是否所有這些限制是值得的麻煩。我懷疑你正在嘗試使用一個協議,因爲你需要一堆通用變量在實現該協議的類之間一致地初始化。也許使用委託類將提供比協議更簡單的解決方案(只是一個想法)。

protocol Thing:AnyObject 
{ 
    var color:UIColor! { get set } 
    init() 
} 

extension Thing 
{  
    init(color:UIColor) 
    { 
     self.init() 
     self.color = color 
    } 
} 

class NamedThing:Thing 
{ 
    var name:String! = nil 
    var color:UIColor! = nil 

    required init() {} 

    convenience init(name:String,color:UIColor) 
    { 
     self.init(color:color) 
     self.name = name 
    } 
} 
+1

符合AnyObject我們多餘的,隱式解包的名稱和顏色是危險的,而不是必需的(改爲設置默認值) – user3441734

+0

感謝您的富有洞察力的評論,您似乎遇到了類似的障礙。我同意你的評論是否值得這樣做。我想我正在尋找在面向協議的方法中實現上述問題的最佳實踐。需要給vars默認值或者讓它們隱式解開對我來說似乎不是太方便也不是最好的做法,並且讓我懷疑這是否使用協議的味道對於這個問題不是正確的方法。 @ alain-t你可以使用代碼示例填寫你的評論'代表班'嗎? –

+0

@CraigGrummitt swift中的所有變量(和/或常量)在使用之前必須有一些值(對於引用類型,Swift中的變量表示爲類,值爲引用,對於值類型,它是值self)。直接相當於null不存在的就是Swift。 var i =可選()具有默認值nil。 var j = ImplicitlyUnwrappedOptional ()給出了相同的結果(兩者都是枚舉'類型')....(繼續下面) – user3441734

1

這就是我對「代表班」的想法。

這是我用來使用協議將存儲變量添加到類的技術。

class ManagedColors 
{ 
    var color:UIColor 
    // other related variables that need a common initialisation 
    // ... 
    init(color:UIColor) 
    { 
     self.color = color 
     // common initialisations for the other variables 
    } 
} 

protocol ManagedColorClass 
{ 
    var managedColors:ManagedColors { get } 
} 

extension ManagedColorClass 
{  
    // makes properties of the delegate class accessible as if they belonged to the 
    // class that uses the protocol 
    var color:UIColor { 
         get { return managedColors.color } 
         set { managedColors.color = newValue } 
         }  
} 


// NamedThing objects will be able to use .color as if it had been 
// declared as a variable of the class 
// 
// if you add more properties to ManagedColors (and the ManagedColorHost protocol) 
// all your classes will inherit the properties as if you had inherited from them through a superclass 
// 
// This is an indirect way to achive multiple inheritance, or add additional STORED variables with 
// a protocol 
// 
class NamedThing:ManagedColorClass 
{ 
    var name:String 
    var managedColors:ManagedColors 

    init(name:String,color:UIColor) 
    { 
     managedColors = ManagedColors(color:color) 
     self.name = name 
    } 
} 

let red = NamedThing(name:"red", color:UIColor.redColor()) 
print(" \(red.name) \(red.color)") 
+0

得到我的頭後,你的協議名稱中有'class'這個詞,我按照你的例子,謝謝你的輸入。用另一種方式提出你的建議,你使用工廠類來建立原來簡單的'Thing'類中的任何屬性吧?我想我把它作爲這個問題的解決方案的問題是,它的基礎上它再次使用一個類。但這是一個有趣的例子,謝謝。 –

+0

它確實使用了一個類,但是這裏的好處是你可以在繼承層次結構之外使用它,就像使用協議一樣。我正在使用它來實現「多重繼承」,這就是爲什麼我使用Class來命名協議的原因。對於單個變量,它看起來像是一種矯枉過正,但是當您想要將數據和行爲添加到具有自己層次結構的多個類時,它開始變得更有意義。爲了您的具體需求,我同意這可能不是最好的方法。 –

10
protocol Thing { 
    var color: UIColor {get set} 
} 

真棒,沒有問題。

extension Thing { 
    init(color: UIColor) { 
     self.color = color 
    } 
} 

不,這是行不通的。這打破了太多規則。首先也是最重要的是,這不一定會設置所有的屬性。考慮你的NamedThing。這種情況下name是什麼?如果color設置程序獲取其他尚未設置的屬性,會發生什麼情況?編譯器看不到每個可能的實現,所以它不知道是否color只是一個伊娃或更復雜的東西。不,這不起作用。

真正的問題是「可以在具體類中擴展的抽象類」。忘記課程。忘記繼承。 Swift是關於組合和協議,而不是繼承。所以讓我們來考慮你在評論中描述的例子(儘管在Cocoa中,也沒有「抽象類」)。讓我們假設設置顏色實際上是很多你不想重複的代碼。那沒問題。你只需要一個功能。

import UIKit 

protocol Thing { 
    var color: UIColor {get set} 
} 

private extension Thing { 
    static func colorForColor(color: UIColor) -> UIColor { 
     // We don't really use the color directly. We have some complicated code that we don't want to repeat 
     return color 
    } 
} 

final class NamedThing: Thing { 
    var name: String 
    var color: UIColor 

    init(name: String, color: UIColor) { 
     self.name = name 
     self.color = NamedThing.colorForColor(color) 
    } 
} 

因爲你的擴展點是處理部分初始化,就讓它計算出您需要的部分。不要試圖在擴展中使它成爲初始化器,因爲它必須負責初始化所有內容,並且在將它與繼承結合時非常難以正確執行。

+0

感謝您的幫助Rob。爲簡單起見,我將代碼簡化爲一個簡單的例子,而沒有深入討論爲什麼它需要成爲一個類,但在現實生活中,它是一個需要實現協議的類,因爲它將繼承一個UIKit類。 樣板代碼旨在通過處理顏色設置的協議擴展來說明。 –

+0

順便說一句,我剛剛通過您的評論意識到「Swift中沒有抽象類」,我們可能正在處理對「抽象類」的不同理解,如果我把這個問題與對「抽象類」的錯誤理解混淆了,術語。我編輯的問題更清晰。 –

+0

這個UIKit類是什麼總是必須被子類化? (我們同意什麼是抽象類,我只是想不出你正在談論的類。UIGestureRecognizer?)我強烈懷疑你面臨的實際問題以另一種方式更容易解決。這是過度簡化問題的經典問題。 –

-1

我得出的結論是,問題是無法回答的,因爲協議擴展不能動態定義屬性(除非它爲屬性提供默認值,或者將它們聲明爲隱式解包)。要在多個協議時尚化解決這個問題,它需要不同的方法,這仍然涉及聲明和初始化所有變量在具體的類,類似:

import UIKit 
protocol Colorable { 
    var color: UIColor {get set} 
} 
protocol Nameable { 
    var name: String {get set} 
} 
class ColoredNamedThing: Colorable, Nameable { 
    var name: String 
    var color: UIColor 

    init(name: String, color: UIColor) { 
     self.name = name 
     self.color = color 
    } 
} 

var coloredNamedThing = ColoredNamedThing(name: "Name", color: UIColor.redColor()) 

謝謝@阿蘭-T的答案我我會接受,因爲它最接近我的問題的解決方案,儘管它包括隱含的解包屬性。

感謝@ rob-napier也爲您的貢獻。