Posted at

[cocoa][swift]Swift Protobufについて

JSON(JavaScript Object Notation)は、通信などで利用されているデータ交換フォーマットだ。人によって読み書きが容易で、かつ、計算機にとって簡単に解釈や生成が行える。また、システムの標準的なライブラリが対応していて導入が楽という利点もあり、広く利用されている。

JSONにかわるものとしてMessage Packというフォーマとがあって、コンパクトで率的に扱えるということで、自分の周りでは使われだしている。ただ、macOS/iOSプログラマーとして難点なのは複数のライブラリが存在するのだが、安心して利用できる決定打がないということだ。また、IDL (Interface Definition Language) による読み書きコードの生成の需要があるのだが、Message Packは利用側が独自に用意するしかないということだ。

IDLが利用できるデータ交換フォーマットは色々あるのだが、Googleがオープンソースとして公開してたProtocol Buffersというデータ交換フォーマットのSwiftライブラリをAppleが用意していることを知った。そこで、どのような使いごこちなのか試してみることにした。


導入方法

本家/a>から入手して、自分でビルドする方法もあるが、以下からバイナリを取得する。

この記事を書いている時に最新はProtocol Buffers v3.6.1なので、protoc-3.6.1-osx-x86_64.zip をダウンロドする。

これを例えば、~/binにコピーして、~/.bash_profileなどでパスを通しておく。

PATH="$HOME/bin/protoc-3/bin:$HOME/bin:$PATH"

次に、Swift Protobuf プラグインを組み込む。

最も手軽な方法は、Homebrewだと思う。

$ brew install swift-protobuf

でも、今回はgithubからクローンするやり方を選んだ。

$ git clone https://github.com/apple/swift-protobuf.git

$ cd swift-protobuf

リリース・バージョンを確認する。

$ git tag -l

この記事を書いている時に最新だった1.3.1を選んでビルドする。

$ git checkout tags/1.3.1

$ swift build -c release -Xswiftc -static-stdlib

.build/release に、protoc-gen-swift というファイルが生成されているので、これを例えば ~/bin にコピーする。

以下のようなprotoファイル"my.proto"を用意する。

syntax = "proto3";


message BookInfo {
int64 id = 1;
string title = 2;
string author = 3;
}

これを以下のコマンドでswiftコードに変換する。

$ protoc --swift_out=. my.proto

my.pb.swift というファイルが生成されているはずだ。

次に、自分のXcodeプロジェクトに組み込む。

CocoaPodsやCarthageを利用する方法があるが、ここでは、Swift ProtobufのXcodeプロジェクトを自分のXcodeプロジェクトに組み込む方法でやることにする。

自分のXcodeプロジェクトに組み込むと、TARGETSのBuild PhasesのTarget DependencesにmacOS/iOS/tvOS/watchOS毎に追加できるようになっているので、必要なものを追加する。

そして、先ほど、生成した my.pb.swift を追加する。

すると、以下のように呼び出せるはずだ。

// Create a BookInfo object and populate it:

var info = BookInfo()
info.id = 1734
info.title = "Really Interesting Book"
info.author = "Jane Smith"

// As above, but generating a read-only value:
let info2 = BookInfo.with {
$0.id = 1735
$0.title = "Even More Interesting"
$0.author = "Jane Q. Smith"
}
print("\(info2)")

// Serialize to binary protobuf format:
let binaryData: Data = try! info.serializedData()

// Deserialize a received Data object from `binaryData`
let decodedInfo = try! BookInfo(serializedData: binaryData)
print("\(decodedInfo)")

// Serialize to JSON format as a Data object
let jsonData: Data = try! info.jsonUTF8Data()

// Deserialize from JSON format from `jsonData`
let receivedFromJSON = try! BookInfo(jsonUTF8Data: jsonData)
print("\(receivedFromJSON)")

【関連情報】

Cocoa Advent Calendar 2018


Cocoa.swift 2019-01


Cocoa.swift


Cocoa勉強会 関東


Cocoa練習帳


Qiita