はじめに
構造体の配列をUserDefaultsで保存、または取得する方法について記載します。
開発環境
- macOS Big Sur 11.2.3
- Xcode 12.4
- Swift 5.3.2
本題
保存/取得する方法
以下公式ドキュメントに記載の通り、独自の構造体のような、NSData、 NSString、NSNumber、NSDate、NSArray、NSDictionary以外の型を保存するには、NSData型のインスタンスを作成する必要がある。
"If you want to store any other type of object, you should typically archive it to create an instance of NSData."
※引用:
https://developer.apple.com/documentation/foundation/userdefaults
そのため、保存時は構造体の配列をData型にエンコードし、取得時にはData型のオブジェクトをデコードすることで、構造体の配列の保存と取得が可能になる。
※参考:
How to load and save a struct in UserDefaults using Codable - free Swift 5.1 example code and tips
例
以下のような構造体の配列をUserDefaultsで保存、または取得したい場合。
var bookmarks: [Bookmark] = [ Bookmark(name: "SamplePageA", urlString: "{URL}"), Bookmark(name: "SamplePageB", urlString: "{URL}"), Bookmark(name: "SamplePageC", urlString: "{URL}") ]
構造体BookmarkをCodableに準拠させることで、構造体の配列をエンコード、またはデコードできるようにする。
※参考:
https://developer.apple.com/documentation/swift/codable
struct Bookmark: Codable { var name: String var urlString: String }
以下のように、構造体の配列をJSONにエンコードすることで、Data型として保存。
func saveBookmarks(bookmarks: [Bookmark]) { let jsonEncoder = JSONEncoder() guard let data = try? jsonEncoder.encode(bookmarks) else { return } UserDefaults.standard.set(data, forKey: "bookmarks") }
保存したJSONをデコードすることで構造体の配列を取得できる。
func loadBookmarks() -> [Bookmark]? { let jsonDecoder = JSONDecoder() guard let data = UserDefaults.standard.data(forKey: "bookmarks"), let bookmarks = try? jsonDecoder.decode([Bookmark].self, from: data) else { return nil } return bookmarks }
※保存と取得のメソッドを使い回したい場合は、以下のようにジェネリクスを使う 。
func save<T: Encodable>(object: T, key: String) { let jsonEncoder = JSONEncoder() guard let data = try? jsonEncoder.encode(object) else { return } UserDefaults.standard.set(data, forKey: key) }
func load<T: Decodable>(key: String) -> T? { let jsonDecoder = JSONDecoder() guard let data = UserDefaults.standard.data(forKey: key), let object = try? jsonDecoder.decode(T.self, from: data) else { return nil } return object }
おわりに
NSDataとDataの違いが説明できない・・・!