DearMiku

iOS中使用Protocol Buffer

字数统计: 1.3k阅读时长: 4 min
2017/11/03 Share

iOS中使用Protocol Buffer

简介

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到其目录下执行下面的终端命令进行安装

1
2
3
4
5
$ ./autogen.sh
$ ./configure
$ make
$ make check
$ sudo install

安装结束后,执行 protoc –version ,若有显示版本号,则表明安装成功.若是要试用Swift则需要

1
2
3
4
$ brew install protobuf-swift
$ git clone https://github.com/alexeyxo/protobuf-swift.git
//cd到clone后的目录
$ ./scripts/build.sh

接下来就是创建proto文件,将其翻译为OC或Swift,所以先了解proto的语法

语法

接下来我只介绍些常用语法,这里有介绍语法比较详细的博文 这是一份很有诚意的Protocol Buffer语法详解 Protobuf3 语法指南

1
2
3
4
5
6
7
8
9
10
//表示使用的是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

1
2
进入proto文件目录 执行下面的命令
$ protoc --objc_out=./ ./test.proto

Swift

1
2
进入proto文件目录 执行下面的命令
$ mbp$ protoc --swift_out=./ ./test.proto

这样就得到了,翻译后所需的类文件了,接下来就要到项目中集成了

项目集成

在项目中使用PB需要使用第三方库,可以使用CocoaPod集成

1
2
3
4
5
OC:
pod "Protobuf"

Swift:
pod 'ProtocolBuffers-Swift'

对于OC版本,拖进项目后要再做一些额外处理,生成的是MRC环境下的代码,需要设置一下, 其次再编译后会报一些错误,据我所知的处理方案是将其注释掉(我了解到的是该方法在C99后失效了,至于为何这里还有,我也很无奈ㄟ( ▔, ▔ )ㄏ,到Github上反应了).这样就可以使用了. 然后就是PB的序列化与反序列化

序列化与反序列化

OC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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);

运行结果:

1
2
PB --> 16  JSON --> 49
南小鸟,18,<GPBInt32Array 0x600000059200> { 10 }

Swift

1
2
3
4
5
6
7
8
9
10
11
//创建新的对象,通过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
1,数据压缩效果好,序列化反序列速度快
2,跨平台,生成一次proto文件,多端使用

缺点

1
2
3
1,可读性行差(在代码中)
2,最增加App包体积(生成的类本身就代码很多,而且需要使用第三方库)
3,用的人少(在项目交接时,还需要学习这方面的知识)

综上:个人觉得该方案适用于大量频繁的数据交流业务中,如IM
若有不准确的地方,欢迎大家指正

CATALOG
  1. 1. iOS中使用Protocol Buffer
    1. 1.1. 简介
    2. 1.2. 原理
    3. 1.3. 安装
    4. 1.4. 语法
    5. 1.5. 编译转换
    6. 1.6. 项目集成
    7. 1.7. 序列化与反序列化
    8. 1.8. 优缺点