2016-09-17 39 views
1

這是一個後續行動這樣一個問題:Can I have a Swift protocol without functions與性能斯威夫特協議並不總是使用

假設我想更多的屬性,以我的協議添加:

protocol Nameable { 
    var name: String {get} 
    var fullName: String: {get} 
    var nickName: String: {get} 
} 

然而,並不是每一個結構符合此協議的可能具有全名和/或暱稱。我如何去做這件事?我可以使這兩個屬性可選嗎?或者,也許我需要三個單獨的協議?還是我只是將它們添加到每個結構,但讓他們空的,就像這樣:

struct Person : Nameable { 
    let name: String 
    let fullName: String 
    let nickName: String 
    let age: Int 
    // other properties of a Person 
} 

let person = Person(name: "Steve", fullName: "", nickName: "Stevie", age: 21) 

,編譯和作品,但我不知道這是「正確」的方法呢?

回答

2

不像在Objective-C,你不能定義純斯威夫特任擇議定書要求classes/structs財產。符合協議的類型必須採用指定的所有要求。

允許可選屬性需求的一種潛在方式是將它們定義爲可選項,默認實現的計算屬性僅返回nil

protocol Nameable { 
    var name : String? { get } 
    var fullName : String? { get } 
    var nickname : String? { get } 
} 

extension Nameable { 
    var name : String? { return nil } 
    var fullName : String? { return nil } 
    var nickname : String? { return nil } 
} 

struct Person : Nameable { 

    // Person now has the option not to implement the protocol requirements, 
    // as they have default implementations that return nil 

    // What's cool is you can implement the optional typed property requirements with 
    // non-optional properties – as this doesn't break the contract with the protocol. 
    var name : String 
} 

let p = Person(name: "Allan") 
print(p.name) // Allan 

但是這樣做的缺點的方法是,你可能污染與他們沒有實現(在這種情況下fullName & nickName)性能符合類型。

因此,如果它使一個類型有這些特性沒有邏輯感(比如你想以符合CityNameable - 但城市沒有(真正)有暱稱),你不應該是符合Nameable

如您所說,更靈活的解決方案將是定義多個協議以定義這些要求。這樣,類型可以精確選擇他們想要實現的要求。

protocol Nameable { 
    var name : String { get } 
} 

protocol FullNameable { 
    var fullName : String { get } 
} 

protocol NickNameable { 
    // Even types that conform to NickNameable may have instances without nicknames. 
    var nickname : String? { get } 
} 

// A City only needs a name, not a fullname or nickname 
struct City : Nameable { 
    var name : String 
} 

let london = City(name: "London") 

// Person can have a name, full-name or nickname 
struct Person : Nameable, FullNameable, NickNameable { 
    var name : String 
    var fullName: String 
    var nickname: String? 
} 

let allan = Person(name: "Allan", fullName: "Allan Doe", nickname: "Al") 

你甚至可以使用protocol composition爲了定義一個typealias代表所有這三種協議的便利,例如:

typealias CombinedNameable = Nameable & FullNameable & NickNameable 

struct Person : CombinedNameable { 
    var name : String 
    var fullName: String 
    var nickname: String? 
} 
+0

我不知道協議組成的,感謝分享該鏈接。有趣的是,蘋果在名爲'Named'的示例中調用了協議,而Swift API指導原則中聲明'描述功能的協議應該使用後綴名稱,可以是ible或ing(例如Equatable,ProgressReporting)。' – Koen

+0

@Koen Happy to幫助:)關於協議命名指南,國際海事組織都提供'命名'和'命名'是可以接受的,因爲它們都直接描述了一種能力。我通常想到的方式是它應該適合句子「An X is Y」,其中X是符合類型,Y是協議(例如「一個人是可命名/命名的」)。儘管按我自己的邏輯走,「CombinedNameable」並不是一個好選擇(我打算稱它爲「FullyNameable」,但與「FullNameable」IMO太接近了)。 – Hamish

1

可以使用協議extension提供一個默認實現這些特性,並覆蓋在那裏實際上你需要

extension Nameable{ 
    var fullName: String{ 
     return "NoFullName" 
    } 

    var nickName: String{ 
    return "NoNickName" 
    } 
} 
struct Foo : Nameable{ 
    var name: String 
}