ios开发Protobuf入门到精通

  之前公司的app中的埋点数据传输是通过json进行传输的,对流量消耗比较大,考虑到降低流量消耗的要求,决定用Protobuf对传输的数据进行压缩处理。主要是考虑到Protobuf应用比较广泛,而且一直有谷歌在维护。中途停止维护的可能性较小。下面来和大家介绍一下Protobuf。注:这篇博客是去年写的没写完,今天接着写一下。由于本人主要从事iOS开发,今天主要以oc语言为例来进行说明

Protocol Buffer简介

  Protocolbuffer(简称Protobuf或PB)是由Google推出的一种数据交换格式,它独立于语言,独立于平台。Google 提供了三种语言的实现:java、c++ 和 python,每一种实现都包含了相应语言的编译器以及库文件。可以把它用于分布式应用之间的数据通信或者异构环境下的数据交换。与传统的XML和JSON不同的是,它是一种二进制格式,免去了文本格式转换的各种困扰,并且转换效率非常快,由于它的跨平台、跨编程语言的特点,让它越来越普及,尤其是网络数据交换方面日趋成为一种主流。

PB目前托管在GitHub,链接地址:https://github.com/google/protobuf 大家可以在这个地址下载最新版本的protobuf进行安装。

注意:建议大家使用的时候尽量使用官方的protobuf库。

PB环境的安装

https://github.com/google/protobuf/releases下载protocolBuffer对应版本编译器包,比如目前的对应的objc最新版本
解压包,假设解压后的文件夹名为: protobuf-objectivec-3.6.0,
    打开终端,进入文件夹protobuf-objectivec-3.6.0, 依次执行以下命令:

./configure
make
make check
sudo make install

亲自测试过了,可以的哦
在protobuf-objectivec-3.6.0目录下找到objectivec文件夹
将该文件夹下的.h,.m文件导入到项目中即可。当然了测试文件除外。

PB的语法

1,字段限制

字段限制共有3类:
required:必须赋值的字段
optional:可有可无的字段
repeated:可重复字段(变长字段),类似于数组
由于一些历史原因,repeated字段并没有想象中那么高效,新版本中允许使用特殊的选项来获得更高效的编码:

repeated int32 samples = 4 [packed=true];

例子如下:

message SearchRequest 
{
  required string query = 1;
  optional int32 page_number = 2;// Which page number do we want?
  optional int32 result_per_page = 3;// Number of results to return per page.
}

2,tags

  在上面的例子中我们看到每一个字段都有一个独一无二的数值类型的tag,其中1~15
使用一个字节编码,16~2047使用2个字节编码,所以应该将Tags 1到15留给频繁使用的字段.可以指定的最小的Tag为1, 最大为2^{29}-1或536,870,911.但是不能使用19000到19999之间的值,这些值是预留给protocol buffer的.

3,注释

在上面的例子中,我们看到可以直接使用双斜杠 //来进行注释。

4,可选字段与缺省值

  在消息解析时,如果发现消息中没有包含可选字段,此时会将消息解析对象中相对应的字段设置为默认值,可以通过下面的语法为optional字段设置默认值:

optional int32 result_per_page = 3 [default = 10];

如果没有指定默认值,则会使用系统默认值,对于string默认值为空字符串,对于bool默认值为false,对于数值类型默认值为0,对于enum默认值为定义中的第一个元素.

5,枚举

message SearchRequest 
{
  required string query = 1;
  optional int32 page_number = 2;
  optional int32 result_per_page = 3 [default = 10];
  enum Corpus 
  {
    UNIVERSAL = 0;
    WEB = 1;
    IMAGES = 2;
    LOCAL = 3;
    NEWS = 4;
    PRODUCTS = 5;
    VIDEO = 6;
  }
  optional Corpus corpus = 4 [default = UNIVERSAL];
}

由于枚举值采用varint编码,所以为了提高效率,不建议枚举值取负数.这些枚举值可以在其他消息定义中重复使用.

6,使用其他消息类型

可以使用一个消息的定义作为另一个消息的字段类型.

message Result 
{
  required string url = 1;
  optional string title = 2;
  repeated string snippets = 3;
}

message SearchResponse 
{
  repeated Result result = 1;
}

可以使用import语法来包含另外一个.proto文件.

import "myproject/other_protos.proto";

7,嵌套类型

在protocol中可以定义如下的嵌套类型

message SearchResponse 
{
  message Result 
  {
    required string url = 1;
    optional string title = 2;
    repeated string snippets = 3;
  }
  repeated Result result = 1;
}

8,更新一个数据类型

在更新一个数据类型时更多的是需要考虑与旧版本的兼容性问题:

不要改变任何已存在字段的Tag值,如果改变Tag值可能会导致数值类型不匹配,具体原因参考protocol编码原理
建议使用optional和repeated字段限制,尽可能的减少required的使用.
不需要的字段可以删除,删除字段的Tag不应该在新的消息定义中使用.
不需要的字段可以转换为扩展,反之亦然只要类型和数值依然保留
int32, uint32, int64, uint64, 和bool是相互兼容的,这意味着可以将其中一种类型任意改编为另外一种类型而不会产生任何问题
sint32 和 sint64是相互兼容的
string 和 bytes是相互兼容的
fixed32 兼容 sfixed32, fixed64 兼容 sfixed64.
optional 兼容repeated

9,扩展

extend特性来让你声明一些Tags值来供第三方扩展使用.

message Foo 
{
  // ...
  extensions 100 to 199;
}

假如你在你的proto文件中定义了上述消息,之后别人在他的.proto文件中import你的.proto文件,就可以使用你指定的Tag范围的值.

extend Foo 
{
  optional int32 bar = 126;
}

10,生成源代码文件

protoc --plugin=/usr/local/bin/protoc-gen-objc SearchRequest.proto --objc_out="./"

后续还会持续完善。。。

参考博客如下:
https://www.jianshu.com/p/b1f18240f0c7
https://www.jianshu.com/p/8c6c009bc500

更多优质文章,可以微信扫码关注:
这里写图片描述

猜你喜欢

转载自blog.csdn.net/hhl110120/article/details/78440514