Protobuf 的简单使用

简介

Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。

  1. 官网

     https://developers.google.com/protocol-buffers/
    
  2. Github

      https://github.com/google/protobuf
    
  3. SwiftProtobuf

      https://github.com/apple/swift-protobuf
    
  4. 参考网站:

     4.1 数据交换利器 Protobuf 技术浅析
     http://blog.jobbole.com/107405/ 
     
     4.2 swift Protobuf 
     https://www.jianshu.com/p/89efeecd5b43
     
     4.3 OC Protobuf
     https://www.jianshu.com/p/6009e96866e5
     
     4.4 Protobuf 的 proto3 与 proto2 的区别
     https://solicomo.com/network-dev/protobuf-proto3-vs-proto2.html
    

搭建环境

1、 首先我们需要在mac电脑上安装google的protobuf编译器

brew install protobuf

2、生成 protoc-gen-swift(如果是oc, 不需要此步骤)
google的编译器是不包含如何生存swift代码的,所以还需要安装一个用于生成swift代码的工具 protoc-gen-swift

$ git clone https://github.com/apple/swift-protobuf.git  // 见图2.2.1
$ cd swift-protobuf
$ git tag -l                         // 该命令将展示所有的tag_name 见图2.2.2
$ git checkout tags/[tag_name]       // checkout指定tag 见图2.2.2
$ swift build                       // build 指定代码 见图2.2.2

build 结束之后,在.build/debug目录下会生成 protoc-gen-swift 二进制文件

$ mkdir ~/bin                                   // 生成 ~/bin目录
$ cp  .build/debug/protoc-gen-swift  ~/bin      // 将protoc-gen-swift拷贝到~/bin目录下
$ vim ~/.bash_profile                           // 打开bash_profile 环境, 配置环境变量PATH
$ export PATH=/Users/yangyu/bin:$PATH           // (/Users/breeze/bin是bin对应的路径, 每个电脑的情况不同, 见图2.2.3)
$ source ~/.bash_profile 
$ protoc-gen-swift -v                           // 见图2.2.4

如果展示出版本信息,说明protoc-gen-swift配置成功;
需要注意的是版本号,如:** protoc-gen-swift 1.0.3 **,后续需要使用;

图2.2.1



图2.2.2



图2.2.3

图2.2.4


编译proto文件

1.编写proto, 具体参照官网要求

  https://developers.google.com/protocol-buffers/docs/proto3

syntax = "proto3"   //指定proto版本, 还有proto2, 不知道默认是proto2

message DBMyAlbum {
    required int64 album_id = 1;
    required string album_name = 2;
    optional string album_display_pic = 3;
    required int32 album_type = 4 [default = 0];
    repeated string album_photos_local_url = 5;

    enum AlbumType {
        NORMAL = 0;
        TRASH = 1;
        ITUNES = 2;
    }
}
  1. 编译该文件

      protoc --swift_out=. Album.proto 
    

编译失败时, 终端里会有提示对应的错误, 根据提示, 修改对应的错误.
[图片上传失败...(image-59f176-1524462266835)]

修改完成后, 代码如下, 继续编译.

syntax = "proto3";

message DBMyAlbum {
    int64 album_id = 1;
    string album_name = 2;
    string album_display_pic = 3;
    int32 album_type = 4;
    repeated string album_photos_local_url = 5;

    enum AlbumType {
        NORMAL = 0;
        TRASH = 1;
        ITUNES = 2;
    }
}

编译得到一个DBMyAlbum.pb.swift文件, 代码如下

// DO NOT EDIT.
//
// Generated by the Swift generator plugin for the protocol buffer compiler.
// Source: DBMyAlbum.proto
//
// For information on using the generated types, please see the documenation:
//   https://github.com/apple/swift-protobuf/

import Foundation
import SwiftProtobuf

// If the compiler emits an error on this type, it is because this file
// was generated by a version of the `protoc` Swift plug-in that is
// incompatible with the version of SwiftProtobuf to which you are linking.
// Please ensure that your are building against the same version of the API
// that was used to generate this file.
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
  struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
  typealias Version = _2
}

struct DBMyAlbum {
  // SwiftProtobuf.Message conformance is added in an extension below. See the
  // `Message` and `Message+*Additions` files in the SwiftProtobuf library for
  // methods supported on all messages.

  var albumID: Int64 = 0

  var albumName: String = String()

  var albumDisplayPic: String = String()

  var albumType: Int32 = 0

  var albumPhotosLocalURL: [String] = []

  var unknownFields = SwiftProtobuf.UnknownStorage()

