Xcode8+Swift3におけるシリアライズ・デシリアライズ
XcodeとSwiftの仕様変更にまたもハマる
先日投稿した2記事同様、Xcode8・Swift3のバージョンアップによりXcode7系やSwift2系のときの開発方法と少し違うところが出てきています。そこにハマったのでまたも記事にしました。
[iOS][Swift]prepareForSegueをOverride出来ない……の対処法 - Qiita
Xcode8+Swift3でNSUserDefaultsが使えない http://cabbalog.blogspot.jp/2016/09/xcode8-swift3-nsuserdefaults.html
背景
売り上げランキング: 3,610
本気ではじめるiPhoneアプリ作りに従ってiOSアプリの開発を学んでいるのですが、こちらはXcode7系+Swift2系の開発環境での開発方法について解説しています。Xcode8系+Swift3系のバージョンの違いによる書き換えが思いの外発生している様子。こちらの書籍をお持ちの方はChapter5のSection3を御覧ください。このあたりの内容について今回は記述しています。この書籍はフルカラーで書き方も易しいため以前のバージョンの環境で開発するのであれば間違いなくお勧め出来ると思います。
前回も紹介しましたが新しい環境での開発を学びたい方は下の書籍をどうぞ。
売り上げランキング: 5,959
シリアライズとは
独自クラスはそのままではUserDefaults
(以前のバージョンではNSUserDefaults
)に格納することができません。そこでデータを一旦NSKeyedArchiver
クラスのメソッドを介してData型
に変換する必要があります。(以前はNSData型
に変換したようです。書籍でもそうでした。)この形式に変換することでUserDefaults
に独自クラスを保存することが可能になります。
デシリアライズとは
シリアライズされ、UserDefaults
に格納されたデータはUserDefaults.object(forKey: String)
というメソッドで呼び出すことができます。このメソッドではAny型
でオブジェクトを返すので必要に応じてキャストする必要があります。そこで通常Data型
に一度戻してからさらにNSKeyedUnarchiver
クラスのメソッドを介して元の独自のクラスに戻します。この最後の過程がデシリアライズというものです。要するにシリアライズされたオブジェクトを元のクラスのインスタンスに変換するというイメージで良いと思います。
SBクリエイティブ
ハマったとこ
今回ハマったところは、NSKeyedArchiver
とNSKeyedUnarchiver
というクラスこそあるものの、それらがそれぞれもつメソッドarchivedDataWithRootObject
とunarchiveObjectWithData
が見当たらなかったという点です。
NSKeyedArchiver.archivedDataWithRootObjectが見当たらない件について
こちらはとても簡単な問題でした。これはSwiftとObjective-C(iOS開発に使われていた従来の言語)でのメソッドの命名規則が異なることがきっかけだったようです。Objective-Cの時代ではarchiveDataWithRootObject
のように何をするか + with + 最初の引数名
という順でメソッド名が定義されていました。ところがSwiftではwith以降の部分がパラメータ名に記述するしきたりらしく、archiveData(withRootObject: Any)
という名前に変更されたようです。
名前こそ異なりますが、使い方は前身であるarchiveDataWithRootObject
と変わりませんのでそこまで問題にはならないでしょう。
NSKeyedUnarchiver.unarchiveObjectWithDataが見当たらない件について
こちらも上記同様で、新しいバージョンではunarchiveObject(with: Data)
となっています。こちらの使い方も同様ですので戸惑うこともないと思います。一点気をつけるとすれば、移行元のメソッドunarchiveObjectWithData
の引数がNSData型
なのに対して新しいメソッドの引数がData型
なので、userDefaults.object(forKey: String)
で呼び出したオブジェクトはas? Data
とするなどしてData型
にキャストする必要があります。
SBクリエイティブ
売り上げランキング: 140,408
対応策
前回同様上記書籍のサンプルプロジェクトを題材に書き換えてみました。著作権保護のため元のコードをこちらで掲載することはできませんが、出版社の公式ページからダウンロードできます。Chapter5のSampleCustomClassDataStorageというプロジェクトを御覧ください。照らし合わせていただけるとわかりやすいと思います。
こちらに私が書き直したバージョンのソースを掲載します。
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//put data after view is loaded
let userDefaults = UserDefaults.init()
let data = MyData()
data.valueString = "hogehoge"
//serializing
let archiveData = NSKeyedArchiver.archivedData(withRootObject: data)
userDefaults.set(archiveData, forKey: "data")
userDefaults.synchronize()
//deserializing
if let storedData = userDefaults.object(forKey: "data") as? Data{
if let unarchivedData = NSKeyedUnarchiver.unarchiveObject(with: storedData) as? MyData{
if let valueString = unarchivedData.valueString{
print("deserialized:" + valueString)
}
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
ポイントは
- NSData型
→Data型
- NSKeyedArchiver.archivedDataWithRootObject
→NSKeyedArchiver.archivedData
- NSKeyedUnarchiver.unarchiveObjectWithData
→NSKeyedUnarchiver.unarchiveObject
の書き換えです。
もしもっと正しい書き方があればコメントいただければ幸いです。
まとめ
今回はXcode8+Swift8におけるiOSアプリ開発において独自クラスを保存するためのシリアライズとデシリアライズの方法について解説しました。バージョンアップによって勝手が変わったこのあたりで困っている人の助けになれば幸いです。
売り上げランキング: 27,708
売り上げランキング: 91,531
0 件のコメント :
コメントを投稿