JSON
Swift
Xcode8
swift3

SwiftyJSONをSwift3で使う

More than 1 year has passed since last update.

--> 2016/09/25追記

本家がSwift3に対応しました🎉

ご利用の際はぜひこちらを

Release Swift 3 Xcode 8 Support · SwiftyJSON/SwiftyJSON

(この記事よりもっとちゃんと綺麗に丁寧に直されてました:-P)


背景

iOSアプリを急遽Swift3化して審査に出さなくてはならなくなったのですが、アプリで使ってるSwiftyJSONがSwift3に対応していなかったのでSwift3化してみたメモ。

SwiftyJSONは現在(2016/9/16)swift3ブランチはあるもののcommitが3ヶ月前と古くてそのままでは使えず。またXcode8に対応したとするPRはあるものの、本当に使えるのかわからなかったので取り急ぎ自分でもSwift3化してみることにしました。


修正箇所


privateをfileprivateに変更

before

private var rawArray: [AnyObject] = []

private var rawDictionary: [String : AnyObject] = [:]
private var rawString: String = ""
private var rawNumber: NSNumber = 0
private var rawNull: NSNull = NSNull()

after

fileprivate var rawArray: [Any] = []

fileprivate var rawDictionary: [String : Any] = [:]
fileprivate var rawString: String = ""
fileprivate var rawNumber: NSNumber = 0
fileprivate var rawNull: NSNull = NSNull()

初めてSwiftのprivateが同じファイル内からアクセス可能だと知ったときはビビりましたが、extensionとかで使うときは便利なんだよな〜ということで気持ち悪さを感じつつも使っていましたprivate。

それがSwift3からは下記のようになってすっきりしました。


  • private: Javaなど他の言語と同様のスコープ

  • fileprivate: Swiftの旧privateと同じファイル内で有効なスコープ

cf. SE-0025 Scoped Access Level

今回は動作を変えないよう、旧privateをfileprivateにそのまま書き換えました。

(privateに絞れるものがあればprivateに絞っても良いですね)


関数からプロパティになったので()を削除

before

if decimal == NSDecimalNumber.notANumber() {  // indicates parse error

return NSDecimalNumber.zero()

after

if decimal == NSDecimalNumber.notANumber {  // indicates parse error

return NSDecimalNumber.zero

もともと関数で定義されていたのがプロパティーになってたので削除(この変更の原典ってなんだろう)。


AnyObjectからAnyへ

before

let object: AnyObject = try JSONSerialization.jsonObject(with: data, options: opt)

after

let object: Any = try JSONSerialization.jsonObject(with: data, options: opt)

これはObjective-Cのid型をSwiftで扱う際に、AnyObjectではなくAnyで扱うようになった影響ですね。

AnyObjectは参照型の型全般を表すもの、Anyは値型、参照型含めた型全般を表するものですが、SwiftではStringやArrayなどが値型になっているのでそれらとの相互運用をしやすくするための変更のようです。

JSONSerialization.jsonObjectでJSONデータからobjectを作る際に返す型がAnyObjectからAnyになったので、その関連部分もすべて型をAnyに差し替えました。

cf. SE-0116 Import Objective-C id as Swift Any type


whereを,に変更

before

if let errorValue = error where errorValue.code == ErrorNotExist{

after

if let errorValue = error, errorValue.code == ErrorNotExist{

if文の中などで複数の条件節がある場合の曖昧さをなくすために書き方が変わったようです。

cf. SE-0099 Restructuring Condition Clauses


Booleanプロトコルへの適合部分を削除

before

extension JSON: Swift.Boolean {

after

extension JSON {

Booleanプロトコルが廃止されたことによる影響です。

歴史的な経緯で他のいろんな型の値をBooleanとして使ってるけど良くないのでBoolだけにしようぜということらしい。

コンパイルを通すためにBooleanプロトコルに適合させる部分だけ削除したけど本当はこのextension自体削除した方がいいのだろうか・・・?

cf. SE-0109 Remove the Boolean protocol


まとめ

ということで一応使えるようになった&Swift3の変更点の勉強になってよかった。

問題ありそうなところありましたらご指摘いただけると嬉しいです。

※Testとかまで直して確認してないので動作保証はできませんm(_ _)m


作業環境

Xcode: Version 8.0 (8A218a)

Folkした状態のまんまのswift3ブランチ

https://github.com/jollyjoester/SwiftyJSON/tree/swift3

Xcode8.0でビルドできるようにしたブランチ

https://github.com/jollyjoester/SwiftyJSON/tree/swift3-new

上記の差分

https://github.com/SwiftyJSON/SwiftyJSON/compare/swift3...jollyjoester:swift3-new?expand=1