  enum AlbumType: SwiftProtobuf.Enum {
    typealias RawValue = Int
    case normal // = 0
    case trash // = 1
    case itunes // = 2
    case UNRECOGNIZED(Int)

    init() {
      self = .normal
    }

    init?(rawValue: Int) {
      switch rawValue {
      case 0: self = .normal
      case 1: self = .trash
      case 2: self = .itunes
      default: self = .UNRECOGNIZED(rawValue)
      }
    }

    var rawValue: Int {
      switch self {
      case .normal: return 0
      case .trash: return 1
      case .itunes: return 2
      case .UNRECOGNIZED(let i): return i
      }
    }

  }

  init() {}
}

// MARK: - Code below here is support for the SwiftProtobuf runtime.

extension DBMyAlbum: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
  static let protoMessageName: String = "DBMyAlbum"
  static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
    1: .standard(proto: "album_id"),
    2: .standard(proto: "album_name"),
    3: .standard(proto: "album_display_pic"),
    4: .standard(proto: "album_type"),
    5: .standard(proto: "album_photos_local_url"),
  ]

  mutating func decodeMessage(decoder: inout D) throws {
    while let fieldNumber = try decoder.nextFieldNumber() {
      switch fieldNumber {
      case 1: try decoder.decodeSingularInt64Field(value: &self.albumID)
      case 2: try decoder.decodeSingularStringField(value: &self.albumName)
      case 3: try decoder.decodeSingularStringField(value: &self.albumDisplayPic)
      case 4: try decoder.decodeSingularInt32Field(value: &self.albumType)
      case 5: try decoder.decodeRepeatedStringField(value: &self.albumPhotosLocalURL)
      default: break
      }
    }
  }

  func traverse(visitor: inout V) throws {
    if self.albumID != 0 {
      try visitor.visitSingularInt64Field(value: self.albumID, fieldNumber: 1)
    }
    if !self.albumName.isEmpty {
      try visitor.visitSingularStringField(value: self.albumName, fieldNumber: 2)
    }
    if !self.albumDisplayPic.isEmpty {
      try visitor.visitSingularStringField(value: self.albumDisplayPic, fieldNumber: 3)
    }
    if self.albumType != 0 {
      try visitor.visitSingularInt32Field(value: self.albumType, fieldNumber: 4)
    }
    if !self.albumPhotosLocalURL.isEmpty {
      try visitor.visitRepeatedStringField(value: self.albumPhotosLocalURL, fieldNumber: 5)
    }
    try unknownFields.traverse(visitor: &visitor)
  }

  func _protobuf_generated_isEqualTo(other: DBMyAlbum) -> Bool {
    if self.albumID != other.albumID {return false}
    if self.albumName != other.albumName {return false}
    if self.albumDisplayPic != other.albumDisplayPic {return false}
    if self.albumType != other.albumType {return false}
    if self.albumPhotosLocalURL != other.albumPhotosLocalURL {return false}
    if unknownFields != other.unknownFields {return false}
    return true
  }
}

extension DBMyAlbum.AlbumType: SwiftProtobuf._ProtoNameProviding {
  static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
    0: .same(proto: "NORMAL"),
    1: .same(proto: "TRASH"),
    2: .same(proto: "ITUNES"),
  ]
}

注意点: _ 的书写方式在编译后变成了驼峰.

在项目中使用protobuf

  1. 把编译的 DBMyAlbum.pb.swift 文件, 导入到项目中.

  2. 导入SwiftProtobuf, 版本号需和protoc-gen-swift -v里面的版本号一致

     pod 'SwiftProtobuf', '~> 1.0.3'
    
  3. 使用

     var album = DBMyAlbum()
     
     album.albumID = 1;
     album.albumName = "Live Photo"
     album.albumDisplayPic = "displayPic"![[email protected]](https://upload-images.jianshu.io/upload_images/1792156-1e32b64f9f0f43df.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
     album.albumType = Int32(DBMyAlbum.AlbumType.normal.rawValue)
     album.albumPhotosLocalURL .append("/tmp/abc.png")
     
     guard let data = try? album.serializedData() else { return }
     print("-------data------")
     print(data)
     
     guard let jsonData = try? album.jsonUTF8Data() else { return }
     print("-------jsonData------")
     print(jsonData)
     
     guard let album2 = try? DBMyAlbum(serializedData: data) else { return }
     print("-------album2------")
     print(album2.albumID)
     print(album2.albumDisplayPic)
    

你可能感兴趣的:(Protobuf 的简单使用)