Protocol Buffers - Google的数据交换格式

概述

Protocol Buffers是什么呢,Protocol Buffers是一个灵活高效可序列化的数据交换格式,比起传统的XML方式,它更简单,更小巧,更快,更少歧义,并且能很方便的生成访问数据的类,不需要额外的解析器。

Protocol Buffers源代码

Protocol Buffers的源代码在Github上:https://github.com/google/protobuf,目前支持的语言有C++、Java、Python、Objective-C、C#、JavaNano、JavaScript、Ruby、Go、PHP。
Protocol Buffers源代码由两部分组成:
1、Protocol Buffers代码生成器,可以根据数据描述文件(.proto)生成指定语言的的数据模型类。
2、生成的数据模型类序列化与反序列化需要用到的基础依赖代码。

Protocol Buffers代码生成器的安装与使用

如果你是C++使用者,可以按照C++ Installation Instructions安装Protocol Buffers代码生成器,Objective-c使用者则可以直接下载一个pre-built binary: protobuf-objectivec-3.0.0-beta-2.tar.gz,下载好了之后使用如下命令安装:

1
2
3
4
5
6
tar -xzvf protobuf-objectivec-3.0.0-beta-2.tar.gz 
cd protobuf-3.0.0-beta-2
./configure
make
make check
sudo make install

安装好生成器之后,可以使用如下命令查看生成器的帮助文档

1
protoc -h

要使用生成器生成代码,需先编写.proto描述文件,示例如下

1
2
3
4
5
6
7
8
9
syntax = "proto3";//默认是生成proto2格式的代码,所以加上了一个proto3的头
message Person {
string name = 1;
int32 sex = 2;
int32 age = 3;
}
message Family {
repeated Person person = 1;//经过repeated修饰,能对应生成数组属性
}

编写好描述文件,保存为Family.proto,cd到同一目录下,执行以下命令

1
protoc --objc_out=./ ./Family.proto

ls以下便可查看到已经生成了一组代码文件

1
2
Family.pbobjc.h
Family.pbobjc.m

改变命令参数–objc_out为–cpp_out、–java_out可以生成对应其他语言使用的代码文件。

Protocol Buffers生成器生成的代码的使用

新建一个工程,将之前生成的代码添加进工程,因为生成的代码是MRC的,所以需要加上-fno-objc-arc这样的Compiler Flag,然后新建一个Podfile文件,编写内容如下

1
2
platform :ios, ‘7.2’
pod "Protobuf", "~> 3.0.0-beta-2"

这里一定记住版本号要和之前的生成器版本号一致,否则无法正常使用。执行pod install命令,重新用.xcworkspace文件打开工程,之后便可以开始使用Protocol Buffers生成器生成的代码啦,示例如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
- (void)viewDidLoad {
[super viewDidLoad];

Person *daddy = [Person new];
daddy.name = @"李雷";
daddy.sex = 1;
daddy.age = 28;

Person *mommy = [Person new];
mommy.name = @"韩梅梅";
mommy.sex = 2;
mommy.age = 26;

Person *daughter = [Person new];
daughter.name = @"李丽丽";
daughter.sex = 2;
daughter.age = 3;

Family *family1 = [Family new];
[family1.personArray addObject:daddy];
[family1.personArray addObject:mommy];
[family1.personArray addObject:daughter];

NSData *data = [family1 data];

[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"Family"];
[[NSUserDefaults standardUserDefaults] synchronize];
NSData *data2 = [[NSUserDefaults standardUserDefaults] objectForKey:@"Family"];

Family *family2 = [Family parseFromData:data2 error:NULL];

for (Person *p in family2.personArray) {
NSLog(@"\n============\n%@\n%d\n%d\n============",p.name,p.sex,p.age);
}
}

更多Protocol Buffers相关内容请参看:https://developers.google.com/protocol-buffers/

Protocol Buffers与JSON

Protocol Buffers的优点很明显,但也有一些缺点,因为传输时是二进制形式,导致对人的可阅读性较差,而对数据的封装也比较单一,也不支持继承等面向对象概念。

而JSON的缺点在于对应的封装数据类写起来太麻烦,要实现序列化则需要对应的数据封装类实现NSCoding协议,更是要写一些无聊的代码,所以在此推荐一个以前写的通过JSON自动生成实现了NSCoding协议的Objective-c类的工具,工具源代码https://github.com/andylee1988/JSONCreatorPlus,为方便使用,生成的代码附带以下方法。

1
2
3
- (id)initWithJson:(NSDictionary *)aDicJson;
- (NSData*)jsonData;
- (NSMutableDictionary*)dictionary;

另附使用NSKeyedArchiver做序列化的示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
+ (void)store:(id<NSCoding>)aObject to:(NSString*)strKey {
NSMutableData *mData = [[NSMutableData alloc] init];
NSKeyedArchiver *myKeyedArchiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:mData];
[myKeyedArchiver encodeObject:aObject];
[myKeyedArchiver finishEncoding];
[[NSUserDefaults standardUserDefaults] setObject:mData forKey:strKey];
[[NSUserDefaults standardUserDefaults] synchronize];
}

+ (id)getObject:(NSString*)strKey {
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:strKey];
if (data) {
NSKeyedUnarchiver *myKeyedUnarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
id aObject = [myKeyedUnarchiver decodeObject];
return aObject;
}
return nil;
}