2017-03-09 92 views
4

Swift中的協議可以在其定義中聲明init()方法。然而,我想不出任何解決任何問題的用例,而不是強制符合類定義協議中的init()。我們可以在協議類型上調用已聲明的方法,但協議初始化不能用於實例化它的對象,這是它唯一的目的。在Swift協議中init()如何相關?

在協議中聲明init()方法有什麼問題解決?

+2

要不然怎麼會一個協議擴展能夠創建符合協議的給定類型的新實例嗎? ;) – Hamish

+0

啊!對。好點子。它與協議擴展相關。 – Shubham

+1

這是一個例子:http://stackoverflow.com/questions/25645090/protocol-func-returning-self。 –

回答

2

它迫使類有init(data: data)從一些數據,例如:

protocol JSONable { 
    init(data: JSON) 
} 

軍隊的所有類,是JSONable有一個初始化器從JSON,所以你總是肯定的是,你可以創建一個實例JSON

+1

貌似這就是問題所說的話,我認爲這個問題是什麼目的它服務(除了確保符合執行init方法),如果我不能把喜歡的東西'JSONable(數據:<*someJson*>)' – uchiha

+0

@uchiha好,那麼我不會得到這個問題,確保你100%創建一個實例是至關重要的,我無法想象任何其他目的。 – JuicyFruit

+1

@uchiha,但你可以做'FUNC˚F(jsonString:字符串) - >牛逼{返回T(數據:parseJSON(jsonString))}' – user28434

1

它通常用於允許協議擴展和約束協議的通用佔位符在符合協議的給定具體類型上調用初始化程序。的init<S : Sequence>(_ elements: S)例如,考慮RangeReplaceableCollection的默認實現:

extension RangeReplaceableCollection { 

    // ... 

    /// Creates a new instance of a collection containing the elements of a 
    /// sequence. 
    /// 
    /// - Parameter elements: The sequence of elements for the new collection. 
    public init<S : Sequence>(_ elements: S) where S.Iterator.Element == Iterator.Element { 
     self.init() 
     append(contentsOf: elements) 
    } 
    // ... 
} 

沒有init()被定義爲RangeReplaceableCollection協議的要求,有沒有辦法擴展到知道,我們可以爲了創建一個新的實例調用init()符合類型。

但它也可用於直接外泛型和擴展的 - 比如,它可以被用於構建由給定存在元類型(的「符合的協議一些具體類型的元類型所表示的新的實例「):

protocol P { 
    init() 
} 
struct S : P { 
    init() {} 
} 

let s: P = S() 
let s1 = type(of: s).init() // creates a new instance of S, statically typed as P. 

在這個例子中:

  • type(of: s)返回動態類型s作爲P.Type(一種存在metaty的pe)​​,因爲s是靜態類型爲P。請記住,type(of:)是一個(T) -> T.Type操作。

  • init()構建底層具體類型的新實例,在這種情況下S

  • 新實例靜態類型爲P(即裝入存儲容器中)。

+0

我覺得類型(:S)''將會返回'S.Type '在這裏。而且,我們不能在'P.Type'上調用初始化器,因爲's'被輸入爲'P',所以我們不能在'P.Type' – Shubham

+0

@Shubham No上調用初始化器。你可以在'P.Type'上調用這個初始化函數 - 可以自己嘗試它:)它只是'P.Protocol'(協議本身的類型),你不能*調用一個初始化函數,就像它並不代表具體的類型。 – Hamish

+0

我在操場上試過了。 'type(of:s)'返回'S.Type',&'P.Type.init()'失敗,並且「P.Type沒有名爲init的成員」 – Shubham

2

我認爲真正的實用工具來作爲一個泛型o函數的約束。這是我的一個項目中的真實代碼。

我宣佈一個協議與init

protocol JSONCreatable { 
    init(fromJson json: JSON) 
} 

然後,在通用功能,我返回符合該協議的類:

import SwiftyJSON 

extension JSON { 
    func asObject<T>() -> T? where T: JSONCreatable { 
     if isEmpty { 
      return nil 
     } 
     return T(fromJson: self) 
    } 

    func asArray<T>() -> [T] where T: JSONCreatable { 
     return array?.map{ json in T(fromJson: json) } ?? [] 
    } 
} 

這讓我做事情是這樣的:

let user: User = json["user"].asObject() 
let results: [Element] = json["elements"].asArray() 
+0

通常,我發現形式'() - > T'的通用函數通常更好地寫作'SomeProtocol'的擴展中的初始化函數。在'[T]'的情況下,我還會考慮在受限制的''Array''擴展中寫入'init'。雖然可能只是一個偏好問題。我發現'let array = [SomeJSONCreatable](json:someJSON)'比let數組更自然:[SomeJSONCreatable] = someJSON.asArray()'。 – Hamish