記一次 StackOverFlow 問(wèn)題回答 —— Protocol Adopting Class Method returning Self

我在自己的項(xiàng)目中使用網(wǎng)絡(luò)請(qǐng)求是通過(guò)的自己寫(xiě)的 urlSession 的封裝庫(kù)(參考了不少 Alamofire的源碼)撞反。
前些天在將封裝庫(kù)重構(gòu)成面向協(xié)議的時(shí)候,想使用泛型函數(shù)來(lái)使 complete-handler 能夠處理不同的返回參數(shù)搪花。具體如何使用我在最后簡(jiǎn)單說(shuō)一下遏片。
我希望能夠定義一個(gè)協(xié)議 FormDataCreatable垛膝,需要實(shí)現(xiàn)一個(gè)接收 NSData 然后轉(zhuǎn)化為自身類(lèi)型的靜態(tài)方法,類(lèi)似于這樣:

protocol FromDataCreatable {
    static func fromData(data: NSData) throws -> Self?
}

比如說(shuō)我希望我得到一個(gè)從 urlSession 中得到的 data 能轉(zhuǎn)化成 Dictionary<String,AnyObject>
那我就這樣實(shí)現(xiàn)(有點(diǎn)繞丁稀,使用的是 extend-protocol )

extension FromDataCreatable where Self: Dictionary<String,AnyObject> {
    static func formData(data: NSData) throws -> Self {
        if let json = try NSJSONSerialization.JSONObjectWithData(
            data, options: []) as? Dictionary<String,AnyObject> {
            return json
        }
        return [ : ]
    }
}

extension Dictionary: FormDataCreatable {}

但是在我轉(zhuǎn)用 NSData 來(lái)采用這個(gè)協(xié)議的時(shí)候吼拥,就不能實(shí)現(xiàn)這個(gè)靜態(tài)方法了:
(為什么要 NSData 實(shí)現(xiàn)這個(gè)協(xié)議?一開(kāi)始說(shuō)了线衫,我希望能傳進(jìn)一個(gè)泛型 complete-handler)

extension NSData: FromDataCreatable {
    public static func formData(data: NSData) throws -> NSData {
    //報(bào)錯(cuò):method 'formData' in non-final class 'NSData' must return `Self` to conform to protocol 'FromDataCreatable'
        return data
    }
}

我在 StackOverFlow 上找尋答案的時(shí)候凿可,找到了這個(gè):
Method in non-final class must return Self to conform to protocol
也是同樣的問(wèn)題。其中一個(gè)回答說(shuō):

The compiler doesn't know what Self is when it compiles f in the protocol extension and I think it assumes it must be the exact type of the class it is applying it too. With NSData, that might not be the case because you might have a subclass of it.

很有道理授账,Swift 作為一個(gè)靜態(tài)語(yǔ)言枯跑,自然應(yīng)該在編譯的時(shí)候做出更多限制。

然后今天在看 The Swift Programming Language (Swift 3) 的時(shí)候白热,注意到了一個(gè)以前沒(méi)有用過(guò)于是忘記了的 protocol 特性:

Initializer Requirements
Protocols can require specific initializers to be implemented by conforming types. You write these initializers as part of the protocol’s definition in exactly the same way as for normal initializers, but without curly braces or an initializer body:

protocol SomeProtocol {
    init(someParameter: Int)
}

返回一個(gè) Self 敛助,不就相當(dāng)于初始化?
于是我將 protocol 改成了這樣屋确。注意這是一個(gè)可以失敗的初始化器:

protocol FromDataCreatable {
    init?(data: NSData) throws
}

接下來(lái)讓 Dictionary 實(shí)現(xiàn)這個(gè)協(xié)議:

extension Dictionary: FromDataCreatable {
    init?(data: NSData) throws {
        if let json = try NSJSONSerialization.JSONObjectWithData(
            data, options: []) as? Dictionary {
            self = json
        }
        return nil
    }
}

非常簡(jiǎn)單吧纳击?
還不只是這樣,讓別的類(lèi)型實(shí)現(xiàn)這個(gè)也是非常容易的攻臀,UIImage焕数、NSData 甚至都不需要實(shí)現(xiàn),直接 adopt 就可以了:

extension UIImage: FromDataCreatable { }

extension NSData: FromDataCreatable { }

解決了問(wèn)題之后刨啸,這是我在 StackOverFlow 上的回答:

StackOverFlow

希望能夠有所幫助吧堡赔。

接下來(lái)簡(jiǎn)單說(shuō)一下我定義這個(gè)是用來(lái)做什么吧。
一般 handler 都是handle response设联,這里為了簡(jiǎn)單表示就省去這一步:
我在NetConnectable協(xié)議中寫(xiě)了一個(gè)默認(rèn)實(shí)現(xiàn)的方法:

public func request<T: FromDataCreatable>(
    action: Action,
    params: [String : AnyObject]?,
    handler: T -> Void ) {
    let manager = Manager(
        url: action.rawValue,
        params: params)
    manager.startRequest(handler)
}

這樣一來(lái)善已,在任何 adopt 了NetConnectable協(xié)議的類(lèi)中,都能夠這么寫(xiě):

self.request(Action.getPhoto, params: [userId : 2]) {
    doSomeThingWithImage($0)
}

func doSomeThingWithImage(image: UIImage) {
    //使用圖片做一些什么
}

又或者:

self.request(Action.getUser, params: [userId : 2]) {
    doSomeThingWithJSON($0)
}

func doSomeThingWithJSON(json: [String : AnyObject]) {
    //使用json做一些什么
}

而且都只是用的這一個(gè)泛型函數(shù)离例,編譯器會(huì)幫你判斷類(lèi)型换团。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市粘招,隨后出現(xiàn)的幾起案子啥寇,更是在濱河造成了極大的恐慌,老刑警劉巖洒扎,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辑甜,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡袍冷,警方通過(guò)查閱死者的電腦和手機(jī)磷醋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)胡诗,“玉大人邓线,你說(shuō)我怎么就攤上這事淌友。” “怎么了骇陈?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵震庭,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我你雌,道長(zhǎng)器联,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任婿崭,我火速辦了婚禮拨拓,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘氓栈。我一直安慰自己渣磷,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布授瘦。 她就那樣靜靜地躺著醋界,像睡著了一般。 火紅的嫁衣襯著肌膚如雪奥务。 梳的紋絲不亂的頭發(fā)上物独,一...
    開(kāi)封第一講書(shū)人閱讀 51,679評(píng)論 1 305
  • 那天袜硫,我揣著相機(jī)與錄音氯葬,去河邊找鬼。 笑死婉陷,一個(gè)胖子當(dāng)著我的面吹牛帚称,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播秽澳,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼闯睹,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了担神?” 一聲冷哼從身側(cè)響起楼吃,我...
    開(kāi)封第一講書(shū)人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎妄讯,沒(méi)想到半個(gè)月后孩锡,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡亥贸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年躬窜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片炕置。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡荣挨,死狀恐怖男韧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情默垄,我是刑警寧澤此虑,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站口锭,受9級(jí)特大地震影響寡壮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜讹弯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一况既、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧组民,春花似錦棒仍、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至耸三,卻和暖如春乱陡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背仪壮。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工憨颠, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人积锅。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓爽彤,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親缚陷。 傳聞我的和親對(duì)象是個(gè)殘疾皇子适篙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容