Swift泛型文法進階處理一例

來源:互聯網
上載者:User

Swift參考某幾種語言,增加了泛型這一機制,讓人又愛又恨。

泛型增加了語言的表現力,減少了冗餘,這是好訊息;然而壞訊息是:對於複雜的實現來說,七繞八不繞,文法容易把人搞暈…以下就是一例。

這是從我實際的項目中摘出來的例子,做了簡化。有童鞋看到後面的代碼可能會問,這麼簡單的問題,幹嘛要繞圈寫這麼複雜的實現。。。這不前面說了麼,因為實際的項目複雜。。。這裡只是簡化到講解本主題,所以若有詞不達意,也請包涵。

這裡有一個通用協議和另一個Main協議,Main協議遵守通用協議:

protocol CommonDelegate {    associatedtype Item    func invoke(with item:Item)}protocol MainDelegate:CommonDelegate {    func save(with item:Item)}

這裡比較奇怪的是Item類型,它是什麼呢。它是實際要操作的Model。

因為上述協議和遵守協議的類在Framework中,而實際的Model在App裡,所以有必要再寫一個Model協議:

protocol FooDelegate{    var name:String {get set}    var id:Int {get set}    var desc:String {get}}

記住,實際的Foo資料模型類在App裡,它遵守FooDelegate協議:

class Foo:FooDelegate{    var name:String    var id:Int    var desc: String{        return "\(name):\(id)"    }    init(name:String,id:Int) {        self.name = name        self.id = id    }}

下面輪到”過渡”類Main隆重出場了:

class Main{    var delegate:MainDelegate!    func breed(){        let newFoo = Foo(name: "hopy", id: 1)        self.delegate.save(with: newFoo)    }}

沒錯,它只有一個breed方法,而其中又調用了委託的save方法。這裡很有意思,實際上它本身不幹啥活,具體幹啥還得委託delegate說了算。

上面這樣寫對麼。。。錯。。。

回到MainDelegate協議看一下,它繼承於CommonDelegate,其中有一個關聯類別型Item,在聲明委託變數delegate的時候必須確定Item的類型,但是這裡啥也沒有說明白…

所以我們需要將Main類修改成如下形式:

class Main<T> where T:MainDelegate,T.Item:FooDelegate{    var delegate:T!    func breed(){        let newFoo = Foo(name: "hopy", id: 1)        self.delegate.save(with: newFoo)  //TODO:注意這行    }}

注意我們在Main裡綁定了一個泛型T,確定了Item的類型為FooDelegate。這裡Item的類型為什麼不是Foo。。。因為前面說過了實際的Model在App裡由使用者定義,它可以是一個CoreData的託管對象或是其他什麼別的東東,Framework控制不了,也沒心思理這些,不管實際資料模型是啥,只要遵守FooDelegate就行了。

看到上面TODO那行了麼。別急,我們最後再來說它。

OK,現在只剩最後一個實際“幹活”的類了,就叫它Maker吧:

class Maker:MainDelegate {    typealias Item = Foo    var main:Main<Maker>!    func didLoad(){        main = Main<Maker>()        main.delegate = self        main.breed()    }    func invoke(with item: Item) {        print("invoke item:\(item.desc) done!!!")    }    func save(with item: Item) {        print("save item [\(item.desc)] done!!!")    }}

因為顯然Maker在App裡,所以我們把Item和Foo綁定;實際上這裡也不可以和FooDelegate綁定,因為不可以將非實體類型和關聯類別型綁定。

Maker裡的main屬性很有意思,它將Main的泛型型別設為自己。

上面的代碼都可在Xcode的playground裡愉快地玩耍,大家可以實際運行下試試。

如果到這裡你還沒有暈,那麼最後我們再來聊一聊,前面TODO那一行。

假設你按我說的嘗試運行一下,你會失望的:就在TODO那行報錯了:

為毛呢。協議裡save方法的參數類型是Item,實際Item類型卻是FooDelegate,你可能會想做一下強轉:

let newFoo = Foo(name: "hopy", id: 1) as FooDelegate

很遺憾,錯誤依舊。我們不可以在Maker裡將Item設定為FooDelegate,原因前面說過了。那麼這裡該怎麼寫呢。

很簡單,你不是要抽象麼。我就給你抽象:

let newFoo = Foo(name: "hopy", id: 1) as! T.Item

現在運行OK啦:

這就是Swift泛型的折騰,謝謝觀賞。

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.