快速上手 iOS Protocol Buffer | 来自缤纷多彩的灰

快速上手 iOS Protocol Buffer @ WHlcj | 2024-07-04T21:53:04+08:00 | 3 分钟阅读

本文主要介绍在 iOS 开发中如何快速上手使用 Protobuf。更多关于 Protobuf 的介绍和相关的功能 api,读者可自行查阅官网

Protocol Buffer(简称 Protobuf)是一种由Google开发的语言中立、平台无关的序列化数据结构的方法。它允许你定义结构化的数据,并提供一种高效且灵活的方式进行数据序列化和反序列化。

安装 Protobuf 工具

最简单的方式是直接通过 brew 进行安装:

1
2
brew install protobuf           // 支持生成.h和.m文件,和其他多种语言的文件
brew install swift-protobuf     // 支持生成.swift文件

检查是否安装成功:

1
2
protoc --version
protoc-gen-swift --version

brew 进行下载安装的缺点是,通常只能安装最新几个版本的目标工程。若安装指定版本的 protobuf 可按照以下流程(以安装3.20.0为例):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 从github下载目标版本的压缩包
 curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v3.20.0/protobuf-all-3.20.0.tar.gz
# 解压目标文件
tar -xzvf protobuf-3.20.0.tar.gz
# 打开目标文件夹
cd protobuf-3.20.0
# 检测系统环境(如编译器、库、头文件等)
# 设置编译选项和路径
# 生成用于编译的 Makefile
./configure --prefix=/usr/local
make                # 根据生成的 Makefile,编译源码生成可执行文件和库文件
make check          # 可选
sudo make install   #将编译生成的文件复制到指定的安装路径
# 最后检查是否安装成功
protoc --version

创建 .proto 文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// 使用V3语法
syntax = "proto3"

// OC语言可选,添加模型文件前缀
option objc_class_prefix = "MY"

// message代表一个模型
message Test {
    string title = 1;
    int32 tag = 2;
    Request request = 3;        // 自定义的 Request 类型
    repeated string values = 4; // 数组
}

message Request {
    string url = 1;
}

OC、Swift 代码生成

Protobuf 提供api用于根据.proto文件生成代码,需传入两个参数,生成结果与参数的传入顺序无关:

  1. .proto 文件的路径(下文中用 source_path 表示)
  2. 需要生成的目标语言(下文用 target_language 表示)以及文件的输出路径(下文用 target_path 表示)
1
protoc source_path/xxx.proto --target_language_out=target_path

eg:

1
2
protoc --objc_out=. xxx.proto      // 在当前文件夹根据xxx.proto生成.h和.m文件
protoc xxx.proto --swift_out=.     // 在当前文件夹根据xxx.proto生成.swift文件

在 iOS 工程中的使用

  1. 工程添加依赖
1
2
pod 'Protobuf'          // OC和其他多种语言的能力依赖
pod 'SwiftProtobuf'     // swift能力依赖
  1. 把转换后的代码文件加入到工程。
  2. 跟正常使用某个类的方法一样。
  • Swift eg:
 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
/*
 {
     "title": "test",
     "tag": 1,
     "request": {
         "url": "www.fivehow.com"
     },
     "values": ["value1", "value2"]
 }
 */

let request = Request.with { $0.url = "www.whlcj.github.io" }
// ProtoBuf data
let test = Test.with {
    $0.title = "test"
    $0.tag = 1
    $0.request = request
    $0.values = ["value1", "value2"]
}
let binaryData = try? test.serializedData()
guard let binaryData = binaryData else { return }
_ = try? Test(serializedData: binaryData)
// Json Data
let jsonStr = "{\"title\":\"test\", \"tag\":1, \"request\":{\"url\":\"www.whlcj.github.io\"},\"values\":[\"value1\", \"value2\"]}"
let jsonStrData = jsonStr.data(using: .utf8)
// 对比 data length
print("binaryData: \(binaryData.count)")            // 43
guard let jsonStrData = jsonStrData else { return }
print("jsonStrData: \(jsonStrData.count)")          // 92
  • Objective-C eg:
 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
/*
 {
     "title": "test",
     "tag": 1,
     "request": {
         "url": "www.fivehow.com"
     },
     "values": ["value1", "value2"]
 }
 */

// ProtoBuf data
MYTest *test = [[MYTest alloc] init];
test.title = @"test";
test.tag = 1;
test.valuesArray = [NSMutableArray arrayWithObjects:@"value1", @"value2", nil];
MYRequest *request = [[MYRequest alloc] init];
request.URL = @"www.whlcj.github.io";
test.request = request;
NSData *protoBufData = [test data];
// Json Data
NSString* jsonStr = @"{\"title\":\"test\", \"tag\":1, \"request\":{\"url\":\"www.whlcj.github.io\"},\"values\":[\"value1\", \"value2\"]}";
NSData* jsonData = [jsonStr dataUsingEncoding:(NSUTF8StringEncoding)];
// 对比 data length
NSLog(@"protoBufData: %ld", protoBufData.length);   // 43
NSLog(@"jsonData: %ld", jsonData.length);           // 92