Swift・iOS

Swiftを中心に学んだことを記録に残すブログです。技術に関係ない記事もたまに書いています。

【Swift】構造体の配列をUserDefaultsで保存/取得する

 

はじめに

構造体の配列をUserDefaultsで保存、または取得する方法について記載します。

 

開発環境

 

本題

保存/取得する方法

以下公式ドキュメントに記載の通り、独自の構造体のような、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の違いが説明できない・・・!

 

参考