分享iOS使用ProtocolBuffer的方法

时间:2022-12-05 03:58:23

分享一下用了两个月的ProtocolBuffer,对它的理解。

上班第一天,技术总监丢给我一个PortocolBuffer的文档,说这个是我们的网络协议文档,到时候你用这个和服务器交互?整个人都傻了,以前都没听过。不知道为什么要用ProtocolBuffer,用JSON不好吗? 哎,想太多也没用。作为小弟的只能学怎么去用。

那么ProtocolBuffer究竟是什么呢?我理解为就像<NSCoding>协议一样。可以把一个内存里的对象序列化成一个二进制的包。反过来可以把二进制的包反序列化成一个对象。

那么为什么要用ProtocolBuffer呢?看了一堆网上说的好处,我只记得一点,这个序列化成的二进制的包比其他传输格式小很多,可以节约网络流量。

那么重点是,怎么用ProtocolBuffer呢?这里就要详细点说了。

首先,ProtocolBuffer是Google的产物,官方说的是:"目前支持Java,Python, 和C++。在最新的版本,增加了Go,JavaNano,Ruby,C#语言,然后呢更多语言支持会出来"。 没错,目前2015年10月21日,官方原生不支持OC,或者Swift。那么做iOS的我们怎么办呢?

这里有两条思路。第一条思路是用C++的那一套,oc和C++非常亲和。第二条思路是用GitHub上面别人做好的OC,或者Swift那一套。可惜小弟我不熟悉C++,不过我还是把别人写好的C++的思路贴出来吧。

C++思路:https://developers.google.com/protocol-buffers/docs/cpptutorial   官方有详细的使用说明和教程。然后呢在我们的程序里面,OC和C++的桥接:

序列化成NSData:

- (NSData *)getDataForPacket:(Packet *)packet { 
std
::string ps = packet->SerializeAsString();
return [NSData dataWithBytes:ps.c_str() length:ps.size()];

反序列化成对象(注意这个Packet对象是我假定的,是proto文件里面编译出来的,如果你看不懂前面这句话,说明你没看官方说明,官方说明写得很详细)

- (Packet *)getPacketFromNSData:(NSData *)data { 
char raw[[data length]];
Packet *p = new Packet;
[data getBytes:raw length:[data length]];
p
->ParseFromArray(raw, [data length]);
return p;
}
好了,现在来说第二条思路。这条是我走过,走通过的路。

我也是用别人大牛做好的东西:https://github.com/alexeyxo/protobuf-objc 这个github里面有详细的使用说明。我简单的讲一下思路吧。


首先,需要搭建一个编译protocolbuffer的编译器:

1.检查你的mac有没有安装Homebrew :在命令行里面敲 brew -v

2.如果没有,就安装:ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

3.安装需要的小工具:brew install automake brew install libtool brew install protobuf

4.(可以跳过)为你的编译器创建一个连接 ln -s /usr/local/Cellar/protobuf/2.6.1/bin/protoc /usr/local/bin

5.把这个从网上克隆下来 git clone https://github.com/alexeyxo/protobuf-objc.git

  6.编译 ./scripts/build.sh

这样编译proto文件的编译器就弄好了。需要编译proto文件的时候,命令行进入有proto文件的文件夹:protoc --plugin=/usr/local/bin/protoc-gen-objc person.proto --objc_out="./"

“person.proto”改成你的proto文件名字。这样就可以把一个proto文件编译成一个person.h 和person.m  这样我们就可以吧.h和.m放入我们的工程使用了。

如果你不知道什么是proto文件。那么我简单说一下,proto文件就是用于规定一个类,有那些属性,叫什么名称之类的。我这边是总监写的,因为他负责服务器的数据和交互接口。

其次,我们要用cocopod导入 pod'ProtocolBuffers', '~> 1.9.8'   这样我们的工程就可以把.h和.m用于把类序列化成NSData和反序列化了。

这样就大功告成。


****使用ProtocolBuffer和服务器交互::

把一个对象发到服务器:

首先把这个对象设置好属性。

例如: PersonBuilder *personBuilder = [[PersonBuilder alloc] init];

personBuilder.age = 18;

personBuilder.name = @"xiaosan"

序列化:NSData *data = [PersonBuilder build].data;


接下来,怎么把NSData发送到服务器呢?

NSURLSessionDataTask就可以了。这里需要注意一点就是 [requestsetValue: @"application/protobuf"forHTTPHeaderField:@"Content-Type"];

这里服务器一般会设置好这个Content-Type,标明是Protobuffer格式的。这个是自定义的。

这样就把一个参数为  18岁, 名字  xiaosan的对象发到服务器了。然后服务器根据逻辑会返回一个NSData。

我们再把这个NSData反序列化成我们的对象。

例如,假设返回的对象是Person  :

  NSURLSessionDataTask *task = [sessiondataTaskWithRequest:request completionHandler:^(NSData *data,NSURLResponse *response, NSError *error) {

Person *person = [Person parseFromData:data];

............

}];

写到这里,我会的都写出来了,protocolbuffer整条线也走完了。

我们总监在这里还弄了一个与众不同的地方,他在二进制包的前面拼了两个字节的正短整型的数,这样来区分不同的逻辑。比如  我发送103是表示登录,然后服务器就会把我上传的对象按照登录的对象,反序列化处理。如果我发送104是表示获取订单,服务器就按照获取订单的对象处理。    当然,这个只是总监想的小点子而已,不同的公司有不同的处理办法吧。

好了,写完了,我写的不一定对。