一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

您好,歡迎來(lái)電子發(fā)燒友網(wǎng)! ,新用戶?[免費(fèi)注冊(cè)]

您的位置:電子發(fā)燒友網(wǎng)>源碼下載>數(shù)值算法/人工智能>

如何使用協(xié)議的實(shí)現(xiàn) MVVM 架構(gòu)

大?。?/span>0.4 MB 人氣: 2017-10-11 需要積分:1

  在 Swift 中用值類型來(lái)替代引用類型,比以前在 Objective-C 中要容易許多,這可以讓您的代碼更簡(jiǎn)潔,并且更不容易出錯(cuò)。然而,當(dāng)需要在多個(gè)類型當(dāng)中共享代碼的時(shí)候,許多人往往會(huì)回避使用值類型,而轉(zhuǎn)為使用繼承來(lái)實(shí)現(xiàn)。

  通過(guò) Natasha 在 do{iOS} 2015上對(duì) MVVM 的介紹,您可以學(xué)習(xí)到如何使用協(xié)議來(lái)實(shí)現(xiàn)這個(gè)功能,而不再采用繼承的方式!Natasha The Robot 將會(huì)引導(dǎo)您跟隨她學(xué)習(xí)和使用面向協(xié)議編程的過(guò)程,使用 Swift 2.0 的特性來(lái)創(chuàng)建漂亮、穩(wěn)定的代碼。

  About the Speaker: Natasha Murashev

  Natasha 喜歡學(xué)習(xí) Swift 和 iOS 開(kāi)發(fā),她暗喻自己是一名“機(jī)器人”。此前,她曾經(jīng)在位于舊金山 Capital One 公司工作,任職 iOS 資深工程師,但是如今她正四處旅行,撰寫(xiě)她學(xué)習(xí)新技術(shù)的心得體會(huì)。在她空余的時(shí)候,她會(huì)將時(shí)間花在她的個(gè)人項(xiàng)目、在聚會(huì)沙龍和大會(huì)上進(jìn)行演講、向開(kāi)源項(xiàng)目貢獻(xiàn)代碼,以及實(shí)現(xiàn)她愿望清單上列出的各項(xiàng)事宜。

  為什么要簡(jiǎn)化 Swift 中的代碼呢? (0:00)

  嗨,我是 Natasha。就是 Twitter 上的 @NatashaTheRobot。關(guān)于我的個(gè)人介紹的話我還想多說(shuō)一些:我有一個(gè) 每日 Swift 周報(bào),還有一個(gè)寫(xiě)了許多關(guān)于 Swift 文章的博客,自 Swift 第一天推出以來(lái),我就已經(jīng)在大量地研究 Swift 了。

  作為一名 Objective-C 開(kāi)發(fā)者,我基本上是在 Swift 剛剛推出的時(shí)候開(kāi)始學(xué)習(xí) Objective-C 代碼的——這導(dǎo)致我使用了很多的引用類型。我習(xí)慣性將所有東西聲明為類,因?yàn)槲乙呀?jīng)習(xí)慣了面向?qū)ο缶幊?。這也正是 Objective-C 的思想。

  我覺(jué)得我自己的編程習(xí)慣還是很不錯(cuò)的了,因?yàn)槲矣行r(shí)候還是會(huì)使用枚舉的。它們比普通的枚舉要復(fù)雜得多,這讓我覺(jué)得很不錯(cuò)。然而,當(dāng)我開(kāi)始參加各種活動(dòng)然后聽(tīng)取演講之后,尤其是 Andy Matuschak關(guān)于控制 Swift 代碼復(fù)雜度的演講之后,我就豁然開(kāi)朗了。他提到要使用值類型。直到這個(gè)時(shí)候,我才知道 Swift 當(dāng)中有結(jié)構(gòu)體,但是作為一名從 Objective-C 轉(zhuǎn)向 Swift 的開(kāi)發(fā)者,對(duì)我來(lái)說(shuō)以類來(lái)起步是很自然的一件事情。

  這次演講給我留下了很深的印象,我覺(jué)得應(yīng)該要盡可能將所有東西都應(yīng)用上值類型。事實(shí)上,他發(fā)現(xiàn)絕大多數(shù) Swift 標(biāo)準(zhǔn)庫(kù)中的東西都是使用的值類型,并且語(yǔ)言的創(chuàng)造者本身也在使用值類型。我回到我的工作項(xiàng)目當(dāng)中,然后創(chuàng)建了一個(gè)新文件,準(zhǔn)備從此開(kāi)始實(shí)驗(yàn)值類型的強(qiáng)大之處。

  最初,我有這樣一個(gè)感覺(jué):“我是一名 Swift 開(kāi)發(fā)者了!我在使用結(jié)構(gòu)體了!”,但是后來(lái)有些需求不得不讓我轉(zhuǎn)而使用繼承,這感覺(jué)非常糟糕,但是我不知道該如何解決這個(gè)問(wèn)題,直到……

  面向協(xié)議編程 (2:28)

  在今年的 WWDC 上,有一個(gè)難以置信的演講,講述了在 Swift 中進(jìn)行面向協(xié)議編程。在這里,他們解釋了如何用協(xié)議來(lái)替代繼承。如果您沒(méi)有看過(guò)這個(gè)演講并且打算轉(zhuǎn)向 Swift 進(jìn)行開(kāi)發(fā)的話,那么我覺(jué)得這是自去年的 WWDC 以來(lái),最為重要的一個(gè)演講了。

  在這個(gè)演講中, Apple Swift 標(biāo)準(zhǔn)庫(kù)的技術(shù)總監(jiān) Dave Abrahams提到了:

  “Swift 是一門(mén)面向協(xié)議的編程語(yǔ)言?!?/p>

  在視頻當(dāng)中,他演講的標(biāo)題是“醍醐灌頂?shù)闹v解 (Professor of Blowing Your Mind)”,他成功做到了這一點(diǎn),我以及每一名觀眾都能感受到這一點(diǎn)。

  這對(duì)我們來(lái)說(shuō)并不是一個(gè)全新的概念:我們已經(jīng)見(jiàn)識(shí)過(guò) Apple 使用了大量的協(xié)議,比如說(shuō) TableView 當(dāng)中,我們都覺(jué)得這是一個(gè)很棒的設(shè)計(jì)模式,因?yàn)闆](méi)有人希望每時(shí)每刻都要繼承 UITableViewController。相反,您可以使用協(xié)議來(lái)告訴 Apple 您需要多少個(gè)表視圖單元格。我們已經(jīng)知曉了這種設(shè)計(jì)模式的魅力所在,而現(xiàn)在我們需要把它帶到一個(gè)全新的高度。

  對(duì)于我來(lái)說(shuō),我對(duì)此非常興奮。我已經(jīng)迫不及待回到電腦面前,更詳細(xì)地研究這個(gè)設(shè)計(jì)模式,成為一名“面向協(xié)議的程序員”。我隨后帶著興奮回去處理我的那些工作。在我的工作當(dāng)中,我已經(jīng)有了一個(gè)正在使用的代碼庫(kù),它當(dāng)中帶有了已經(jīng)確定并建立的模式。這很難向其中加入新的東西,也很難理解應(yīng)該如何使用它。我想要使用面向協(xié)議編程,但是我覺(jué)得我已經(jīng)受限于我的既有項(xiàng)目了,我不知道該如何才能更進(jìn)一步。

  MVVM - 將事情留到第二天再考慮 (5:00)

  我的腦海里一直在思考著關(guān)于協(xié)議的相關(guān)內(nèi)容,我在想“我該怎么將協(xié)議整合到我的代碼當(dāng)中呢?”這件事情一直停留在我的腦海里,揮之不去,但是我不知道該如何做到這一點(diǎn)。然后,我就去睡了一覺(jué)。我非常強(qiáng)烈推崇這種做法,盡管對(duì)于程序員來(lái)說(shuō),他們的聲譽(yù)往往在于“不達(dá)目的不罷休”。對(duì)于我來(lái)說(shuō),睡一覺(jué)可以幫助我解決很多問(wèn)題,很可能是因?yàn)槲覀兊拇竽X在睡眠的時(shí)候可以更好地處理信息。

  睡了一覺(jué)之后,我醒來(lái)發(fā)現(xiàn)所有的東西都迎刃而解了。我想我至少能夠在我的工作代碼中應(yīng)用一個(gè)用例,這讓我十分興奮。這個(gè)用例就是使用 MVVM。

  對(duì)那些不熟悉 MVVM 的人來(lái)說(shuō),您可以去閱讀 Ash Furrow 的這篇博文:Swift 中的 MVVM。同樣在 objc.io上還有一篇叫做 “MVVM 介紹” 的文章。我會(huì)使用一個(gè)簡(jiǎn)單的例子來(lái)介紹,所以希望大家能夠看到 MVVM 是如何工作的。

  我曾經(jīng)在一家銀行工作。比如說(shuō)您有一個(gè)模型,里面包含了關(guān)于賬戶余額的一些原始數(shù)據(jù)。在模型層當(dāng)中,您想要保留這個(gè)值,作為原始的 NSDecimalNumber。

  letamount = 6729383.99

  當(dāng)您向用戶展示相同數(shù)字的時(shí)候,您可能想要轉(zhuǎn)換其顯示樣式,例如說(shuō):“您的賬戶余額為……”,然后在您的視圖當(dāng)中添加 “$” 標(biāo)識(shí),并且進(jìn)行格式化:

  Your balance is $6,729,383.99

  許多人喜歡將這種代碼放到視圖控制器當(dāng)中。這往往會(huì)導(dǎo)致視圖控制器變得臃腫不堪,從而難以測(cè)試。此外,您還可能將這種代碼放到模型當(dāng)中,從而讓模型也變得非常難看,因?yàn)橛性S多進(jìn)行格式化的代碼擠在其中。

  相反,您可以讓模型變得清晰,然后僅僅只用于映射您的原始數(shù)據(jù)。這是您視圖模型的初始狀態(tài):

  structAccountViewModel { letdisplayBalance: String init(mode: BankAccount) { letformattedBalance = model.balance.currencyValue displayBalance = “Your balance is\(formattedBalance)” } }

  您的視圖模型實(shí)際上會(huì)讀取您的數(shù)據(jù)模型,然后將其中的信息進(jìn)行格式化,從而準(zhǔn)備展示到視圖當(dāng)中。這就是視圖模型的魅力所在。這很容易進(jìn)行測(cè)試。您可以將帶有賬戶信息的模型放進(jìn)去,然后測(cè)試顯示就可以了,而在此之前,如果您想要測(cè)試您的視圖控制器或者視圖,這是非常非常難的,因?yàn)檩敵鎏貏e紛繁復(fù)雜。

  Zoetrope 模型 (8:29)

  注意到我的視圖模型是值類型的。那么這個(gè)在 Swift 中是如何起作用的呢?

  關(guān)鍵在于,您的視圖控制器需要維持視圖模型的最新版本。值類型是一種數(shù)據(jù)類型。它不應(yīng)該成為真實(shí)的數(shù)據(jù),它只是數(shù)據(jù)在某個(gè)時(shí)間點(diǎn)的一份拷貝而已。您的視圖控制器需要跟蹤這些信息,決定哪個(gè)拷貝數(shù)據(jù)應(yīng)該展示給用戶(也就是最新的拷貝)。

  順便想想,在 Andy Matuschak 的演講中,那個(gè)關(guān)于 zoetrope 的例子。(在日本的 Ghibli 博物館中有這樣一個(gè)很神奇的西洋鏡)。

  這里的關(guān)鍵在于,zoetrope 的每一個(gè)幀都是靜態(tài)值。您可以通過(guò)改變?nèi)宋锸植刻鸬木嚯x,或者人物頭部?jī)A斜的角度,來(lái)對(duì)字符進(jìn)行編碼。每一幀都是靜態(tài)的,但是當(dāng)您把它們放到一起,然后一直看向一個(gè)中心的話,那么始終都會(huì)有新的數(shù)據(jù)出現(xiàn),這樣您就可以得到一個(gè)美麗、生動(dòng)的動(dòng)畫(huà)。

  您可以用相同的方式來(lái)實(shí)現(xiàn)值類型。您的視圖控制器將會(huì)跟蹤 zoetrope 的最后一個(gè)幀圖像——也就是最新的一塊活躍數(shù)據(jù),然后將其展示給用戶。只要您的模型發(fā)生了更新,也就是有了新的數(shù)據(jù),這樣您就可以通過(guò)計(jì)算得到一個(gè)新的視圖模型?,F(xiàn)在,您的視圖就會(huì)根據(jù)最新的信息進(jìn)行更新了。

  var viewModel =ViewModel(model: Account)

  沒(méi)有協(xié)議之前的丑陋 (9:57)

  現(xiàn)在,我們已經(jīng)得到了令人興奮的部分了。我現(xiàn)在將會(huì)運(yùn)行一個(gè)非常簡(jiǎn)單的例子。在這個(gè)表視圖當(dāng)中,比如說(shuō)絕大多數(shù)應(yīng)用都會(huì)有的設(shè)置屏幕,試想我只有一個(gè)設(shè)置:用一個(gè)滑塊 (slider) 來(lái)將整個(gè)應(yīng)用主色調(diào)變?yōu)辄S色。

  這個(gè)操作應(yīng)該是非常簡(jiǎn)單的,但是它也會(huì)變得很復(fù)雜。這里有一個(gè)問(wèn)題:在我們的表視圖單元格當(dāng)中,其中的每一個(gè)單獨(dú)組件都需要以某種方式來(lái)進(jìn)行格式化。如果其中有標(biāo)簽 (label) 的話,那么您必須要定義它的字體,字體顏色,字體大小,等等。如果是開(kāi)關(guān) (switch) 的話,那么當(dāng)開(kāi)關(guān)打開(kāi)的時(shí)候會(huì)發(fā)生些什么?初始狀態(tài)是關(guān)閉還是打開(kāi)?對(duì)于這種擁有這兩個(gè)元素的簡(jiǎn)單的表視圖單元格來(lái)說(shuō),我已經(jīng)有 6 種不同的方式來(lái)對(duì)它進(jìn)行配置:

  classSwitchWithTextTableViewCell: UITableViewCell{ func configure( title: String, titleFont: UIFont, titleColor: UIColor, switchOn: Bool, switchColor: UIColor= .purpleColor(), onSwitchToggleHandler: onSwitchTogglerHandlerType? = nil) { // 在這里配置視圖 } }

  您可以想象得到,我們絕大多數(shù)人進(jìn)行配置的表視圖單元格比著遠(yuǎn)復(fù)雜得多。在我的代碼當(dāng)中,這種 configure 方法將非常非常累贅。添加一個(gè)副標(biāo)題將會(huì)導(dǎo)致多出額外的三個(gè)屬性需要設(shè)置。在 Swift 中您可以用默認(rèn)值來(lái)獲得一些輔助,但是使用這種臃腫的 configure 方法不是非常簡(jiǎn)潔。

  在您實(shí)際上調(diào)用此方法的視圖控制器當(dāng)中,我們持有了所有存放在其中的信息棧。它看起來(lái)并不是很好看;這讓人感覺(jué)很不好,但是我一直沒(méi)想到有更好的辦法,直到協(xié)議的出現(xiàn)。

  視圖模型及協(xié)議 (12:05)

  對(duì)于單元格來(lái)說(shuō),我們不應(yīng)該使用這些臃腫的配置方法,而是應(yīng)該將每個(gè)部分單獨(dú)拿出來(lái),然后將其放大一個(gè) SwiftchWithTextCellProtocol 的協(xié)議當(dāng)中。這讓我感覺(jué)到非常開(kāi)心。這樣子,我就可以讓我的視圖模型實(shí)現(xiàn)這個(gè)協(xié)議,然后在這里設(shè)置所有的屬性?,F(xiàn)在,我就不用再去使用臃腫的配置方法了,但是我仍然需要有一種方式來(lái)確保每個(gè)單獨(dú)的屬性實(shí)際上都被設(shè)置了。

  protocol SwitchWithTextCellProtocol { vartitle: String { get} vartitleFont: UIFont { get} vartitleColor: UIColor { get} varswitchOn: Bool { get} varswitchColor: UIColor { get} func onSwitchToggleOn(on: Bool) }

  通過(guò) Swift 2.0 當(dāng)中的協(xié)議擴(kuò)展,我就可以通過(guò)默認(rèn)值做一些處理了。如果對(duì)于大多數(shù)單元格來(lái)說(shuō),可以確定某一種顏色的話,那么您就可以對(duì)其建立擴(kuò)展,然后設(shè)置該顏色即可。所有的實(shí)現(xiàn)此協(xié)議的視圖模型都沒(méi)必要再去設(shè)置這個(gè)顏色了。這個(gè)做法非常棒:

  extension SwitchWithTextCellProtocol { varswitchColor: UIColor { return.purpleColor() } }

  現(xiàn)在,我的 configure 方法只需要獲取某個(gè)實(shí)現(xiàn)此協(xié)議的值就可以了:

  classSwitchWithTextTableViewCell: UITableViewCell{func configure(withDelegate delegate:SwitchWithTextCellProtocol) { //在這里配置方法 } }

  這個(gè)方法只有一個(gè)參數(shù),這對(duì)之前的那個(gè)六個(gè)參數(shù)(甚至更多)的方法來(lái)說(shuō)是一個(gè)重大的改進(jìn)。這是我現(xiàn)在的視圖模型的一個(gè)示例:

  structMinionModeViewModel: SwitchWithTextCellProtocol { vartitle = “Minion Mode!??!”varswitchOn = truevarswitchColor: UIColor { return.yellowColor() } funconSwitchToggleOn(on: Bool) { ifon { print(“The Minions are here to stay!”) } else{ print(“The Minions went out to play!”) } } }

  它實(shí)現(xiàn)了這個(gè)協(xié)議,然后配置了所有相關(guān)的信息。正如您在前面的示例中看到的那樣,您可以用您的模型對(duì)象來(lái)初始化視圖模型了。現(xiàn)在,如果您需要諸如外匯收益之類的信息的話,您實(shí)際上可以在您視圖模型的各個(gè)地方使用這個(gè)信息,以便能夠指明如何對(duì)其進(jìn)行配置,并將視圖展示出來(lái)。

  因此,這個(gè)操作將會(huì)非常簡(jiǎn)單?,F(xiàn)在,我的 cellForRowAtIndexPath() 也變得非常的簡(jiǎn)明了:

  // YourViewController.swiftletcell = tableView.dequeueReusableCellWithIdentifier(“SwitchWithTextTableViewCell”, forIndexPath: indexPath) as! SwitchWithTextTableViewCell // This is where the magic happens!cell.configure(withDelegate: MinionModeViewModel()) returncell

  我將單元格 dequeue 出來(lái),然后調(diào)用了我視圖模型的 configure 方法。在這個(gè)例子當(dāng)中,我沒(méi)有對(duì)它的 frame 進(jìn)行任何的配置,它同樣也沒(méi)有包含模型層,但是您同樣可以將這個(gè)模型放到視圖控制器層級(jí),以便對(duì)其進(jìn)行跟蹤。您同樣可以在視圖模型當(dāng)中傳遞這些信息,這樣您的單元格就可以生成了。當(dāng)我們重構(gòu)之后,我們只需要三行代碼就可以完成配置了。

  進(jìn)一步的抽象 (14:10)

  這個(gè)時(shí)候,我為自己的做法感到非常開(kāi)心。因?yàn)槲野堰@個(gè)臃腫的帶有六個(gè)參數(shù)的 configure 方法,用協(xié)議的方式將其進(jìn)行了重構(gòu)。我發(fā)現(xiàn)使用協(xié)議能夠讓我的代碼更優(yōu)美、更簡(jiǎn)潔,邏輯更清晰。

  通常情況下,我的下一步動(dòng)作就是通過(guò)博客把它發(fā)表出來(lái)。我喜歡為了總結(jié)學(xué)習(xí)經(jīng)驗(yàn)而寫(xiě)博客,因此無(wú)論我是學(xué)到了什么還是發(fā)現(xiàn)了什么,我都會(huì)在博客中把它寫(xiě)出來(lái)。我的博客上已經(jīng)講述了這一點(diǎn),有人發(fā)帖評(píng)論說(shuō):“有沒(méi)有考慮創(chuàng)建兩個(gè)協(xié)議呢?一個(gè)作為實(shí)際編碼信息的數(shù)據(jù)源,就比如說(shuō)單元格的標(biāo)題之類的東西,也就是實(shí)際的數(shù)據(jù)。”和顏色、字體之類的信息不同,它們應(yīng)該是相互獨(dú)立的,因?yàn)樽煮w之類的信息更多是關(guān)于格式化方面的,而其中并沒(méi)有包含實(shí)際的數(shù)據(jù),并且這種模式我們已經(jīng)可以看到 Apple 用過(guò)了,比如說(shuō)在 UITableViewCells 或者集合視圖之類的地方。

  我認(rèn)為這是一個(gè)非常絕妙的想法。我將我的邏輯進(jìn)行了分離,然后再創(chuàng)建了單元格數(shù)據(jù)存儲(chǔ)和單元格委托:

  protocol SwitchWithTextCellDataSource { vartitle: String { get} varswitchOn: Bool { get} } protocol SwitchWithTextCellDelegate { func onSwitchToggleOn(on: Bool) varswitchColor: UIColor { get} vartextColor: UIColor { get} varfont: UIFont { get} }

  接下來(lái),我讓我的 configure 方法同時(shí)接收這兩個(gè)協(xié)議。因?yàn)槲锌梢匀吭趨f(xié)議擴(kuò)展中使用默認(rèn)值進(jìn)行配置,比如說(shuō)字體、顏色之類的信息,這樣在理論上我可以不用向里面?zhèn)鬟f任何東西進(jìn)去;我可以只用創(chuàng)建一個(gè)模型就可以了:

  // SwitchWithTextTableViewCellfunc configure(withDataSource dataSource: SwitchWithTextCellDataSource, delegate: SwitchWithTextCellDelegate?) { // 在這里配置視圖}

  現(xiàn)在我可以使用擴(kuò)展來(lái)改進(jìn)我的視圖模型了。我會(huì)使用一個(gè)實(shí)現(xiàn)數(shù)據(jù)源的代碼塊,然后給定要傳遞給視圖當(dāng)中的原始信息:

  structMinionModeViewModel: SwitchWithTextCellDataSource { vartitle = “Minion Mode?。?!”varswitchOn = true}

  接下來(lái),我會(huì)在一個(gè)單獨(dú)的視圖模型的部分當(dāng)中使用處理字體、顏色之類的委托,然后在其中進(jìn)行相關(guān)的配置。

  extension MinionModeViewModel: SwitchWithTextCellDelegate { var switchColor: UIColor { return.yellowColor() } func onSwitchToggleOn(on: Bool) {ifon{print(“The Minions are here to stay!”) } else{ print(“The Minions went out to play!”) } } }

  最終,我的表視圖單元格變得非常簡(jiǎn)單:

  // SettingsViewControllerletviewModel = MinionModeViewModel() cell.configure(withDataSource: viewModel, delegate: viewModel) returncell

  我僅僅只用創(chuàng)建了我的視圖模型,然后將其傳遞到配置方法當(dāng)中,然后返回單元格,就完畢了。

  Swift 2.0 中的 Mixin 和 Trait (16:32)

  我對(duì)這一點(diǎn)還是比較滿意的。我創(chuàng)建了協(xié)議,簡(jiǎn)化了我的代碼,然后發(fā)表了相關(guān)的博客,學(xué)習(xí)到了相關(guān)的知識(shí)。接著,我又讀到了一個(gè)非常贊的文章,我覺(jué)得大家都應(yīng)該去讀一讀:@mhollemans 寫(xiě)的 Swift 2.0 中的 Mixin 和 Trait。Matthijs 講述的是游戲開(kāi)發(fā),雖然我對(duì)此并不是很熟悉,但是我們?nèi)匀豢梢匀ダ斫馑岬降幕靖拍睢?/p>

  在游戲開(kāi)發(fā)當(dāng)中,通常會(huì)有著一個(gè)很龐大的層級(jí)關(guān)系,以及一系列的繼承。比如說(shuō)“怪物”類型當(dāng)中,可能會(huì)有各種各樣的“怪物”。繼承在這里變得十分有意義。但是,隨著層級(jí)的擴(kuò)展,事情變得開(kāi)始凌亂起來(lái)。

  如何使用協(xié)議的實(shí)現(xiàn) MVVM 架構(gòu)

  對(duì)于這種類型的層次結(jié)構(gòu)來(lái)說(shuō),剛開(kāi)始的時(shí)候還好。不過(guò)隨著后面的發(fā)展,當(dāng)您遇到要設(shè)計(jì)一個(gè)也能夠射擊的怪物的時(shí)候,事情就變得麻煩起來(lái)了,因?yàn)槌潜ね瑯右部梢陨鋼?,因?yàn)樵诔潜さ捻敹藫碛写笈?,因此您現(xiàn)在就必須要將這個(gè)“射擊輔助類”提取出來(lái)。當(dāng)您正在創(chuàng)建這些子類的時(shí)候,您會(huì)覺(jué)得這種做法是非常非常奇異的,但是這很快會(huì)變得越來(lái)越混亂,最終您將會(huì)寫(xiě)出一團(tuán)亂麻般的代碼。

  Matthijs 重構(gòu)了這個(gè)代碼,這樣我們不再使用這些繼承對(duì)象的邏輯,比如說(shuō)控制能夠射擊或者控制能夠治療的子類,而是將其提取成為協(xié)議,通過(guò)協(xié)議擴(kuò)展來(lái)實(shí)現(xiàn)這個(gè)功能。

  這使得代碼看起來(lái)更加簡(jiǎn)潔,更容易理解。例如:

  class ZapMonster: GameObject, GunTrait, RenderTrait, HealthTrait, MovementTrait { 。。.}

  只需要看一看這個(gè)對(duì)象的類型,我就可以立刻理解這個(gè)對(duì)象擁有哪些功能,而不是去一個(gè)一個(gè)查看它的實(shí)現(xiàn)。我個(gè)人更加喜歡這樣的設(shè)計(jì)模式。

  在我們的應(yīng)用中應(yīng)用 Mixin (19:47)

  雖然剛剛的例子是關(guān)于游戲開(kāi)發(fā)的,但是我希望我也能夠在我自己的代碼中對(duì)表視圖單元格應(yīng)用上這個(gè)功能。這樣就不用讓我實(shí)際的單元格實(shí)現(xiàn)這個(gè)協(xié)議了,我只需要將其與更寬泛的 TextPresentable 聯(lián)系在一起就可以了。這樣,任何擁有標(biāo)簽的視圖,而不僅僅只是單元格,都可以實(shí)現(xiàn)這個(gè)協(xié)議來(lái)完成相關(guān)的功能。這樣我就可以說(shuō)這個(gè)標(biāo)簽當(dāng)中有什么樣的文本,什么樣的顏色,以及什么樣的字體:

  protocol TextPresentable { vartext: String { get} vartextColor: UIColor { get} varfont: UIFont { get} } protocol SwitchPresentable { varswitchOn: Bool { get} varswitchColor: UIColor { get} func onSwitchToggleOn(on: Bool) }

  Switch 擁有自己獨(dú)有的協(xié)議,這樣就可以知道它應(yīng)該如何配置了。您可以想象這個(gè)從游戲開(kāi)發(fā)示例當(dāng)中得來(lái)的靈感:現(xiàn)在您需要一個(gè)圖像了,你只需要實(shí)現(xiàn) ImagePresentable 協(xié)議就可以了;現(xiàn)在您需要一個(gè)文本框了,只需要實(shí)現(xiàn) TextFieldPresentable 協(xié)議就可以了:

  protocol ImagePresentable { varimageName: String { get} } protocol TextFieldPresentable { varplaceholder: String { get} vartext: String { get} func onTextFieldDidEndEditing(textField: UITextField) }

  通過(guò)協(xié)議擴(kuò)展,您可以配置所有的字體和顏色,因此每一個(gè)單獨(dú)實(shí)現(xiàn)這個(gè) TextPresentable 協(xié)議的視圖都會(huì)擁有這個(gè)標(biāo)簽的默認(rèn)配置,因?yàn)橥ǔG闆r下,您應(yīng)用中的標(biāo)簽基本上都是非常相似的:

  extension TextPresentable { vartextColor: UIColor { return.blackColor() } varfont: UIFont { return.systemFontOfSize(17) } }

  您甚至可以更進(jìn)一步,創(chuàng)建不同類型的標(biāo)簽,比如說(shuō)標(biāo)題標(biāo)簽?;蛟S它擁有確定的字體或者顏色,這就意味著您可以一遍又一遍地在您的應(yīng)用程序中重用這個(gè)標(biāo)簽。這樣當(dāng)您的設(shè)計(jì)師要求將所有的標(biāo)題顏色變成藍(lán)色的時(shí)候,這種做法將會(huì)非常快速。您可以前往協(xié)議擴(kuò)展當(dāng)中,將其改變?yōu)樗{(lán)色,然后通過(guò)這一行代碼的變化,每一個(gè)擁有這個(gè) HeaderTextPresentable 協(xié)議的視圖中的標(biāo)簽都會(huì)立刻改變。

  我十分喜歡這個(gè)設(shè)計(jì)模式。這是我現(xiàn)在單元格的模樣:

  class SwitchWithTextTableViewCell《T whereT: TextPresentable, T: SwitchPresentable》: UITableViewCell { privatevardelegate: T? func configure(withDelegate delegate: T) { // 在這里配置視圖} }

  在這種情況下,它沒(méi)有實(shí)現(xiàn)這些協(xié)議,但是它會(huì)期待某種實(shí)現(xiàn)這些協(xié)議的東西傳遞進(jìn)去,因此我們使用了泛型。這個(gè)單元格期待一個(gè)實(shí)現(xiàn)了 TextPresentableProtocol 以及 SwitchPresentableProtocol 的委托。這個(gè)配置方法并不關(guān)心傳遞進(jìn)去的對(duì)象。就我們而言,傳遞進(jìn)去的將是一個(gè)視圖模型,但是它所想要的只要是實(shí)現(xiàn)了這些協(xié)議的東西就可以了,現(xiàn)在,您就可以基于這些信息在單元格當(dāng)中配置所有東西了。

  extension MinionModeViewModel: TextPresentable { vartext: String{ return“Minion Mode”} vartextColor: UIColor { return.blackColor() } varfont: UIFont { return.systemFontOfSize(17.0) } }

  我們的視圖模型將擁有一個(gè) TextPresentable 代碼塊,在其中您可以配置文本、顏色、字體,并且由于所有這些在協(xié)議擴(kuò)展當(dāng)中都已經(jīng)有默認(rèn)值了,您甚至都不用讓視圖模型去實(shí)現(xiàn)這些具體的內(nèi)容。

  對(duì)于 SwitchPresentable 也是一樣的。這個(gè)開(kāi)關(guān)應(yīng)該開(kāi)啟還是關(guān)閉?當(dāng)開(kāi)關(guān)開(kāi)啟的時(shí)候應(yīng)該發(fā)生些什么?這里,您可以看到這個(gè)視圖的一小部分:

  extension MinionModeViewModel: SwitchPresentable { varswitchOn: Bool { returnfalse} varswitchColor: UIColor { return.yellowColor() } func onSwitchToggleOn(on: Bool) { ifon { print(“The Minions are here to stay!”) } else{ print(“The Minions went out to play!”) } } }

  最后,視圖控制器當(dāng)中的代碼就變得十分簡(jiǎn)單:您只需要 dequeue 相應(yīng)的單元格。然后通過(guò)視圖模型對(duì)其進(jìn)行配置,然后返回單元格即可。其中一個(gè)關(guān)鍵的地方是,因?yàn)槲覀兪褂玫氖欠盒停虼宋覀儽仨氁该?T 是什么東西,在我們的例子當(dāng)中,T 是視圖模型。

  Swift: 一個(gè)正在發(fā)展的語(yǔ)言 (24:02)

  在這一點(diǎn)上我是非常興奮的。我已經(jīng)經(jīng)歷了三種不同的迭代版本了。然而,Swift 仍然是一門(mén)新語(yǔ)言,它只出現(xiàn)了不到兩年的時(shí)間。在這個(gè)過(guò)程中它變化了很多,我們作為一個(gè)社區(qū)必須要決定 Swift 的最佳用例是什么。

  我一直在想一件事情,當(dāng)我在我的代碼中發(fā)現(xiàn)或者是提出某個(gè)新的設(shè)計(jì)模式的時(shí)候,該如何才能夠輕松地進(jìn)行遷移。這使得我切實(shí)相信:

  世上唯一不變的事就是變化本身。

  這句話特別適用于編程界。我通常會(huì)花費(fèi)一個(gè)季度的時(shí)間來(lái)重寫(xiě)我的每個(gè)應(yīng)用,因?yàn)樽罱K您可能會(huì)需要改變很多東西;您需要添加單元測(cè)試,或者需要為了 iOS 7 重新設(shè)計(jì)。Apple 有時(shí)候會(huì)推出新的東西,因此您可能需要?jiǎng)h除或者添加新的功能;任何東西都在不斷的變化。

  因此,我總是在認(rèn)定我的代碼即將被改變的這種假設(shè)下進(jìn)行工作的。對(duì)于長(zhǎng)期的產(chǎn)品開(kāi)發(fā)來(lái)說(shuō),我必須要考慮到我正在用的這個(gè)設(shè)計(jì)模式是否允許我簡(jiǎn)單地進(jìn)行修改,而不是對(duì)一個(gè)類進(jìn)行一個(gè)細(xì)小的變化就得祈禱這個(gè)操作不會(huì)發(fā)生崩潰。對(duì)于我來(lái)說(shuō),這個(gè)設(shè)計(jì)模式是非常贊的,因?yàn)樗试S快速地進(jìn)行修改。

  假如說(shuō)我的產(chǎn)品經(jīng)理過(guò)來(lái)跟我說(shuō):“哎,對(duì)于這個(gè)單元格,我希望讓它能夠添加一個(gè)圖像”。剛開(kāi)始的時(shí)候,我們只有標(biāo)簽和開(kāi)關(guān),而現(xiàn)在只是多了一個(gè)圖像而已。因此,我會(huì)讓這個(gè)單元格期待一個(gè)還實(shí)現(xiàn)了 ImagePresentableProtocol 的東西傳遞進(jìn)去,這就是我在單元格層面所做的全部操作。

  我同樣也必須要更新我的配置方法,以便能夠讓其能夠真正使用上這個(gè)圖像,但是這只需要使用兩行代碼就可以了。最后,我只是對(duì)我的視圖模型進(jìn)行擴(kuò)展就可以了。

  extension MinionModeViewModel: ImagePresentable { varimageName: String{ return“minionParty.png”} }

  開(kāi)心的 Natasha the Robot:總結(jié) (26:26)

  這個(gè)時(shí)候我是非常開(kāi)心的。這些就是我所要討論的所有東西了,在 MVVM 架構(gòu)中使用協(xié)議。

  使用協(xié)議來(lái)配置您的視圖使用協(xié)議擴(kuò)展來(lái)實(shí)現(xiàn)默認(rèn)值——這就是您設(shè)置用在您應(yīng)用當(dāng)中的所有字體、顏色以及配置的地方。這里最大的障礙就是處理子類了;這就是人們?yōu)槭裁纯偸鞘褂美^承——因?yàn)樾枰诙鄠€(gè)類當(dāng)中使用相同的功能。使用視圖模型來(lái)為協(xié)議提供數(shù)據(jù)。您使用視圖模型的目的在于它們易于測(cè)試,并且變化帶來(lái)的耦合度很小。您的視圖控制器可以決定在最新版本的代碼當(dāng)中使用哪個(gè)版本的視圖模型。

  重點(diǎn)是我希望在明年的 WWDC 中,他們能夠提出一個(gè)適用于 Swift 的全新架構(gòu),或者有人能夠在這個(gè)演講之后在 Tweet 上給我一個(gè)更好的主意。對(duì)于那些使用 Swift 開(kāi)發(fā)的人來(lái)說(shuō),我建議大家保持一個(gè)開(kāi)放的心態(tài)。想想您該如何讓代碼變得更好。

  聽(tīng)從您的同事、社區(qū)的建議??傆锌梢愿纳拼a的方式的,并且我確信我可以借此來(lái)進(jìn)行代碼的改善。在這一點(diǎn)上,我是非常高興的,不過(guò)我下周可能會(huì)讀到某些文章,這可能會(huì)導(dǎo)致我改變主意,或者學(xué)到一些新的東西。

  關(guān)于 Swift 的一個(gè)很酷的事情是,我們都有不同的編程經(jīng)驗(yàn)。您的同事可能是函數(shù)式編程語(yǔ)言出身,也有可能是 Ruby 或者 .NET 出身——他們可能有與你不同的想法。由于 Swift 是一個(gè)不斷發(fā)展的語(yǔ)言,因此您需要虛心向別人學(xué)習(xí)。這能夠改善您的設(shè)計(jì)模式,并且能夠幫助您找到最好的設(shè)計(jì)模式。我認(rèn)為您總是可以對(duì)其進(jìn)行優(yōu)化和改進(jìn),分享您的發(fā)現(xiàn),然后周而復(fù)始。

非常好我支持^.^

(0) 0%

不好我反對(duì)

(0) 0%

如何使用協(xié)議的實(shí)現(xiàn) MVVM 架構(gòu)下載

相關(guān)電子資料下載

      發(fā)表評(píng)論

      用戶評(píng)論
      評(píng)價(jià):好評(píng)中評(píng)差評(píng)

      發(fā)表評(píng)論,獲取積分! 請(qǐng)遵守相關(guān)規(guī)定!

      ?