iOS Protobuf的使用

494 阅读4分钟

Protobuf

Protobuf 即 google protocol buffer 是一种数据封装格式协议,是google推出

的一种语言无关、平台无关、扩展性好的用于通信协议、数据存储的结构化数据串行化方法。支持

C++、Python、Java三种语言。

1、安装 Protobuf 工具

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

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

检查是否安装成功:

protoc --version

protoc-gen-swift --version

2、创建 .proto 文件

// 使用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;

}

3、proto文件 转化成objc文件

在桌面上建立两个文件夹,一个叫protofile,一个叫objcfile

然后将创建好的person.proto放进protofile文件夹,然后

cd Desktop

在终端输入:

protoc --proto_path=protofile --objc_out=objcfile message.proto
protoc --proto_path=protofile --swift_out=objcfile message.proto

然后成功在objcfile里得到我们要的文件 这将在当前目录下生成Message.pbobjc.h和Message.pbobjc.m文件。

4、在 iOS 工程中的使用

工程添加依赖

pod 'Protobuf'          // OC和其他多种语言的能力依赖

pod 'SwiftProtobuf'     // swift能力依赖

将生成的.pbobjc.h和.pbobjc.m文件添加到你的Xcode项目中。

导入模型头文件

#import "Message.pbobjc.h"

导入工程中,这两个文件是采用的手动引用计数,因此在加入项目后需要设置它们的编译参数。

在工程target->Build Phrases->Compile Sources->给Person.pbobjc.m设置-fno-objc-arc.

image.png

使用生成的类构建请求并发送
在你的iOS应用中,使用这些类来构建请求并发送到服务器。这里是一个使用URLSession发送protobuf请求的示例:

#import "Message.pbobjc.h"
 
// 创建消息实例并填充数据
MyRequest *request = [MyRequest message];
request.name = @"John Doe";
request.id = 123;
 
// 将消息序列化为Data对象
NSData *data = [request data];
 
// 创建URLRequest并设置HTTP方法、URL和HTTPBody
NSMutableURLRequest *requestObj = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://yourserver.com/api"]];
[requestObj setHTTPMethod:@"POST"];
[requestObj setHTTPBody:data];
[requestObj setValue:@"application/x-protobuf" forHTTPHeaderField:@"Content-Type"];
 
// 使用URLSession发送请求
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:requestObj completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
    if (error) {
        NSLog(@"Error: %@", error);
    } else {
        // 处理响应数据...
        NSLog(@"Response received");
    }
}];
[dataTask resume];

处理服务器响应(可选)

如果服务器返回了protobuf格式的数据,你可以使用相同的方式解析这些数据:

// 假设这是从服务器接收到的数据(NSData类型)
NSData *responseData = ...; // 从服务器响应中获取的数据
MyResponse *response = [MyResponse parseFromData:responseData error:nil]; // 假设MyResponse是对应的protobuf类
if (response) {
    // 处理解析后的数据...
} else {
    NSLog(@"Failed to parse response");
}

`` /* { "title": "test", "tag": 1, "request": { "url": "www.fivehow.com" }, "values": ["value1", "value2"] } */

// ProtoBuf data

WHTest *test = [[WHTest alloc] init];
test.title = @"test";
test.tag = 1;
test.valuesArray = [NSMutableArray
                    arrayWithObjects:@"value1", @"value2", nil];
WHRequest *request = [[WHRequest alloc] init];
request.URL = @"www.fivehow.com";
test.request = request;
NSData *protoBufData = [test data];

// Json Data

NSString* jsonStr = @"{\"title\":\"test\", \"tag\":1, \"request\":{\"url\":\"www.fivehow.com\"},\"values\":[\"value1\", \"value2\"]}";
NSData* jsonData = [jsonStr dataUsingEncoding:(NSUTF8StringEncoding)];

// 对比 data length

NSLog(@"protoBufData: %ld", protoBufData.length);   // 43
NSLog(@"jsonData: %ld", jsonData.length);           // 92`
在iOS应用中使用protobuf来发送和接收数据。确保你的服务器端也支持protobuf,并且正确配置了相应的服务接口来处理protobuf格式的数据。

swift

跟正常使用某个类的方法一样。

/* { "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=10.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

使用protobuf发起请求

请求行和请求头与普通Http请求一致

请求体可使用protobuf方式生成二进制数据,设置到请求体中


let data = try? requestMessage.serializedData() request.httpBody = data

guard let url = URL(string: "xxx.com/api/room/en…") else { return } var request = URLRequest(url: url) // 设置请求行 request.httpMethod = "POST" // 设置请求头 request.setValue("application/x-protobuf", forHTTPHeaderField: "Content-Type") // 构造请求体 let requestMessage = YCRequest.with { request in request.anchorID = 2118859354127 request.roomID = 1978193384833024376 } let data = try? requestMessage.serializedData() request.httpBody = data let task = URLSession.shared.dataTask(with: request) { data, response, error in } task.resume()


 解析数据
 
 使用protobuf 自带的数据解析,可完成 二进制数据 -> 模型数据 映射

let responseMessage = try? Room(serializedData: data) guard let responseMessage else { print("Failed to decode response.") return } print("Server response: (responseMessage)")