post Image
Swift3対応をしてハマった不具合

お久しぶりです。最近ウスネオイデスの育成にハマってます
仕事でSwift3対応をして出会ったいくつかの不具合をまとめました。
もしこれからSwift3対応するぞー!っていう人がいれば参考になればと思います。

DeviceTokenの取得方法が変わった

まずはこれです。Swift3対応をしたら必ずと言っていいほど出会うのでないでしょうか
Swift2系まではこんな感じで取得していたdeviceTokenですが

let token = (deviceToken.description.trimmingCharacters(in: CharacterSet(charactersIn: "<>")) as NSString).replacingOccurrences(of: " ", with: "")

Swift3環境で動かすと
いままで64文字が取得できていた上記のコードでは”32bytes”という文字列が吐かれるようになってしまってます。
32bytesの文字量の文字列ではありません。”32bytes”です。意味不です
これを打開するには以下のようなコードを書く事で回避することができます。

let token = deviceToken.map { String(format: "%.2hhx", $0) }.joined()

pushはアプリの起動動線として非常に重要なものですのでしっかりと抑えて置きたいとこです。

※上記対応の引用元: http://qiita.com/mono0926/items/3cf0dca3029f32f54a09

通知設定情報の取得方法が変わった

続いてもpush周り。
端末の通知設定の取得でこんなコード書いていませんでしたか?

guard let currentSettings = UIApplication.shared.currentUserNotificationSettings else { return }
currentSettings.types != .none

これでもビルドはとおります。ただし、期待してる動作はしません。
Swift3の環境からはtypesの中身は

types = [UIUserNotificationType.badge, UIUserNotificationType.alert]

こんな感じでリストで返ってくるようになったようです。
なのでプッシュ設定が許可されていないかどうかのチェックをする場合は

types.isEmpty // or types == []

で確認することになりそうです。

Error と NSError

swift3からNSプレフィックスが取れたのでNSErrorも同様にErrorとして一皮剥けました
その結果どうなったかっというとこれまでNSErrorでは結構自由にlocalizedDescriptionとかadditionalUserInfoに対して情報を突っ込めてましたがそれができなくなってます。code等がまるっきり参照できなくなってますね。
幸いErrorとNSErrorで相互変換が可能なので例えば

extension Error {
    var code: Int {
        let nsError = self as NSError
        return nsError.code
    }
}

こんな感じのエクステンションを作るだけでこれまで通りのcodeを取得できます。description等も同様です。

encode/decode

これ結構事故ります。アップデート気をつけてください
UserDefautlsやファイルキャッシュ等で自作のクラスを保存する場合NSKeyedArchiver, NSKeyedUnArchiverすると思います。
クラスのプロパティ等は

Swift2系

func encodeWithCoder(aCoder: NSCoder) {
    aCoder.encodeObject("hogege", forKey: "fugafuga")
    aCoder.encodeBool(true, forKeyu: "fugafugafuga")
}

required init?(coder aDecoder: NSCoder) {
   stringValue = aDecoder.decodeObjectForKey("fugafuga") as? String
   boolValue = adecoder.decodeBoolForKey("fugafugafuga")
}

こんな感じでencode/decodeしてたかと思います。
Swift3系ではencodeが賢くなり

func encode(with aCoder: NSCoder) {
    aCoder.encode("hogege", forKey: "fuagafuga")
    aCoder.encode(true, forKey: "fugafugafuga")
}

引数で受け取ったobjectの型で勝手によしなにencodeしてくれるようになりました。
取り出す時は取り出したいものの型を厳密に指定してdecodeObjectやdecodeIntegerを使いこなさないといけなくなりました。

しかし、ここで問題なのが過去バージョンで

encodeObject(true, forKey: "fugafuga")

encodeObjectでObjectでないもの(Int値だったりBool値)だったりをdecodeして保存してしまった場合です。
これをちゃんと型を意識してとりだそー!と考えて

decodeBool(forKey: "fugafuga")

とすると、クラッシュします。

decodeObject(forKey: "fugafuga") as? Bool

こうやって取り出すしかなくなります。
お、これで終わりだと思うと次の落とし穴に落ちます。
先ほど述べたようにSwift3からはencodeは引数を見てよしなに保存してくれます、そして取り出す時も厳密に指定してあげないと値を取り出せません。
つまり上記のパターンの場合decodeObjectを使ってInt値を取り出せるのは過去バージョンからのアップデート後1回きりでその後は通常時と同じようにdecodeInteger(forKey:)を利用しないと値を取得できません。
つまり以下のような記述をしないといけなくなります。

if let oldSaveValue = decodeObject(forKey: "fugafuga") as? Bool {
   value = oldSaveValue  //旧バージョンのサポート
} else {
   vaiue = decodeBool(forKey: "fugafuga")
}

悲しいなぁ

名前空間を意識したencode/decode

非常にレアケースかと思いますが一応記載しておきます。

class A {
    class B {
    }
}

このような構造のクラスがあります。
そしてこのクラスBをNSKeyedArchiverを利用してdata化して保存します。
そして時がきたらNSKeyedUnArchiverをして利用します。

上記の操作ですが
Optimaization Levelを

Fast. Whole Module Optimization [-o]

以上にするとクラッシュします。

どうやら正式名称 A.BクラスなところをBクラスとしてencodeしてしまい。
decodeするときに「Bクラス?どこだよくっそもうわけわかんねぇ!落ちよ!!」ってなるみたい。
一応

NSKeyArchiver.setClassName(A.B.self, forClassName: "B")

みたいに道案内してあげるとちゃんと動くがメリットなさすぎコストかかりすぎだと思うので特に意味がないようなら外だししてあげるのが無難

JSONのパース

これも結構限定的な事象か?
NSJSONSerialization.JSONObjectWithDataから取り出せない型を含んだDictionaryの扱いについてです。
これまでは暗黙的にInt型をBoolにキャストできていましたがSwift3からはできなくなります。

let dic: [String: Any] = ["test": (1 as Int)]

// Swift2.3
let s2_3 = dic["test"] as? Bool // true
// Swift3.0
let s3_0 = dic["test"] as? Bool // nil

もしテスト等でJSONを作る等あればIntは使わずNSNumberを使うこと

あとがき

一旦これで僕が(僕のいるチームが)Swift3対応した中で出会った不具合たちです。
だいたい上記のものを抑えとけば深刻な不具合は産まないと思います。
また何か見つかれば追記していきようにします
これをみた人にSwift3対応がうまくいきますように・・・


『 Swift 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

AWSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

CentOSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

dockerに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

GitHubに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Javaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Laravelに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Vue.jsに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。