日本語であまり記事を見かけなかったので自分のメモの為にも。
#UserDefaultの特性
- 決まった型のみ保持される
- NSArray
- NSDictionary
- NSString
- NSNumber
- NSDate
- NSData
つまりこれに則した型でなければ、保存されない。つまりクラスなどはUserDefaultsに保存されない為、変換が必要になる。
今回はクラスを保存したいからNSDataに変換してUserDefaultsに収めることにしよう。
そこでNSKeyedArchiverとNSKeyedUnarchiverを使ってみようという根端です。
#DecoderとCoder
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 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
じゃあ、この作ったクラスを実際に保存したい時どうするか。
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 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