還在用JSON? Google Protocol Buffers 更快更小 (實踐篇)

隨手記技術團隊發表於2018-03-27

歡迎關注微信公眾號「隨手記技術團隊」,檢視更多隨手記團隊的技術文章。轉載請註明出處
本文作者:丁同舟
原文連結:mp.weixin.qq.com/s/y0dyK47_s…

背景

由於隨手記客戶端與服務端互動的過程中,對部分資料的傳輸大小和效率有較高的要求,普通的資料格式如 JSON 或者 XML 已經不能滿足,因此決定採用 Google 推出的 Protocol Buffers 以達到資料高效傳輸。

介紹

Protocol buffers 為 Google 提出的一種跨平臺、多語言支援且開源的序列化資料格式。相對於類似的 XML 和 JSON,Protocol buffers 更為小巧、快速和簡單。其語法目前分為proto2proto3兩種格式。

目前 Google 官方的 Protobuf 最新 release 版本為3.5.1,以下都是基於此版本的環境搭建。

關於 Protocol Buffer 的使用可以查閱官方文件

準備工作

環境要求

  • Objective-C 2.0 Runtime (32bit & 64bit iOS, 64bit OS X)
  • Xcode 7.0+

Note

Protobuf 出於效能考慮沒有使用 ARC,但在 ARC 下是可以使用的

安裝

  1. 下載 Protobuf 程式碼包,這裡選擇 protobuf-objectivec-3.5.1.tar.gz

  2. 解壓程式碼包

  3. 編譯 Protobuf,這裡可能需要安裝部分工具:

$ brew install autoconf
$ brew install automake
$ brew install libtool
複製程式碼
  1. 執行下面指令碼進行編譯
$ ./autogen.sh
$ ./configure
$ make
$ make install
複製程式碼
  1. 檢查protobuf是否安裝成功
$ protoc --version
複製程式碼

如果成功列印版本號則安裝成功

libprotoc 3.5.1
複製程式碼

在 iOS 中使用 Protobuf

建立.proto檔案

這裡使用官方文件上的一份示例資料結構建立Person.proto

syntax = "proto3";

message Person {
  string name = 1;
  int32 id = 2;
  string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    string number = 1;
    PhoneType type = 2;
  }

  repeated PhoneNumber phone = 4;
}
複製程式碼

使用命令列編譯Person.protoobjective-c的檔案,編譯出來的檔案為Person.pbobjc.hPerson.pbobjc.m

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

引入 Protobuf 執行時資源

Google 官方的文件提供了兩種引入方式,但使用第一種的時候編譯不能通過,所以這裡選擇了第二種:

複製protobuf目錄下的objectivec/*.h, objectivec/google/protobuf/*.pbobjc.h, objectivec/google/protobuf/*.pbobjc.m, 以及除去objectivec/GPBProtocolBuffers.m後的objectivec/*.m

這裡直接用命令列操作,首先進入protobufobjectivec的目錄:

 $ cd protobuf-3.5.1/objectivec
複製程式碼

然後複製符合規則的檔案到指定的工程目錄下:

$ mkdir ~/ProtobufDemo/ProtocolBuffers ~/ProtobufDemo/ProtocolBuffers/google ~/ProtobufDemo/ProtocolBuffers/google/protobuf
$ cp *.h *.m ~/ProtobufDemo/ProtocolBuffers
$ cp google/protobuf/*.pbobjc.h google/protobuf/*.pbobjc.m ~/ProtobufDemo/ProtocolBuffers/google/protobuf

複製程式碼

Note

上面的命令並沒有排除 GPBProtocolBuffers.m 檔案,引入時需要手動排除

現在把ProtocolBuffers目錄下所有檔案以及上面編譯出來的Person.pbobjc.hPerson.pbobjc.m都引入到工程中

現在工程目錄結構大概是長這樣

project-structure2

需要注意,由於protobuf沒有使用 ARC,因此需要為所有.m檔案加上-fno-objc-arc來關閉 ARC

compile-source

Note

需要注意工程中的 Header Search Paths 要增加 $(PROJECT_DIR)/ProtocolBuffers(具體的路徑視情況而定)

直接引入 ProtocolBuffers 工程

如果覺得手動引入檔案的方式過於複雜,可以直接引入ProtocolBuffers工程作為依賴項

  1. 進入解壓後的protobuf目錄下,複製objective目錄下的所有檔案到ProtobufDemo/ProtocolBuffers目錄下

  2. ProtobufDemo工程中引入ProtocolBuffers_iOS工程

    ProtobufDemo 工程結

  3. Build Phases中加入依賴關係並連結庫

    Build Phases配置

  4. 引入Person.pbobjc.hPerson.pbobjc.m檔案併為.m加上-fno-objc-arc

  5. 修改工程配置中部分路徑為 $(PROJECT_DIR)/ProtocolBuffers

測試

首先引入標頭檔案

#import "Person.pbobjc.h"
複製程式碼

生成Person物件並進行編碼和解碼

Person *p = [[Person alloc] init];
p.id_p = 1;
p.name = @"person1";
p.email = @"123@qq.com";

//encode
NSData *data = [p data];
NSLog(@"Protocol Buffers:\n%@\nData: %@\nData Length: %lu", p, data, data.length);

//decode
Person *newP = [[Person alloc] initWithData:data error:nil];
NSLog(@"Decoded: %@", newP);
複製程式碼

執行程式,列印日誌如下:

Protocol Buffers:
<Person 0x60c0000da2b0>: {
    name: "person1"
    id: 1
    email: "123@qq.com"
}
Data: <0a077065 72736f6e 3110011a 0a313233 4071712e 636f6d>
Data Length: 23

Decoded: <Person 0x6040000d9c90>: {
    name: "person1"
    id: 1
    email: "123@qq.com"
}
複製程式碼

Coffee time!

相關文章