(コメントにて@ObuchiYukiさんのご指摘にもありますが、)
本記事の内容は古く、現在であればCodable
を使用するのが簡単に思います。
下記に例を示します。
保存対象のカスタムクラス
struct Item: Codable {
let id: Int
let name: String
}
保存処理
func saveItems(items: [Item]) {
let data = items.map { try! JSONEncoder().encode($0) }
userDefaults.set(data as [Any], forKey: "キー名")
}
読み取り処理
func readItems() -> [Item]? {
guard let items = userDefaults.array(forKey: "キー名") as? [Data] else { return [Item]() }
let decodedItems = items.map { try! JSONDecoder().decode(Item.self, from: $0) }
return decodedItems
}
カスタムクラスをData型に変換する必要性
例えばUserDefaultsを使用する場合、カスタムオブジェクトをNSDataに変換する必要があります :)
なぜかというと、UserDefaultsで保存できる型は NSData, NSString, NSNumber, NSDate, NSArray, NSDictionary となっているからです。
これ以外の型を保持させたい場合は一旦NSData型に変換してから保持し、読み込む際はNSData型として読み込んだ後に型変換を行う必要があります。
以下では「UserDefaultsにてカスタムクラスの配列を保存、読み込む」という具体的なケースで、Swift4でカスタムクラスをData型に変換する処理を見ていきます😄
流れ
iOS ではシリアライズすることをアーカイブ、デシリアライズすることをアンアーカイブといいます。
アーカイブのためのクラスとして NSKeyedArchiver クラス
アンアーカイブのためのクラスとして NSKeyedUnarchiver クラスがあります。

UserDefaultsにカスタムクラスの配列を保存・読み込みをする
まず、独自に作成するカスタムクラスを定義します。
<ポイント>
NSObject, NSCodingを継承する
エンコード、デコード処理を記述する
class SomeObj: NSObject, NSCoding {
var word: String!
var date: String!
init(word: String, date: String) {
self.word = word
self.date = date
}
required init?(coder aDecoder: NSCoder) {
self.word = aDecoder.decodeObject(forKey: "word") as! String
self.date = aDecoder.decodeObject(forKey: "date") as! String
}
func encode(with aCoder: NSCoder) {
if let word = word { aCoder.encode(word, forKey: "word") }
if let date = date { aCoder.encode(date, forKey: "date") }
}
}
保存処理ではNSKeyedArchiver.archivedData
を使用します
var someObjArray = [SomeObj]()
let someObj = SomeObj(word: "hoge", date: "2000/01/01")
someObjArray.insert(someObj, at: 0)
UserDefaults.standard.set(NSKeyedArchiver.archivedData(withRootObject: someObjArray), forKey: "someObjs")
読み込み処理では、一度Data型で読み込んだものをNSKeyedUnarchiver.unarchiveObjec
を使用してアンアーカイブ(デシリアライズ)します
func loadSomeObjs() -> [someObj]?{
if let loadedData = UserDefaults().data(forKey: "someObjs") {
let someObjs = NSKeyedUnarchiver.unarchiveObject(with: loadedData) as! [SomeObj]
return someObjs
}else {
return nil
}
}
これでUserDefaultsにカスタムクラスの配列を保存したり、読み込んだりできるようになります!