LoginSignup
9
6

More than 3 years have passed since last update.

NSKeyedArchiverとNSKeyedUnarchiverを使ったクラスの保存

Last updated at Posted at 2018-02-09

日本語であまり記事を見かけなかったので自分のメモの為にも。

ここで作ったテストアプリのRepo

UserDefaultの特性

  • 決まった型のみ保持される
    • NSArray
    • NSDictionary
    • NSString
    • NSNumber
    • NSDate
    • NSData

つまりこれに則した型でなければ、保存されない。つまりクラスなどはUserDefaultsに保存されない為、変換が必要になる。

今回はクラスを保存したいからNSDataに変換してUserDefaultsに収めることにしよう。

そこでNSKeyedArchiverとNSKeyedUnarchiverを使ってみようという根端です。

DecoderとCoder

class.swift
import UIKit

class userList{
    var name: String!
    var age: Int!

    //initialize class
    init(name: String, age: Int){
        self.name = name
        self.age = age
    }
}

こんなクラスがあった時に、まずこのクラスをNSObjectとNSCodingから継承するようにしないといけないらしい。

そんでもって、CoderとDecoderメソッドを実装する

class.swift
class userList: NSObject, NSCoding{
    var name: String!
    var age: Int!

    //initialize class
    init(name: String, age: Int){
        self.name = name
        self.age = age
    }

    //decoder initializing
    required init(coder decoder: NSCoder) {
        self.name = decoder.decodeObject(forKey: "name") as? String ?? ""
        //self.age = decoder.decodeInteger(forKey: "age")
        self.age = decoder.decodeObject(forKey: "age") as? integer
    }

    //encode method
    func encode(with coder: NSCoder) {
        coder.encode(name, forKey: "name")
        coder.encode(age, forKey: "age")
    }
}

ここまでで一応下準備は完了する。Class内のプロパティを全てNSData型に落とし込める状態。(もしかしてここでもうすでに落とし込まれてる?)

NSKeyedArchiver NSKeyedUnArchiver

じゃあ、この作ったクラスを実際に保存したい時どうするか。

ViewController.swift
import UIKit

class ViewController: UIViewController{

    var userArray: [userList] = []
    var archiver = dataArchiver()
    let userDefaults: UserDefaults = UserDefaults.standard

    override func viewDidLoad() {
        super.viewDidLoad()
        userArray.append(userList(name: "John", age: 34))
        userArray.append(userList(name: "Noel", age: 23))
        //ここでarchivedArrayに今アーカイブしたデータを入れる
        let archivedArray = NSKeyedArchiver.archivedData(withRootObject: userArray)

        //UserDefaultsに初期値として入れる。
        savedData().userDefaults.register(defaults: ["savedList": archivedArray])
        //ここで初期値を入れたuserdefaultsからデータを取り出してみる。
        userArray = archiver.unArchiveData(file: userDefaults.data(forKey: "savedList")!) as! [userList]
        print("The users name is \(userArray[0].name!) and he is \(userArray[0].age!) years old")
        //The users name is John and he is 34 years old
        print(userArray)
        //[<DecoderCoderTest.userList: 0x60400046f040>, <DecoderCoderTest.userList: 0x600000463800>]
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

こうすると欲しい値が返される。
あと、このコードClass.swift内にArchiver, Unarchiverのメソッドを書いてて。

Class.swift
class dataArchiver{
    func archiveData(file: Any) -> Any{
        let archivedArray = NSKeyedArchiver.archivedData(withRootObject: file)
        return archivedArray
    }

    func unArchiveData(file: Data) -> Any{
        let unArchivedArray = NSKeyedUnarchiver.unarchiveObject(with: file)
        return unArchivedArray!
    }

ViewControllerの頭でインスタンス化して、こんな感じで納めたってわけですねー。
個人的にこれの方が楽かなと思って。わかんないけど。

Gitの方に全部乗っけてるんで、このRepoみていただいた早いかと思います。

最後に

これ[UIImage]なんかはもっと簡単にできてCoderとDecoderのメソッドが必要なかったりで。

複数画像を保持したい時に便利かなと。Archiveして、Userdefaultにぶち込んで、使いたい時にUserDefaultsから引っ張り出して、Unarchiveして、はい元どおりって感じだった気がします。

参考

"Swift 3 saving and retrieving custom object from userDefaults" via stackoverflow

9
6
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
6