參考:http://www.reibang.com/p/8c6c009bc500
http://blog.csdn.net/kmyhy/article/details/70243065
第一步挽拔、配置環(huán)境(跟著github 上面配置就行了)
第二步橙喘、把項(xiàng)目從gitHub拉下來(以下都是根據(jù)這個(gè)github的內(nèi)容配置的):https://github.com/alexeyxo/protobuf-swift (使用終端操作)
以下兩個(gè)方法供使用:
$ git clone git@github.com:alexeyxo/protobuf-swift.git
$ git clone https://github.com/alexeyxo/protobuf-swift.git
第三步停团、執(zhí)行 ./scripts/build.sh 文件? (使用終端操作)
使用終端cd到protobuf-swift目錄下暇检,然后直接在終端輸入以下命令執(zhí)行(貌似這是一個(gè)腳本竹勉,反正正常執(zhí)行會(huì)生成一大坨文件)
$ ./scripts/build.sh
第四步棋弥、集成protobuf-swift ?(手動(dòng)拖進(jìn)項(xiàng)目媒咳, 或者pod管理)
1.直接拖拽進(jìn)你的工程中凶杖,然后添加編譯文件:target--> build phases? -> Link binary with libraries? (注意: 拖進(jìn)去的/ProtocolBuffers.xcodeproj文件瓦糕, 在你的工程里不會(huì)存在真實(shí)的文件夾底洗, 這里拖進(jìn)去只是一個(gè)引用)
2.然后記得 pod 一下 或者把Source文件夾拖進(jìn)工程:protobuf-swift/Source ? ?(和 使用第三方框架一樣原理)
$ pod 'ProtocolBuffers-Swift'
$ pod install
第五步、用你自己定義的 .proto 文件生成一個(gè) .swift 文件咕娄,.proto 文件使用來寫protobuf代碼的 (使用終端操作)
1.創(chuàng)建(touch)一個(gè) .proto 文件 亥揖,然后 protobuf 代碼就全部寫在這個(gè) .ptoto 文件里面
$ touch ?Test.proto
例如代碼:
syntax = "proto3";
message Test {
string sessionId = 1;
string name = 2;
string authorites = 3;
}
2.cd到你的 .proto 文件位置, 然后 使用終端 編譯成 swift文件
$ protoc? Test.proto --swift_out="./"
3. 生成的 swift文件就可以直接拖進(jìn)你的項(xiàng)目工程中了
第六步圣勒、祝你好運(yùn)费变。
對(duì)于大部分需要后臺(tái)支持的 App 來說,轉(zhuǎn)化和存儲(chǔ)數(shù)據(jù)是非常重要的工作圣贸。和 web service 交互時(shí)挚歧,程序員常常需要發(fā)送或接收 JSON/XML 數(shù)據(jù),創(chuàng)建數(shù)據(jù)結(jié)構(gòu)并傳遞它們吁峻。
盡管已經(jīng)有許多序列化/反序列化框架和 APIs滑负,但這里有一個(gè)維護(hù)性的問題,比如版本管理以及當(dāng)后臺(tái)模型改變后需要對(duì)對(duì)象解析器進(jìn)行修改用含。
如果你想創(chuàng)建全新的矮慕、健壯的后端和前端服務(wù),請(qǐng)嘗試 protocol buffers耕餐,它是一個(gè)和語言無關(guān)的序列化結(jié)構(gòu)數(shù)據(jù)的方法凡傅,由 Google 所開發(fā)。許多時(shí)候肠缔,它都要比別的常用方法比如 JSON夏跷、XML 要更靈活高效哼转。
它有一個(gè)重要的特點(diǎn),只需要定義一次數(shù)據(jù)結(jié)構(gòu)槽华,編譯器就能夠生成多種語言的代碼——包括Swift! 它所產(chǎn)生的類文件能夠毫不費(fèi)力地對(duì)對(duì)象進(jìn)行讀和諧壹蔓。
在本教程中,你將啟動(dòng)一個(gè)Python服務(wù)器猫态,并集成一個(gè)已有iOSAPP 中的數(shù)據(jù)佣蓉。然后,我們將介紹如何使用 protocol buffer亲雪,如何配置環(huán)境勇凭,如何用 protocol buffers 傳遞數(shù)據(jù)。
你是不是仍然覺得沒有必要使用 protocol buffers义辕?請(qǐng)看下面虾标。
本教程假設(shè)你具備一定的 iOS 和 Swift 基本技能,了解基本的服務(wù)端編程灌砖,知道怎么使用終端璧函。
同時(shí),確認(rèn)你使用的是最新版的 Xcode 8.2基显。
RWCards 是一個(gè) app蘸吓,允許你查看自己的門票以及活動(dòng)發(fā)言者清單。
首先下載開始項(xiàng)目,打開目錄下面的 Starter撩幽。
請(qǐng)先熟悉一下這三部分內(nèi)容:
在 Starter/RWCards 目錄库继,打開 RWCards.xcworkspace 瀏覽一下主要的項(xiàng)目文件,包括:
SpeakersListViewController.swift 負(fù)責(zé)列出發(fā)言者名單摸航。這個(gè)控制器是一個(gè)模板制跟,因?yàn)槲覀冞€沒有創(chuàng)建模型對(duì)象。
SpeakersViewModel.swift 充當(dāng) SpeakersListViewController 的數(shù)據(jù)源酱虎。它包含了發(fā)言者的列表雨膨。
CardViewController.swift 負(fù)責(zé)顯示一個(gè)出席者的圖標(biāo)以及他們的社交信息。
RWService.swift 負(fù)責(zé)集成客戶端和后臺(tái)读串。我們將使用 Alamofire 來調(diào)用后臺(tái)服務(wù)聊记。
Main.storyboard 包含了整個(gè) App 用到的所有 scene。
這個(gè)項(xiàng)目通過 CocoaPods 集成了這兩個(gè)框架:
Swift Protobuf 允許你在你的 Xcode 項(xiàng)目中使用 protocol buffers恢暖。
Almofire 是一個(gè) HTTP 網(wǎng)絡(luò)庫排监,我們用它來訪問服務(wù)器。
注意:本教程中我們將使用 Swift Protobuf 0.9.24 以及 Google 的 Protoc Compiler 3.1.0杰捂。它們都已經(jīng)內(nèi)置在開始項(xiàng)目中了舆床,因此你不需要做什么。
要使用 protocol buffers,首先必須定義一個(gè) .proto 文件挨队。在這個(gè)文件中谷暮,你需要定義一個(gè)消息類型,用于定義你的架構(gòu)或數(shù)據(jù)結(jié)構(gòu)盛垦。這是一個(gè) .proto 文件的例子:
syntax ="proto3";message Contact {? enum ContactType {? ? SPEAKER =0;? ? ATTENDANT =1;? ? VOLUNTEER =2;? }stringfirst_name =1;stringlast_name =2;stringtwitter_name =3;stringemail =4;stringgithub_link =5;? ContactTypetype=6;stringimageName =7;};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
這里指定了一個(gè) Contact 消息以及它的屬性湿弦。
定義好 .proto 文件后,你只需要將文件傳遞給 protocol buffer 編譯器腾夯,它將根據(jù)你選擇的語言生成數(shù)據(jù)訪問類(在 Swift 中是結(jié)構(gòu))颊埃。然后你就可以通過這個(gè)類/結(jié)構(gòu)了。簡(jiǎn)單吧蝶俱!
https://koenig-media.raywenderlich.com/uploads/2016/12/pb3.png’ width=’600’/>
編譯器對(duì)消息進(jìn)行翻譯班利,將它的值類型映射為指定的語言,并生成相應(yīng)的模型對(duì)象文件跷乐。后面會(huì)詳細(xì)介紹如何定義消息肥败。
在準(zhǔn)備使用 Protocol buffers 之前,你首先應(yīng)當(dāng)明白為什么要在你的項(xiàng)目中使用它愕提。
JSON 和 XML 是程序員存儲(chǔ)和數(shù)據(jù)轉(zhuǎn)換的標(biāo)準(zhǔn)方式,但 protocol buffers 具有這些優(yōu)勢(shì):
更快皿哨,更星城取:根據(jù) Google 所說,protocol buffers 比起 XML 數(shù)據(jù)量小 3-10 倍证膨,速度快 20-100 倍如输。請(qǐng)閱讀 Damien Bod 的這篇文章,其中對(duì)不同主流數(shù)據(jù)格式的讀寫時(shí)間進(jìn)行了比較央勒。
類型安全:protocol buffers 和 Swift 一樣是類型安全的不见。通過 protocol buffer 語言,你必須為每個(gè)屬性指定屬性崔步。
自動(dòng)反序列化:你不再需要編寫千篇一律的解析代碼稳吮。只需要修改你的 proto 文件,重新生成數(shù)據(jù)訪問類井濒。
面向分享:可以通過指定的語言灶似,跨平臺(tái)分享模型,這意味著進(jìn)行跨平臺(tái)時(shí)能夠減少工作瑞你。
Protocol buffers 有優(yōu)點(diǎn)酪惭,也有缺點(diǎn):
時(shí)間和工作量:將已有項(xiàng)目中切換到 protocol buffers 上時(shí),可能會(huì)增加一些成本者甲,因?yàn)檫@種轉(zhuǎn)換需要成本春感。此外,它需要學(xué)習(xí)一種新語法。
人類不可讀:XML 和 JSON 更加具有描述性鲫懒,更容易閱讀纺铭。Protocol buffer 的原始格式不是自描述的。如果沒有 .proto 文件刀疙,你根本無法看懂?dāng)?shù)據(jù)舶赔。
它不是全能的:如果我們想使用樣式表(比如 XSLT),那么最好用 XML谦秧。protocol buffers 并不適合于這種目的竟纳。
語言不支持:編譯器可能不支持你想使用的那種語言。
它并不是什么情況下都能夠使用疚鲤,因此對(duì)于 protocol buffers 仍然有很多爭(zhēng)論锥累!
編譯運(yùn)行 App,看看它是什么樣子集歇。
https://koenig-media.raywenderlich.com/uploads/2016/12/pb2-6.gif’ width=’400’/>
不幸的是桶略,你不能看到任何數(shù)據(jù),因?yàn)閿?shù)據(jù)源還沒有準(zhǔn)備好诲宇。你的任務(wù)是調(diào)用后臺(tái)服務(wù)际歼,用發(fā)言者列表和參與者角標(biāo)來刷新 UI。首先姑蓝,我們來看一下開始項(xiàng)目中提供的這兩部分鹅心。
回到 Finder,進(jìn)入 Starter/ProtoSchema 目錄纺荧,你會(huì)看到如下文件:
contact.proto 通過 protocol buffer 語法描述了一個(gè) contact 的結(jié)構(gòu)旭愧。后面會(huì)詳細(xì)介紹。
protoScript.sh 是一個(gè) bash 腳本宙暇,將通過 protocol buffer 編譯器生成 contact.proto 所定義的 Swift 結(jié)構(gòu)和 Python 類输枯。
在 folder Starter/Server 下面有如下文件:
RWServer.py 是一個(gè) Python 服務(wù)器,基于 Flask 構(gòu)建占贫。它有兩個(gè) GET 請(qǐng)求:
/currentUser 返回當(dāng)前參會(huì)者的信息桃熄。
/speakers 返回發(fā)言者的列表。
RWDict.py 包含了 RWServer 會(huì)讀取的一個(gè)發(fā)言者的 dictionary靶剑。
然后是配置 protocol buffer 運(yùn)行環(huán)境蜻拨。在后面,你將安裝 Google protocol buffer 編譯器的運(yùn)行環(huán)境桩引、Swift Protobuf 插件缎讼、以及運(yùn)行 Python 服務(wù)器所需要的 Flask。
要使用 protocol buffers坑匠,我們需要安裝一些工具和庫血崭。開始項(xiàng)目中已經(jīng)包含了一個(gè) protoInstallation.sh 腳本,它會(huì)為你完成所有的工作。而且更好的是夹纫,它還會(huì)在安裝某個(gè)庫之前檢查其它庫是否安裝了咽瓷。
這個(gè)腳本的執(zhí)行會(huì)花一點(diǎn)時(shí)間,尤其是安裝 Google 的 protocol buffer 庫的時(shí)候舰讹。打開你的終端茅姜,切到開始項(xiàng)目目錄,執(zhí)行命令:
$ ./protoInstallation.sh
注意:執(zhí)行這個(gè)腳本月匣,可能需要你輸入管理員密碼钻洒。
當(dāng)腳本執(zhí)行完成,你可以再次執(zhí)行它锄开,并確認(rèn)你看到如下輸出:
https://koenig-media.raywenderlich.com/uploads/2016/12/Screen-Shot-2016-12-10-at-2.51.38-PM.png’ width=’550’/>
如果你看到上圖的樣子素标,說明腳本執(zhí)行成功。如果腳本沒有執(zhí)行成功萍悴,可能你的管理員密碼輸錯(cuò)了头遭。如果是這樣,請(qǐng)重新運(yùn)行腳本癣诱,對(duì)于已經(jīng)執(zhí)行成功的內(nèi)容计维,它不會(huì)重復(fù)執(zhí)行的。
這段腳本進(jìn)行了如下工作:
安裝 Flask狡刘,以便能夠在本機(jī)運(yùn)行 Python 服務(wù)器享潜。
從 Starter/protobuf-3.1.0 目錄編譯 Google protocol buffer 編譯器。
安裝 Python 的 protocol buffer 模塊嗅蔬,以便服務(wù)器能夠調(diào)用 protobuf 庫。
將 Swift Protobuf 插件拷貝到 /usr/local/bin疾就。這使得 Protobuf 編譯器能夠生成 Swift 結(jié)構(gòu)澜术。
注意:要具體了解這個(gè)腳本是什么意思,請(qǐng)用文本編輯器打開 protoInstallation.sh 查看詳細(xì)命令猬腰。這需要你具備一定的 bash 知識(shí)鸟废。
萬事俱備,讓我們開始使用 protocol buffers 吧姑荷!
.proto 文件用于定義 protocol buffer 消息盒延,所謂消息描述了數(shù)據(jù)的結(jié)構(gòu)。將它傳遞給 protocol buffer 編譯器之后鼠冕,就會(huì)生成數(shù)據(jù)訪問器結(jié)構(gòu)添寺。
注意:在本教程中,我們將使用 proto3懈费,這是最新的 protocol buffer 語言版本计露。要深入了解這種語法以及如何定義 proto3 文件,請(qǐng)看 Google 的官方指南。
用任意文本編輯器打開 ProtoSchema/contact.proto票罐。這里叉趣,我們使用現(xiàn)成的 .proto 文件,它已經(jīng)為我們定義好了 Contact 消息和 Speakers 消息:
syntax ="proto3";message Contact {// 1enumContactType {// 2SPEAKER =0;? ? ATTENDANT =1;? ? VOLUNTEER =2;? }stringfirst_name =1;//3stringlast_name =2;stringtwitter_name =3;stringemail =4;stringgithub_link =5;? ContactType type =6;stringimageName =7;};message Speakers {// 4repeated Contact contacts =1;};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
這個(gè)定義包含了如下內(nèi)容:
Contact 模型描述了某個(gè)人的聯(lián)系信息该押。在 App 中疗杉,這些信息會(huì)顯示在這個(gè)人的徽章下面。
每個(gè) Contact 都有一個(gè)類別蚕礼,以便區(qū)分這個(gè)人是發(fā)言者還是聽眾烟具。
proto 文件中的 message 和 enum 定義中的每個(gè)字段都必須賦一個(gè)遞增的、唯一的 tag 值闻牡。這個(gè) tag 值會(huì)被 message 二進(jìn)制格式中用作唯一標(biāo)識(shí)净赴,以便保持它們的順序。更多關(guān)于 tag 值和字段管理的內(nèi)容罩润,請(qǐng)參考 google 文檔中的reserved fields玖翅。
Speakers 模型是一個(gè)包含了 Contact 對(duì)象的集合。repeated 表示這是一個(gè)對(duì)象的數(shù)組割以。
當(dāng)我們把 contact.proto 傳遞給 protoc 程序時(shí)金度,proto 文件就生成了 Swift 結(jié)構(gòu)。這些結(jié)構(gòu)將繼承 ProtobufMessage 協(xié)議严沥。protoc 會(huì)為每個(gè) Swift 字段猜极、初始化方法、以及序列化/反序列化方法提供屬性消玄。
注意:關(guān)于 Swfit protobuf API 的更多內(nèi)容跟伏,請(qǐng)參考Apple 的 Protobuf API 文檔。
打開終端翩瓜,切到 Starter/ProtoSchema 目錄受扳。在文本編輯器中打開 protoScript.sh :
#!/bin/bashecho'Running ProtoBuf Compiler to convert .proto schema to Swift'protoc --swift_out=. contact.proto //1echo'Running Protobuf Compiler to convert .proto schema to Python'protoc -I=. --python_out=. ./contact.proto //2
1
2
3
4
5
1
2
3
4
5
這個(gè)腳本會(huì)調(diào)用 protoc 兩次——一次生成了 Swift 源文件,一次生成了 Python 文件兔跌。
回到終端勘高,執(zhí)行這個(gè)腳本:
$ ./protoScript.sh
你會(huì)看到:
Running ProtoBuf Compilertoconvert.proto schematoSwiftprotoc-gen-swift: Generating Swiftforcontact.protoRunning Protobuf Compilertoconvert.proto schematoPython
1
2
3
1
2
3
這樣我們就根據(jù) contact.proto 文件生成了 Swift/Python 源文件。
在 ProtoSchema 目錄坟桅,你會(huì)看到兩個(gè)文件华望,一個(gè) Swift 的,一個(gè)是 Python 的仅乓。注意每個(gè)新生成的文件都會(huì)以 .pb.swift 或 .ph.py 文件為后綴名赖舟。pb 后綴表示它是 protocol buffer 生成的。
https://koenig-media.raywenderlich.com/uploads/2016/12/generatedFiles-650x71.png’ width=’700’/>
將 contact.pb.swift 拖到 Xcode 的項(xiàng)目導(dǎo)航器中方灾,并放到 Protocol Buffer Objects 文件夾下建蹄。注意勾選 “Copy items if needed” 選項(xiàng)碌更。通過 Finder 或終端,將 contact_pb2.py 拷貝到 Starter/Server 文件夾洞慎。
大概看一下 contact.pb.swift 和 contact_pb2.py 的內(nèi)容痛单,看看 proto 的消息是如何映射成兩種語言的結(jié)構(gòu)的。
我們已經(jīng)有了模型對(duì)象劲腿,是時(shí)候來使用他了旭绒!
示例項(xiàng)目包含了一個(gè)內(nèi)置的 Python 服務(wù)器。這個(gè)服務(wù)器提供兩個(gè) GET 接口:一個(gè)返回聽眾的徽章信息焦人,一個(gè)返回發(fā)言者列表挥吵。
本教程不涉及服務(wù)端代碼。但是需要注意 contact_pb2.py 模型文件花椭。另外如果你有興趣忽匈,可以看一下 RWServer.py。當(dāng)然對(duì)于本教程而言矿辽,這不是必須的丹允。
要開啟服務(wù)器,請(qǐng)打開終端袋倔,切換到 Starter/Server 目錄雕蔽。 執(zhí)行命令:
$ python RWServer.py
你會(huì)看到:
https://koenig-media.raywenderlich.com/uploads/2016/12/startServer.png’ width=’600’/>
用瀏覽器進(jìn)行 HTTP 請(qǐng)求,就可以看見 protocol buffer 的原始數(shù)據(jù)格式宾娜。
訪問http://127.0.0.1:5000/currentUser批狐,你會(huì)看到:
https://koenig-media.raywenderlich.com/uploads/2016/12/Screen-Shot-2016-12-10-at-11.41.52-AM-650x61.png’ width=’600’/>
試一下另外一個(gè)接口,http://127.0.0.1:5000/speakers:
https://koenig-media.raywenderlich.com/uploads/2016/12/Screen-Shot-2016-12-19-at-10.14.00-PM-650x70.png’ width=’600’/>
注意:你可以保持本地服務(wù)器的運(yùn)行前塔,也可以停止服務(wù)器嚣艇,然后在需要測(cè)試RWCards App 時(shí)再啟動(dòng)它。
我們啟動(dòng)了一個(gè)簡(jiǎn)單服務(wù)器华弓,這個(gè)服務(wù)器使用了 proto 文件中的消息作為我們的模型髓废。太好了!
讓本地服務(wù)器啟動(dòng)并保持運(yùn)行该抒,讓我們?cè)?App 中調(diào)用它的服務(wù)。在 RWService.swift 中顶燕,將 RWService 類替換為:
class RWService {staticletshared = RWService()// 1leturl ="http://127.0.0.1:5000"privateinit() { }? func getCurrentUser(_ completion: @escaping (Contact?) -> ()) {// 2letpath ="/currentUser"Alamofire.request("\(url)\(path)").responseData { responseinifletdata = response.result.value{// 3letcontact =try? Contact(protobuf: data)// 4completion(contact)? ? ? }? ? ? completion(nil)? ? }? }}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
這個(gè)類負(fù)責(zé)和我們的Python 服務(wù)器進(jìn)行通訊凑保。我們用它實(shí)現(xiàn)了 currentUser 接口調(diào)用。代碼說明如下:
shared 是一個(gè)單實(shí)例涌攻,用于訪問網(wǎng)絡(luò)接口欧引。
getCurrentUser(_:) 方法用于請(qǐng)求 /currentUser 接口,以獲取當(dāng)前用戶數(shù)據(jù)恳谎。這個(gè)用戶在后臺(tái)是以硬編碼的形式定義的芝此。
通過 if let 語句對(duì)響應(yīng)值進(jìn)行解包憋肖。
data 對(duì)象中是 protocol buffer 的二進(jìn)制形式。Contact 構(gòu)造函數(shù)把它作為參數(shù)婚苹,然后對(duì)收到的消息進(jìn)行解碼岸更。
將 protocol buffer 轉(zhuǎn)換成對(duì)象非常簡(jiǎn)單,只需調(diào)用這個(gè)對(duì)象的構(gòu)造函數(shù)并傳入 data膊升。不需要你手動(dòng)解析數(shù)據(jù)怎炊。Swift Protobuf 庫自動(dòng)為你完成一切。
獲得接口數(shù)據(jù)之后廓译,我們要把它顯示出來评肆。
打開 CardViewController.swift,在 viewWillAppear(_:) 方法后面添加方法:
func fetchCurrentUser() { //1RWService.shared.getCurrentUser{ contactinif let contact = contact {? ? ? self.configure(contact)? ? }? }}func configure(_ contact: Contact) { //2self.attendeeNameLabel.attributedText= NSAttributedString.attributedString(for: contact.firstName,and: contact.lastName)? self.twitterLabel.text= contact.twitterNameself.emailLabel.text= contact.emailself.githubLabel.text= contact.githubLinkself.profileImageView.image= UIImage(named: contact.imageName)}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
這兩個(gè)方法用于從服務(wù)器抓取數(shù)據(jù)并顯示用戶徽章非区。代碼解釋如下:
fetchCurrentUser() 負(fù)責(zé)請(qǐng)求服務(wù)器瓜挽,抓取當(dāng)前用戶信息,用 contact 對(duì)象刷新 CardViewController征绸。
configure(_:) 需要一個(gè) Contact 參數(shù)久橙,并對(duì)控制器中的 UI 控件進(jìn)行賦值。
稍后我們?cè)僬{(diào)用這兩個(gè)方法歹垫,現(xiàn)在我們需要從 ContactType 枚舉派生出一個(gè)可讀的聽眾類型剥汤。
我們需要用一個(gè)方法將枚舉類型轉(zhuǎn)換成字符串類型,這樣發(fā)言者的徽章會(huì)顯示成 SPEAKER 而不是 0排惨。
這里有一個(gè)問題吭敢。因?yàn)槊慨?dāng)修改消息之后都需要重新生成 .proto 文件,那么我們?nèi)绾卧谀P椭屑尤胱约旱姆椒兀?/p>
Swift 的擴(kuò)展能夠解決這個(gè)問題暮芭。通過擴(kuò)展鹿驼,我們可以向某個(gè)類中添加方法,而不需要修改它用來的代碼辕宏。
創(chuàng)建一個(gè) contact+extension.swift 文件畜晰,將它加到 Protocol Buffer Objects 文件夾中。這個(gè)文件的內(nèi)容編輯如下:
extension Contact {? func contactTypeToString()->String {switchtype {case.speaker:return"SPEAKER"case.attendant:return"ATTENDEE"case.volunteer:return"VOLUNTEER"default:return"UNKNOWN"}? }}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1
2
3
4
5
6
7
8
9
10
11
12
13
14
contactTypeToString() 方法將 ContactType 類型轉(zhuǎn)換為可顯示的字符串瑞筐。
打開 CardViewController.swift凄鼻,在 configure(_:) 中加入:
self.attendeeTypeLabel.text= contact.contactTypeToString()
1
1
這句代碼將 attendeeTypeLabel 的文本顯示為由 contact 類型轉(zhuǎn)換來的字符串表示。
最后聚假,在 ViewWillAppear 方法的 applyBusinessCardAppearance() 一句后面加入:
ifisCurrentUser {? fetchCurrentUser()}else{// TODO: handle speaker}
1
2
3
4
5
1
2
3
4
5
isCurrentUser 當(dāng)前被硬編碼為 true块蚌,當(dāng)我們需要支持發(fā)言者類型時(shí)我們?cè)賮硇薷乃.?dāng) isCurrentUser 為 true 時(shí)膘格,調(diào)用 fetchCurrentUser()峭范,這會(huì)抓取當(dāng)前用戶信息并顯示到卡片中。
運(yùn)行程序瘪贱,查看聽眾的徽章纱控。
https://koenig-media.raywenderlich.com/uploads/2016/12/Simulator-Screen-Shot-Dec-10-2016-11.00.10-AM.png’ width=’160’/>
在 My Badge 頁完成之后辆毡,我們需要來完成 Spearkers 頁面。
打開 RWService.swift甜害,添加方法:
func getSpeakers(_ completion:@escaping(Speakers?) -> ()){ // 1letpath= "/speakers"Alamofire.request("\(url)\(path)").responseData{responseinifletdata=response.result.value{ // 2letspeakers=try?Speakers(protobuf: data)// 3completion(speakers)}? }completion(nil)}
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
看起來很熟悉吧舶掖?這和 getCurrentUser(_:) 其實(shí)是一樣的,不過它獲取的是發(fā)言者數(shù)據(jù)唾那。發(fā)言者是一個(gè) Contact 對(duì)象數(shù)組访锻,表示所有會(huì)議發(fā)言者。
打開 SpeakersViewModel.swift 闹获,替換文件內(nèi)容為:
classSpeakersViewModel{varspeakers: Speakers!varselectedSpeaker: Contact?? init(speakers: Speakers) {? ? self.speakers = speakers? }? func numberOfRows()->Int {returnspeakers.contacts.count? }? func numberOfSections()->Int {return1}? func getSpeaker(forindexPath: IndexPath)->Contact {returnspeakers.contacts[indexPath.item]? }? func selectSpeaker(forindexPath: IndexPath) {? ? selectedSpeaker = getSpeaker(for: indexPath)? }}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
這個(gè)類用作 SpeakersListViewController 的數(shù)據(jù)源期犬,用于顯示一個(gè)會(huì)議發(fā)言者的列表。speakers 是一個(gè) Contacts 數(shù)組避诽,用 /speakers 接口返回的數(shù)據(jù)填充龟虎。這個(gè)數(shù)據(jù)源為表格的每一行提供一個(gè) Contact 對(duì)象。
view model 準(zhǔn)備好之后沙庐,我們就可以來配置單元格了鲤妥。打開 SpeakerCell.swift 添加方法:
func configure(with contact: Contact) {? profileImageView.image= UIImage(named: contact.imageName)? nameLabel.attributedText= NSAttributedString.attributedString(for: contact.firstName,and: contact.lastName)}
1
2
3
4
1
2
3
4
這個(gè)方法使用一個(gè) Contact 參數(shù),用它來對(duì) cell 的 UIImage 和 UILabel 進(jìn)行賦值拱雏。每個(gè) cell 會(huì)包含一張發(fā)言者的圖片棉安,以及姓名。
然后铸抑,打開 SpeakersListViewController.swift贡耽,在 viewWillAppear(_:) 的父類方法調(diào)用之后添加:
RWService.shared.getSpeakers{ [unowned self] speakersinif let speakers = speakers {? ? self.speakersModel= SpeakersViewModel(speakers: speakers)? ? self.tableView.reloadData()? }}
1
2
3
4
5
6
1
2
3
4
5
6
getSpeakers(_:) 方法負(fù)責(zé)請(qǐng)求并返回一個(gè)發(fā)言者列表。然后用返回的發(fā)言者列表鹊汛,初始化 SpeakersViewModel 對(duì)象蒲赂。然后用抓取到的數(shù)據(jù)刷新表格。
然后需要為表格中的每一行分配一個(gè)發(fā)言者以便顯示刁憋。將 tableView(_:cellForRowAt:) 方法代碼替換為:
letcell = tableView.dequeueReusableCell(withIdentifier:"SpeakerCell",for: indexPath)as! SpeakerCellifletspeaker = speakersModel?.getSpeaker(for: indexPath) {? cell.configure(with: speaker)}returncell
1
2
3
4
5
1
2
3
4
5
getSpeaker(for:) 方法返回指定 indexPath 所對(duì)應(yīng)的 contact 對(duì)象滥嘴。configure(with:) 方法是 SpeakCell 中定義的,作用是設(shè)置單元格的發(fā)言者圖片和姓名至耻。
當(dāng)發(fā)言者列表中的 cell 被點(diǎn)擊若皱,我們要用 CardViewController 顯示所選發(fā)言者信息。打開CardViewController.swift 尘颓,新增如下屬性:
var speaker: Contact?
我們最終會(huì)將所選的發(fā)言者傳遞個(gè)這個(gè)屬性是尖。然后,我們需要顯示發(fā)言者泥耀。將 // TODO: handle speaker 一行替換為:
ifletspeaker = speaker {? configure(speaker)}
1
2
3
1
2
3
這里檢查了 speaker 是否不為空,如果不為空蛔添,調(diào)用 configure() 方法痰催,這個(gè)方法將用指定發(fā)言者信息刷新卡片兜辞。
回到 SpeakersListViewController.swift,傳入選定的發(fā)言者夸溶。首先在 tableView(_:didSelectRowAt:) 方法中逸吵,在 performSegue(withIdentifier:sender:) 之前加入:
speakersModel?.selectSpeaker(for: indexPath)
這句會(huì)在 speakersModel 中記錄用戶所選擇的發(fā)言者。
然后缝裁,在 prepare(for:sender:) 方法中扫皱,在 vc.isCurrentUser = false 一句后面添加:
vc.speaker = speakersModel?.selectedSpeaker
這句將 selectedSpeaker 傳遞給 CardViewController 启昧,以便顯示它族购。
看一下你的本地服務(wù)器是否仍然運(yùn)行,然后編譯運(yùn)行 Xcode〖樱現(xiàn)在粹污,你會(huì)發(fā)現(xiàn) App 已經(jīng)能夠顯示用戶徽章和發(fā)言者列表了段多。
https://koenig-media.raywenderlich.com/uploads/2016/12/pb4-1.gif” width=”300”/>
我們用一個(gè) Python 服務(wù)器和一個(gè) Swift 客戶端打造了一個(gè)端到端應(yīng)用。它們共用由同一個(gè) proto 文件所生成的模型壮吩。如果你想修改模型进苍,只需要運(yùn)行一下編譯器再次生成模型即可,這樣你就可以同時(shí)在服務(wù)端和客戶端使用了鸭叙!
你可以在這里下載最終完成項(xiàng)目觉啊。
在本教程中,我們學(xué)習(xí)了基本的 protocol buffers 用法沈贝,如何定義 .proto 文件杠人、用編譯器生成 Swift 代碼。我們也學(xué)習(xí)了如何啟動(dòng)一個(gè)簡(jiǎn)單的 Flask 本地服務(wù)器缀程,通過這個(gè)服務(wù)器我們創(chuàng)建了一個(gè)服務(wù)用于發(fā)送 protocol buffer 二進(jìn)制到客戶端搜吧,用 protocol buffers 解析這些數(shù)據(jù)是非常簡(jiǎn)單的!
關(guān)于 protocol buffers 還有很多內(nèi)容杨凑,比如定義消息映射以及向后兼容滤奈。如果你對(duì)這些感興趣,請(qǐng)參考Google 文檔撩满。
還有一件有意思的事情就是 protocol buffers 可以用在遠(yuǎn)程過程調(diào)用蜒程。請(qǐng)參考GRPC。
有任何問題和建議伺帘,請(qǐng)?jiān)谙旅媪粞浴?/p>