• swift使用swift-protobuf协议通讯,使用指北


    什么是Protobuf

    Protobuf(Protocol Buffers)协议😉 Protobuf 是一种由 Google 开发的二进制序列化格式和相关的技术,它用于高效地序列化和反序列化结构化数据,通常用于网络通信、数据存储等场景。

    为什么要使用Protobuf? 因为快

    其实 Protobuf 在许多领域都得到了广泛应用,特别是在分布式系统、RPC(Remote Procedure Call)框架和数据存储中,它提供了一种高效、简洁和可扩展的方式来序列化和交换数据,

    Protobuf 的主要优点包括:

    高效性:Protobuf 序列化后的二进制数据通常比其他序列化格式(比如超级常用的JSON)更小,并且序列化和反序列化的速度更快,这对于性能敏感的应用非常有益。
    简洁性:Protobuf 使用一种定义消息格式的语法,它允许定义字段类型、顺序和规则(消息结构更加清晰和简洁)
    版本兼容性:Protobuf 支持向前和向后兼容的版本控制,使得在消息格式发生变化时可以更容易地处理不同版本的通信。
    语言无关性:Protobuf 定义的消息格式可以在多种编程语言中使用,这有助于跨语言的通信和数据交换(截至本文发布目前官方支持的有C++/C#/Dart/Go/Java/Kotlin/python/Swift)
    自动生成代码:Protobuf 通常与相应的工具一起使用,可以自动生成代码,包括序列化/反序列化代码和相关的类(减少了手动编写代码的工作量,提高效率)

    安装编译器

    注意:需要swift5.8以上的版本和xcode14.3以后的版本才可以

    你也可以通过命令行使用 swift --version 命令来查看安装的Swift版本。这将会输出类似于下面的信息,显示当前安装的Swift编译器的版本:

    安装swift-protobuf:这条命令将会给你的电脑上安装 protoc 和 Swift 代码生成器插件。

    brew install swift-protobuf

    根据官方文档可以使用brew安装:

    安装完之后,输入protoc将会出现提示:

    编译Proto文件

    将.proto文件编译为swift代码:--swift_out=. 表示将生成的文件放在当前文件夹中

    protoc --swift_out=. my.proto

    运行之后,就会出现一个GameMsg.pb.swift文件,这就是编译后的swift文件:

    生成的代码将为每个 proto 字段公开一个 Swift 属性以及一组序列化和反序列化功能。假如你的proto文件内容是:

    1. syntax = "proto3";
    2. message BookInfo {
    3. int64 id = 1;
    4. string title = 2;
    5. string author = 3;
    6. }

    那么生成的swift代码:

    1. // DO NOT EDIT.
    2. // swift-format-ignore-file
    3. //
    4. // Generated by the Swift generator plugin for the protocol buffer compiler.
    5. // Source: game.proto
    6. //
    7. // For information on using the generated types, please see the documentation:
    8. // https://github.com/apple/swift-protobuf/
    9. import Foundation
    10. import SwiftProtobuf
    11. // If the compiler emits an error on this type, it is because this file
    12. // was generated by a version of the `protoc` Swift plug-in that is
    13. // incompatible with the version of SwiftProtobuf to which you are linking.
    14. // Please ensure that you are building against the same version of the API
    15. // that was used to generate this file.
    16. fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
    17. struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
    18. typealias Version = _2
    19. }
    20. struct BookInfo {
    21. // SwiftProtobuf.Message conformance is added in an extension below. See the
    22. // `Message` and `Message+*Additions` files in the SwiftProtobuf library for
    23. // methods supported on all messages.
    24. var id: Int64 = 0
    25. var title: String = String()
    26. var author: String = String()
    27. var unknownFields = SwiftProtobuf.UnknownStorage()
    28. init() {}
    29. }
    30. #if swift(>=5.5) && canImport(_Concurrency)
    31. extension BookInfo: @unchecked Sendable {}
    32. #endif // swift(>=5.5) && canImport(_Concurrency)
    33. // MARK: - Code below here is support for the SwiftProtobuf runtime.
    34. extension BookInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
    35. static let protoMessageName: String = "BookInfo"
    36. static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
    37. 1: .same(proto: "id"),
    38. 2: .same(proto: "title"),
    39. 3: .same(proto: "author"),
    40. ]
    41. mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
    42. while let fieldNumber = try decoder.nextFieldNumber() {
    43. // The use of inline closures is to circumvent an issue where the compiler
    44. // allocates stack space for every case branch when no optimizations are
    45. // enabled. https://github.com/apple/swift-protobuf/issues/1034
    46. switch fieldNumber {
    47. case 1: try { try decoder.decodeSingularInt64Field(value: &self.id) }()
    48. case 2: try { try decoder.decodeSingularStringField(value: &self.title) }()
    49. case 3: try { try decoder.decodeSingularStringField(value: &self.author) }()
    50. default: break
    51. }
    52. }
    53. }
    54. func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
    55. if self.id != 0 {
    56. try visitor.visitSingularInt64Field(value: self.id, fieldNumber: 1)
    57. }
    58. if !self.title.isEmpty {
    59. try visitor.visitSingularStringField(value: self.title, fieldNumber: 2)
    60. }
    61. if !self.author.isEmpty {
    62. try visitor.visitSingularStringField(value: self.author, fieldNumber: 3)
    63. }
    64. try unknownFields.traverse(visitor: &visitor)
    65. }
    66. static func ==(lhs: BookInfo, rhs: BookInfo) -> Bool {
    67. if lhs.id != rhs.id {return false}
    68. if lhs.title != rhs.title {return false}
    69. if lhs.author != rhs.author {return false}
    70. if lhs.unknownFields != rhs.unknownFields {return false}
    71. return true
    72. }
    73. }

    在项目中使用的话:

    1. // 创建一个BookInfo对象,并给它赋值
    2. var info = BookInfo()
    3. info.id = 1734
    4. info.title = "Really Interesting Book"
    5. info.author = "Jane Smith"
    6. // 如上所述,但生成只读值:
    7. let info2 = BookInfo.with {
    8. $0.id = 1735
    9. $0.title = "Even More Interesting"
    10. $0.author = "Jane Q. Smith"
    11. }
    12. // 序列化为二进制protobuf格式:可以选择序列化为
    13. // 符合SwiftProtobufContiqueBytes的任何类型。例如
    14. let binaryData: Data = try info.serializedBytes()
    15. let binaryDataAsBytes: [UInt8] = try info.serializedBytes()
    16. // 从`binaryData反序列化接收到的Data对象`
    17. let decodedInfo = try BookInfo(serializedData: binaryData)
    18. // 反序列化从`binaryDataAsBytes接收的[UInt8]对象`
    19. let decodedInfo = try BookInfo(serializedBytes: binaryDataAsBytes)
    20. //序列化为JSON格式的数据对象,或符合
    21. //SwiftProtobufContiqueBytes。例如
    22. let jsonData: Data = try info.jsonUTF8Data()
    23. let jsonBytes: [UInt8] = try info.jsonUTF8Bytes()
    24. // 从`jsonBytes从JSON格式反序列化`
    25. let receivedFromJSON = try BookInfo(jsonUTF8Bytes: jsonBytes)

    添加SwiftProtobuf到你的项目中

    要想使用Protobuf还需要在你的项目中添加SwiftProtobuf,可以使用SPM添加或者使用CocoaPods添加,我这里习惯使用SPM,在xcode项目中可以直接右键添加包就可以了:

    添加之后就可以在左侧项目的依赖包里面显示出来了:

    解决遇到的问题

    1.如果你在finder中在proto文件夹中生成swift代码,但是当你会到xcode总,发现proto文件夹中不一定会显示proto文件和生成的swift文件:

    需要在xcode中手动添加文件到文件夹中:

    再回到项目文件夹就可以看到了:

    2.但是这个时候,当你打开生成的swift文件,可能发现报错了:

    Could not find module 'SwiftProtobuf' for target 'arm64-apple-watchos'; found: arm64_32-apple-watchos, at: /Users/song/Library/Developer/Xcode/DerivedData/mywatch-coaeflxmpfflredurreogfyfvbxz/Index.noindex/Build/Products/Debug-watchos/SwiftProtobuf.swiftmodule 

    这是因为你没有将 SwiftProtobuf 真正添加到项目中:

    需要你手动再将依赖添加到项目中

    就不会报错了:

    简单的DEMO

    我写了一个简单的Demo:

    1. //
    2. // ContentView.swift
    3. // mywatch Watch App
    4. //
    5. // Created by song on 2024/6/19.
    6. //
    7. import SwiftUI
    8. struct ContentView: View {
    9. // Create a BookInfo object and populate it:
    10. @State var info = BookInfo()
    11. // binaryData
    12. @State var binaryData: Data = .init()
    13. // binaryInfo
    14. @State var binaryInfo: BookInfo = .init()
    15. var body: some View {
    16. VStack {
    17. Text(info.author)
    18. Text("Hello, 1024小神!")
    19. Button(action: {
    20. info.id = 1734
    21. info.title = "Really Interesting Book"
    22. info.author = "Jane Smith"
    23. }, label: {
    24. Text("编辑")
    25. })
    26. Button(action: {
    27. binaryData = try! info.serializedData()
    28. print("二进制数据:\(binaryData)")
    29. }, label: {
    30. Text("序列化")
    31. })
    32. Button(action: {
    33. binaryInfo = try! BookInfo(serializedData: binaryData)
    34. print("反序列化数据:\(binaryInfo)")
    35. }, label: {
    36. Text("反序列化")
    37. })
    38. }
    39. .padding()
    40. }
    41. }
    42. #Preview {
    43. ContentView()
    44. }

     可以实现协议消息的序列化和反序列化:

  • 相关阅读:
    抽象工厂模式
    基于ReadWriteLock的全局安全缓存实现
    kkFileView getCorsFile 任意文件读取漏洞(CVE-2021-43734)
    postgresql 主备配置
    【无人机】基于A星算法解决无人机二维路径规划问题含matlab代码
    操作系统(2)进程管理(上)进程与线程
    Cesium快速上手0-Cesium安装与基本介绍
    ComText让机器人有了情节记忆
    设计模式之观察者模式
    1671. 得到山形数组的最少删除次数-c语言dp算法加前序后序遍历求解-双百代码
  • 原文地址:https://blog.csdn.net/weixin_44786530/article/details/139806765