iOS引入google ProtocolBuffer(protobuf3)

史前圖騰發表於2017-12-13
protobuf3.0之後已經很好用了,swift版也有,但網上教程很多已經很老了,不適用了,所以寫個新的

總的過程是3步:

1.編譯安裝.proto格式轉換器; 2.引入相應版本的protobuf(多用CocoaPods); 3.命令列轉換成OC或swift檔案並拖入專案中;

第一步alexeyxo大神(方法二)用了Homebrew全自動安裝,最方便,蘋果(方法三)和谷歌(方法一)的需要手動輸入命令,蘋果還要手動放到/usr/local/bin/目錄下,較為複雜,不過目前蘋果正在快速更新,估計以後就更好用了

方法一:安裝編譯google官方的OC, protobuf3.0以後

參考文章http://blog.csdn.net/mtc1256/article/details/52180929

下載好之後開始安裝

cd protobuf-3.0.0
./configure
make -j8
sudo make install
複製程式碼

驗證是否安裝成功

$ which protoc
/usr/local/bin/protoc
複製程式碼
  • 用pod引入專案中
pod 'Protobuf', '~> 3.2.0'
複製程式碼
  • 寫一個測試指令碼生成proto程式碼

Person.proto

syntax = "proto3";
package com.xxx;
option swift_prefix = "TCC";//swift類字首,適用於方法三
option objc_class_prefix = "TCC";//OC類字首,適用於方法一
message Person{
 string name = 1;
 int32 level = 2;
 string icon = 3;
}
複製程式碼

或者proto2語法

syntax = "proto2";

message Person {
    required string name = 1;
    required int32 level = 2;
    required string icon = 3;
}
複製程式碼

程式碼直接生成.h和.m 舉例:cd進入Person.proto所在的資料夾下,執行命令

protoc  --objc_out=. Person.proto
複製程式碼

然後在gen資料夾下就會生成Person.pbobjc.h和Person.pbobjc.m檔案。 protobuf為了效能考慮,建立的都是mrc檔案,因此在build phrases ->Compile sources中給拖入的檔案新增 -fno-objc-arc的標誌

  • 簡單使用
//建立,直直接賦值
Person *myPerson = [Person alloc] init];
myPerson.name = @"xu";
myPerson.level = 4;
myPerson.icon = @"123.jpg";
//得到data
NSData *data = myPerson.data;
NSLog(@"%@",data);
//從data得到模型
NSError *error = nil;
Person *myPerson2 = [Person parseFromData:data error:&error];
NSLog(@"%@",myPerson2.description);
複製程式碼

方法二:使用別人編譯好的,包括OC,swift

參考http://www.cnblogs.com/akforsure/p/5190187.html github上有大神提供了編譯好的OC和swift版protobuf.由於目前谷歌官方在3.0版本後已經提供了OC版,所以只有swift版還在更新 地址裡面也有操作步驟說明https://github.com/alexeyxo

推薦使用Homebrew自動安裝+pod引用的方式

  • 安裝編譯 利用Homebrew自動安裝(建議使用)
1.ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
2.brew install protobuf-swift
複製程式碼

或手動編譯

1.ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

2.brew install automake

3.brew install libtool

4.brew install protobuf

5.git clone git@github.com:alexeyxo/protobuf-swift.git

6../scripts/build.sh
複製程式碼
  • 編譯安裝後引入專案中 手動新增 ./src/ProtocolBuffers/ProtocolBuffers.xcodeproj 到自己的專案 也可以使用pod方式(建議使用)
use_frameworks!
pod 'ProtocolBuffers-Swift'
複製程式碼
  • 輸出到當前目錄 cd到Person.proto目錄,執行下列,得到Person.proto.swift檔案,拖入專案中即可
protoc  Person.proto --swift_out="./"
複製程式碼
  • 簡單使用
//建立:用builder賦值,得到的是Person.Builder類,不是模型
let myPersonBuilder = Person.Builder()
myPersonBuilder.name = "coderXu"
myPersonBuilder.level = 100
myPersonBuilder.icon = "123.png"
        
//轉成data,需要用到build()來得到真正的模型person例項
guard let myPerson = try? myPersonBuilder.build() else { return }
let data = myPerson.data()

//從data轉回來
let myPerson2 = try? Person.parseFrom(data: data)
print(myPerson2.name)
print(myPerson2.level)
print(myPerson2.icon)
複製程式碼

方法三:使用蘋果官方提供的swift版

參考https://github.com/apple/swift-protobuf

需要注意:如果已經使用了方法二的第三方swift版,需要執行brew uninstall protobuf-swift解除安裝掉

否則會和蘋果官方的swift轉換工具衝突,因為兩個都叫protoc-gen-swift,但是轉換出來的格式不一樣,蘋果官方得到的叫Person.pb.swift,而第三方的叫Person.proto.swift,而且會報錯import ProtocolBuffers找不到no such module ProtocolBuffers

  • 編譯和安裝 先下載,進入,列出tag,切換到對應分支,然後build
