iOS/iPhone/iPad/watchOS/tvOS/MacOSX/Android プログラミング, Objective-C, Cocoa, Swiftなど
JSON(JavaScript Object Notation)は、通信などで利用されているデータ交換フォーマットだ。人によって読み書きが容易で、かつ、計算機にとって簡単に解釈や生成が行える。また、システムの標準的なライブラリが対応していて導入が楽という利点もあり、広く利用されている。
JSONにかわるものとしてMessage Packというフォーマとがあって、コンパクトで率的に扱えるということで、自分の周りでは使われだしている。ただ、macOS/iOSプログラマーとして難点なのは複数のライブラリが存在するのだが、安心して利用できる決定打がないということだ。また、IDL (Interface Definition Language) による読み書きコードの生成の需要があるのだが、Message Packは利用側が独自に用意するしかないということだ。
IDLが利用できるデータ交換フォーマットは色々あるのだが、Googleがオープンソースとして公開してたProtocol Buffersというデータ交換フォーマットのSwiftライブラリをAppleが用意していることを知った。そこで、どのような使いごこちなのか試してみることにした。
この記事を書いている時に最新は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)")