iOS中使用Protocol Buffer

dearmiku發表於2017-12-12

簡介

Protocol Buffer(簡稱Protobuf或PB)是由Google推出的一種資料交換格式. 與傳統的XML和JSON不同的是,它是一種二進位制格式,免去了文字格式轉換的各種困擾,並且轉換效率也是非常快,由於它的跨平臺、跨程式語言的特點,讓它越來越普及,尤其是網路資料交換方面日趨成為一種主流.

原理

對於json和xml最終在網路傳輸時都是以字串轉二進位制的進行傳輸的,使用的是utf8編碼格式,而PB在編碼與解碼上進行了改進,使資料包更小,所以我覺得可以把他當做一種壓縮格式.這裡有一篇關於原理的博文,感興趣大家可以去看一看 Protocol Buffer 序列化原理大揭祕 - 為什麼Protocol Buffer效能這麼好?

安裝

我們需要安裝PB的編譯器,將我們用PB語法格式建立的物件轉化為OC或Swift的物件,原來PB只支援Python,Java,C++,現在新的版本支援OC,Swift需要我們額外配置一下,期待以後的更新吧.這是github的連結

解壓縮後,cd到其目錄下執行下面的終端命令進行安裝

$ ./autogen.sh
$ ./configure
$ make
$ make check
$ sudo install
複製程式碼

安裝結束後,執行 protoc --version ,若有顯示版本號,則表明安裝成功.若是要試用Swift則需要

$ brew install protobuf-swift
$ git clone https://github.com/alexeyxo/protobuf-swift.git
//cdclone後的目錄
$ ./scripts/build.sh
複製程式碼

接下來就是建立proto檔案,將其翻譯為OC或Swift,所以先了解proto的語法

語法

接下來我只介紹些常用語法,這裡有介紹語法比較詳細的博文 這是一份很有誠意的Protocol Buffer語法詳解 Protobuf3 語法指南

//表示使用的是PB3的語法
syntax = "proto3"; 

//message代表著一個資料結構,也就相當於一個類, 類名Person 
message Person {
  string name = 1;  
  int32 age = 2;
  repeated int32 friends = 3;
  //這裡就相當於類中的屬性,string表示型別為字串,name表示屬性名,數字1則是用來標識Person中的屬性,在編解碼時用到,使用從1遞增即可,這樣效率高些
}
複製程式碼

接下來是關於PB的資料結構型別,因為要控制資料編碼後大小,所以型別比較多

PB支援的資料型別

對應到iOS的OC和Swift中,上面就包含了所需的基本資料型別了,一個message,其實就可以看做一個字典.至於陣列就比較特別了,而是要在基本的資料結構前 加上可複用的修飾符 repeated 就如上面的friends一樣.

編譯轉換

OC

進入proto檔案目錄 執行下面的命令
$ protoc --objc_out=./ ./test.proto
複製程式碼

Swift

進入proto檔案目錄 執行下面的命令
$ mbp$ protoc --swift_out=./ ./test.proto
複製程式碼

這樣就得到了,翻譯後所需的類檔案了,接下來就要到專案中整合了

##專案整合 在專案中使用PB需要使用第三方庫,可以使用CocoaPod整合

OC:
pod "Protobuf"

Swift:
pod 'ProtocolBuffers-Swift'
複製程式碼

對於OC版本,拖進專案後要再做一些額外處理,生成的是MRC環境下的程式碼,需要設定一下, 其次再編譯後會報一些錯誤,據我所知的處理方案是將其註釋掉(我瞭解到的是該方法在C99後失效了,至於為何這裡還有,我也很無奈ㄟ( ▔, ▔ )ㄏ,到Github上反應了).這樣就可以使用了. 然後就是PB的序列化與反序列化

序列化與反序列化

OC

    Person* p = [Person new];
    p.name = @"南小鳥";
    p.age = 18;
    p.friendsArray = [GPBInt32Array array]; //這是裡面的陣列,其他方法可以點進去看
    [p.friendsArray addValue:10];

    NSString* jsonStr = @"{\"name\":\"南小鳥\",\"age\":18,\"friendsArray\":[10]}";

    NSData* data = [p data];    //序列化
    NSData* strData = [jsonStr dataUsingEncoding:(NSUTF8StringEncoding)];

    NSLog(@"PB --> %ld  JSON --> %ld",data.length,strData.length);

    //反序列化
    Person* res = [[Person alloc] initWithData:data error:nil];
    NSLog(@"%@,%ld,%@",res.name,res.age,res.friendsArray);
複製程式碼

執行結果:

PB --> 16  JSON --> 49
南小鳥,18,<GPBInt32Array 0x600000059200> { 10 }
複製程式碼

Swift

    //建立新的物件,通過Builder來進行建立,賦值.
        let p = Person.Builder()
        p.name = "南小鳥"
        p.age = 18
        p.friends = [10]

    //getMessage可以得到該物件,然後將其序列化
        let data = p.getMessage().data()
        
    //將其反序列化,可能出錯,需要try
        let res = try! Person.parseFrom(data: data)
複製程式碼

最後說一說PB的優缺點

優缺點

優點

1,資料壓縮效果好,序列化反序列速度快
2,跨平臺,生成一次proto檔案,多端使用
複製程式碼

缺點

1,可讀性行差(在程式碼中)
2,最增加App包體積(生成的類本身就程式碼很多,而且需要使用第三方庫)
3,用的人少(在專案交接時,還需要學習這方面的知識)
複製程式碼

綜上:個人覺得該方案適用於大量頻繁的資料交流業務中,如IM 若有不準確的地方,歡迎大家指正

相關文章