2015-02-06 63 views
12

我不明白爲什麼程序員在他們的類實現中使用extension關鍵字。您可以閱讀其他主題,然後在語義上將代碼更加分離等等。但是,當我使用自己的代碼時,使用// MARK - Something時感覺更清晰。然後當你在Xcode中使用方法列表(ctrl + 6)時,一切都會在第一眼看到。Swift和使用類擴展

在蘋果文檔,你可以閱讀:

「擴展增加新的功能,以現有的類,結構或枚舉類型」

那麼,爲什麼不直接寫我自己的代碼裏面我自己的班級?與我想擴展某些外部類的功能不同,如NSURLSessionDictionary,其中使用擴展名。

馬特湯普森在他的阿拉莫菲爾圖書館使用擴展,也許他可以給我一點解釋,他爲什麼選擇這種方法。

+0

使用你喜歡的任何一個,但擴展使它比單純的'MARK:'更明確,明確指出它開始的位置和結束位置。坦率地說,這不是一個問題,因爲我會同時使用'MARK:'和'extension'。 'extension'的另一個優點是您可以輕鬆地摺疊該代碼(例如「編輯器」 - 「代碼摺疊...」 - 「摺疊」或單擊帶陰影的左邊距)。 – Rob 2015-11-19 22:03:55

回答

14

對我來說,這似乎是完全合理的,因爲您可以使用擴展來將不同部分的邏輯公開給不同的擴展。這也可以用來製造類一致性協議更具有可讀性,比如

class ViewController: UIViewController { 
... 
} 

extension ViewController: UITableViewDelegate { 
... 
} 

extension ViewController: UITableViewDataSource { 
... 
} 

extension ViewController: UITextFieldDelegate { 
... 
} 

協議方法是在清晰度不同的擴展分開,這似乎是更好的閱讀比讓說:

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate {} 

因此,我認爲使用擴展使自己的代碼更具可讀性沒有任何壞處,而不僅僅是從SDK中擴展現有的類。使用擴展可以避免在控制器中擁有大量代碼,並將功能拆分爲易於閱讀的部分,因此使用這些擴展並沒有什麼不利之處。

+0

什麼NSCoding協議?您不能使用此協議的擴展名。 – Deny 2015-02-06 15:04:45

+0

這是棘手的地方,擴展不能添加指定的初始值設定項,因此NSCoding的'init(coder:)'不應該通過擴展來實現,不太確定我自己。 – libec 2015-02-07 00:53:41

+0

如果您需要訪問您正在擴展的課程中的任何私人內容,則不起作用,是嗎?或者我錯過了什麼? – 2016-11-06 10:55:25

6

使用擴展允許您保持協議一致性的聲明在實現該協議的方法旁邊。

如果沒有擴展,想象聲明你的類型爲:使用擴展,在那裏你捆綁在一起的協議的執行情況,實現它的這些具體方法

struct Queue<T>: SequenceType, ArrayLiteralConvertible, Equatable, Printable, Deflectable, VariousOtherables { 

// lotsa code... 

// and here we find the implementation of ArrayLiteralConvertible 
    /// Create an instance containing `elements`. 
    init(arrayLiteral elements: T…) { 
     etc 
    } 

} 

進行對比:

struct Queue<T> { 
    // here go the basics of queue - the essential member variables, 
    // maybe the enqueue and dequeue methods 
} 

extension SequenceType { 
    // here go just the specifics of what you need for a sequence type 
    typealias Generator = GeneratorOf<T> 
    func generate() -> Generator { 
     return GeneratorOf { 
      // etc. 
     } 
    } 
} 

extension Queue: ArrayLiteralConvertible { 
    init(arrayLiteral elements: T...) { 
     // etc. 
    } 
} 

是的,你可以用// MARK來標記你的協議實現(並且記住,你可以結合使用這兩種技術),但是你仍然會被分割到文件的頂部,在那裏協議支持的聲明將會是b e,以及文件的主體,你的實現在哪裏。另外,請記住,如果您正在實施一個協議,您將隨時獲得來自IDE的有用(如果稍爲冗長)反饋,告訴您您還需要執行哪些操作。使用擴展來逐個執行每個協議使它(對我而言)比一次完成所有操作(或者在添加它們時從上到下跳來跳去)要容易得多。

鑑於此,將其他非協議但相關的方法分組爲擴展也很自然。

我實際上偶爾發現它令人沮喪,當你不能做到這一點。例如,

extension Queue: CollectionType { 
    // amongst other things, subscript get: 
    subscript(idx: Index) -> T { 
     // etc 
    } 
} 

// all MutableCollectionType adds is a subscript setter 
extension Queue: MutableCollectionType { 
    // this is not valid - you’re redeclaring subscript(Index) 
    subscript(idx: Int) -> T { 
     // and this is not valid - you must declare 
     // a get when you declare a set 
     set(val) { 
      // etc 
     } 
    } 
} 

因此,您必須在同一個擴展中實現兩者。

+1

好的,所以當你的類源代碼只有幾頁時,你就看不到這個類實現了哪個協議。您必須通過代碼搜索這些信息。對我來說,這不比在代碼中使用MARK更清晰。 – Deny 2015-02-06 15:00:24

+0

馬的課程,但我會說使用語言而不是評論來表明意圖更清晰。另請參閱我的編輯,它使您可以輕鬆實現協議。 – 2015-02-06 15:14:05

+0

感謝您的意見。我會嘗試將兩種方法結合使用 - 使用擴展名並將其標記爲// MARK。 – Deny 2015-02-07 10:24:29