$ git clone https://github.com/apple/swift-protobuf.git
$ cd swift-protobuf
$ git tag -l
$ git checkout tags/[tag_name]
$ swift build
複製程式碼

然後進入.build/debug資料夾下,找到protoc-gen-swift,這是一個可執行檔案,複製一份放到系統的PATH環境目錄下,在mac也就是磁碟/usr/local/bin下面 其中protoc是方法一谷歌生成OC版轉換器

WX20170515-230043@2x.png

需要注意:如果已經使用了方法二的第三方swift版,需要先執行brew uninstall protobuf-swift解除安裝掉 否則會和蘋果官方的swift轉換工具衝突,因為兩個都叫protoc-gen-swift,但是轉換出來的格式不一樣,蘋果官方得到的叫Person.pb.swift,而第三方的叫Person.proto.swift,而且會報錯import ProtocolBuffers找不到no such module ProtocolBuffers

  • 引入專案 推薦用pod,pod install
pod 'SwiftProtobuf'
複製程式碼
  • 轉換輸出 cd到Person.proto目錄,執行下列系統會自動PATH環境目錄下的protoc-gen-swift轉換,得到Person.pb.swift檔案,拖入專案中即可
protoc --swift_out=.  Person.proto
複製程式碼
  • 簡單使用
//直接初始化一個Person例項
var myPerson = Person()
//賦值
myPerson.name = "sss"
myPerson.level = 4
myPerson.icon = "444.jpg"
print(myPerson)
//預設情況下,要求必須有值時(required),如果賦值不完整時,這一步會報錯
guard let data = try? myPerson.serializedData() else {print("error")  return}
print("========serializedData=\(data)")
        
guard let myPerson2 = try? Person(serializedData: data) else {
     print("error")
     return
}
print(myPerson2)
//要求必須有值時(required),賦值不完整時也可以通過引數partial: true來強制轉換出來
guard let data2 = try? myPerson.serializedData(partial: true) else {print("error")
     return}
print("========serializedData=\(data2)")
//同理,data2中的資料不完整也可以通過引數partial: true來強制轉換出來
guard let myPerson3 = try? person(serializedData: data2, partial: true) else {
     print("error")
     return
}
print(myPerson3)
複製程式碼
//json格式字串初始化,可以將字典序列化為Data後再轉換為String得到
let jsonString = "{\"name\":\"xu\",\"icon\":\"321.jpg\",\"level\":2}"
//Person(jsonString: jsonString)
//Person(textFormatString: textString)
//建立:得到模型
guard var myPerson = try? Person(jsonString: jsonString) else {
     print("error")
    return
}
//修改
myPerson.icon = "li.png"
print(myPerson)

//得到Protocol Buffer二進位制序列化的data,一般用來傳輸
guard let data = try? myPerson.serializedData() else {
    print("error")
    return}
print("=========\(data)")
//從Protocol Buffer二進位制序列化data 得到模型
guard let myPerson2 = try? Person(serializedData: data) else {
    print("error")
    return
}
print(myPerson2)
複製程式碼
//textFormatString格式示例,中間用\n或空格分隔
let textString = "name:\"xu\" icon:\"321.jpg\" level:2"
//得到myPerson模型
guard var myPerson = try? Person(textFormatString: textString) else {
       print("error")
       return
}
//修改模型
myPerson.icon = "li.png"
print(myPerson)

//得到UTF-8 JSON序列化的data,這樣沒用到protobuf,是用iOS的JSON serialization轉換的data,一般用來內部使用
guard let data2 = try? myPerson.jsonUTF8Data() else {print("error")
    return}
print("========jsonUTF8Data=\(data2)")
//從UTF-8 JSON序列化的data 得到模型
guard let myPerson3 = try? Person(jsonUTF8Data: data2) else {
     print("error")
    return
}
print(myPerson3)
複製程式碼

最後,protobuf的textFormat格式舉例: 檔案定義test.proto:

//學生模型
message student{  
    required string name = 1;   //姓名  
    required int32  age = 2;    //年齡  
    optional string addr = 3;  
}  
  
//班級模型,包含班級名和學生  
message class{  
    required string name = 1;   //班級名稱  
    repeated student member = 2;    //班級成員 
}
複製程式碼

初始化時的textFormat格式應為

name: "Communication 2004"  
member {  
  name: "flyan338"  
  age: 26  
  addr: "china"  
}  
member {  
  name: "likeliu"  
  age: 25  
  addr: "china"  
}  
member {  
  name: "gaoy"  
  age: 24  
  addr: "American"  
}  
複製程式碼

這份配置表明:一個叫做 "Communication 2004"的班級,有3個student,你可以直接用protobuf來load出來

相關文章