プログラミングや電子工作などについての記事がほとんどです

Xcode8+Swift3におけるシリアライズ・デシリアライズ

0 件のコメント

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

背景


本気ではじめるiPhoneアプリ作りに従ってiOSアプリの開発を学んでいるのですが、こちらはXcode7系+Swift2系の開発環境での開発方法について解説しています。Xcode8系+Swift3系のバージョンの違いによる書き換えが思いの外発生している様子。こちらの書籍をお持ちの方はChapter5のSection3を御覧ください。このあたりの内容について今回は記述しています。この書籍はフルカラーで書き方も易しいため以前のバージョンの環境で開発するのであれば間違いなくお勧め出来ると思います。

前回も紹介しましたが新しい環境での開発を学びたい方は下の書籍をどうぞ。

Xcodeではじめる 簡単iPhoneアプリ開発[Xcode 8&Swift 3対応]
技術評論社 (2016-09-22)
売り上げランキング: 5,959

シリアライズとは

独自クラスはそのままではUserDefaults(以前のバージョンではNSUserDefaults)に格納することができません。そこでデータを一旦NSKeyedArchiverクラスのメソッドを介してData型に変換する必要があります。(以前はNSData型に変換したようです。書籍でもそうでした。)この形式に変換することでUserDefaultsに独自クラスを保存することが可能になります。

デシリアライズとは

シリアライズされ、UserDefaultsに格納されたデータはUserDefaults.object(forKey: String)というメソッドで呼び出すことができます。このメソッドではAny型でオブジェクトを返すので必要に応じてキャストする必要があります。そこで通常Data型に一度戻してからさらにNSKeyedUnarchiverクラスのメソッドを介して元の独自のクラスに戻します。この最後の過程がデシリアライズというものです。要するにシリアライズされたオブジェクトを元のクラスのインスタンスに変換するというイメージで良いと思います。

ハマったとこ

今回ハマったところは、NSKeyedArchiverNSKeyedUnarchiverというクラスこそあるものの、それらがそれぞれもつメソッドarchivedDataWithRootObjectunarchiveObjectWithDataが見当たらなかったという点です。

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型にキャストする必要があります。

これからつくる iPhoneアプリ開発入門 ~Swiftではじめるプログラミングの第一歩~(仮)
藤 治仁 徳弘 佑衣 小林 加奈子 小林 由憲
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.archivedDataWithRootObjectNSKeyedArchiver.archivedData
- NSKeyedUnarchiver.unarchiveObjectWithDataNSKeyedUnarchiver.unarchiveObject
の書き換えです。

もしもっと正しい書き方があればコメントいただければ幸いです。

まとめ

今回はXcode8+Swift8におけるiOSアプリ開発において独自クラスを保存するためのシリアライズとデシリアライズの方法について解説しました。バージョンアップによって勝手が変わったこのあたりで困っている人の助けになれば幸いです。

詳解 Swift 改訂版
詳解 Swift 改訂版
posted with amazlet at 16.09.28
SBクリエイティブ (2016-02-26)
売り上げランキング: 27,708

ヒットするiPhoneアプリの作り方・売り方・育て方
マイナビ出版 (2013-07-27)
売り上げランキング: 91,531

0 件のコメント :

コメントを投稿