欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

iOS數(shù)據(jù)持久化UserDefaults封裝器使用詳解

 更新時間:2023年02月03日 15:06:35   作者:莊周曉夢  
這篇文章主要為大家介紹了iOS數(shù)據(jù)持久化UserDefaults封裝器使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

使用屬性封裝器來完美創(chuàng)建UserDefaults封裝器

想象一下,你有一個應(yīng)用想實現(xiàn)自動登錄功能。你用UserDefaults封裝了關(guān)于UserDefaults的讀與寫邏輯。你會用UserDefaults封裝來保持對自動登錄”On/Off“狀態(tài)、userName的跟蹤。你可能會以下面這種方式來封裝UserDefaults

struct AppData {
    private static let enableAutoLoginKey = "enable_auto_login_key"
    private static let usernameKey = "username_key"
    static var enableAutoLogin: Bool {
        get {
            return UserDefaults.standard.bool(forKey: enableAutoLoginKey)
        }
        set {
            UserDefaults.standard.set(newValue, forKey: enableAutoLoginKey)
        }
    }
    static var username: String {
        get {
            return UserDefaults.standard.string 
        }
        set {
            UserDefaults.standard.set(newValueds, forKey: usernameKey)
        }
    }
}

通過Swift5.1對于屬性封裝器的介紹,我們可以對上面的代碼進行精簡,如下

struct AppData {
    @Storage(key: "enable_auto_login_key", defaultValue: false)
    static var enableAutoLogin: Bool
    @Storage(key: "username_key", defaultValue: "")
    static var username: String
}

這樣就很完美了嗎?接著看

什么是屬性封裝器?

在我們進入詳細討論之前,我們先快速地了解一下什么是屬性封裝器 基本上來講,屬性封裝器是一種通用數(shù)據(jù)結(jié)構(gòu),可以攔截屬性的讀寫訪問,從而允許在屬性的讀寫期間添加自定義行為。

可以通過關(guān)鍵字@propertyWrapper來聲明一個屬性封裝器。你想要有一個字符串類型的屬性,每當(dāng)這個屬性被進行讀寫操作的時候,控制臺就會輸出。你可以創(chuàng)建一個名為Printable的屬性封裝器,如下:

@propertyWrapper
struct Printable {
    private var value: String = ""
    var wrapperValue: String {
        get {
            print("get value:\(value)")
            return value
        }
        set {
            print("set value:\(newValue)")
            value = newValue
        }
    }
}

通過上述代碼我們可以看出,屬性封裝跟其他struct一樣。然而,當(dāng)定義一個屬性封裝器的時候,必須要有一個wrapppedValue。 wrapppedValue get set代碼塊就是攔截和執(zhí)行你想要的操作的地方。在這個例子中,添加了打印狀態(tài)的代碼來輸出get和set的值

接下來,我們看看,如何使用Printable屬性封裝器

struct Company {
    @Printable static var name: String
}
Company.name = "Adidas"
Company.name

需要注意的是,我們?nèi)绾问褂?code>@符號來聲明一個用屬性封裝器封裝的”name“變量。如果你想要在Playground中嘗試敲出上述代碼的話,你會看到以下輸出:

Set Value: Adidas
Get Value: Adidas

什么是UserDefault封裝器

在理解了什么是屬性封裝器以及它是如何工作的之后,我們現(xiàn)在開始準(zhǔn)備實現(xiàn)我們的UserDefaults封裝器??偨Y(jié)一下,我們的屬性封裝器需要持續(xù)跟蹤自動登錄的”On/Off“狀態(tài)以及用戶的username。 通過使用我們上述討論的概念,我們可以很輕松的將Printable屬性封裝器轉(zhuǎn)化為在讀寫操作期間進行讀寫的屬性封裝器。

import Foundation
@propertyWrapper
struct Storage {
    private let key: String
    private let defaultValue: String
    init(key: Stirng, defaultValue: String) {
        self.key = key
        self.defaultValue = defaultValue
    }
    var wrappedValue: String {
        get {
            return UserDefaults.standard.string(forKey: key) ?? defaultValue
        }
        set {
            UserDefaults.standard.set(newValue, forKey: key)
        }
    }
}

在這里,我們將我們的屬性封裝器命名為Storage。有兩個屬性,一個是key,一個是defaultValuekey將作為UserDefaults讀寫時的鍵,而defaultValue則作為UserDefaults無值時候的返回值。

Storage屬性封裝器準(zhǔn)備就緒后,我們就可以開始實現(xiàn)UserDefaults封裝器了。直截了當(dāng),我們只需要創(chuàng)建一個被Storage屬性封裝器封裝的‘username’變量。這里要注意的是,你可以通過keydefaultValue來初始化Storage

struct AppData {
    @Storage(key: "username_key", defaultValue: "")
    static var username: String
}

一切就緒之后,UserDefaults封裝器就可以使用了

AppData.username = "swift-senpai"
print(AppData.username)

同時,我們來添加enableAutoLogin變量到我們的UserDefaults封裝器中

struct AppData {
    @Storage(key: "username_key", defaultValue: "")
    static var username: String
    @Storage(key: "enable_auto_login_key", defaultValue: false)
    static var username: Bool
}

這個時候,會報下面兩種錯誤:

Cannot convert value of type ‘Bool’ to expected argument type ‘String’

Property type 'Bool' does not match that of lthe 'WrappedValue' property of its wrapper type 'Storage'

這是因為我們的封裝器目前只支持String類型。想要解決這兩個錯誤,我們需要將我們的屬性封裝器進行通用化處理

將屬性封裝器進行通用化處理

我們必須改變屬性封裝器的wrappedValue的數(shù)據(jù)類型來進行封裝器的通用化處理,將String類型改成泛型T。進而,我們必須使用通用方式從UserDefaults讀取來更新wrappedValue get代碼塊

@propertyWrapper
struct Storage<T> {
    private let key: String
    private let defaultValue: T
    init(key: String, defaultValue: T) {
        self.key = key
        self.defaultValue = defaultValue
    }
    var wrappedValue: T {
        get {
            // Read value from UserDefaults
            return UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
        }
        set {
            // Set value to UserDefaults
            UserDefaults.standard.set(newValue, forKey: key)
        }
    }
}

好,有了通用屬性封裝器之后,我們的UserDefaults封裝器就可以存儲Bool類型的數(shù)據(jù)了

// The UserDefaults wrapper
struct AppData {
    @Storage(key: "username_key", defaultValue: "")
    static var username: String
    @Storage(key: "enable_auto_login_key", defaultValue: false)
    static var enableAutoLogin: Bool
}
AppData.enableAutoLogin = true
print(AppData.enableAutoLogin)  // true

存儲自定義對象

上面的操作都是用來基本數(shù)據(jù)類型的。但是如果我們想要存儲自定義對象呢?接下來我們一起看看,如何能讓UserDefaults支持自定義對象的存儲

這里的內(nèi)容很簡單,我們將會存儲一個自定義對象到UserDefaults中,為了達到這個目的,我們必須改造一下Storage屬性封裝器的類型T,使其遵循Codable協(xié)議

然后,在wrappedValue``set代碼塊中我們將使用JSONEncoder把自定義對象轉(zhuǎn)化為Data,并將其寫入UserDefaults中。同時,在wrappedValue``get代碼塊中,我們將使用JSONDecoder把從UserDefaults中讀取的數(shù)據(jù)轉(zhuǎn)化成對應(yīng)的數(shù)據(jù)類型。 如下:

@propertyWrapper
struct Storage<T: Codable> {
    private let key: String
    private let defaultValue: T
    init(key: String, defaultValue: T) {
        self.key = key
        self.defaultValue = defaultValue
    }
    var wrappedValue: T {
        get {
            // Read value from UserDefaults
            guard let data = UserDefaults.standard.object(forKey: key) as? Data else {
                // Return defaultValue when no data in UserDefaults
                return defaultValue
            }
            // Convert data to the desire data type
            let value = try? JSONDecoder().decode(T.self, from: data)
            return value ?? defaultValue
        }
        set {
            // Convert newValue to data
            let data = try? JSONEncoder().encode(newValue)
            // Set value to UserDefaults
            UserDefaults.standard.set(data, forKey: key)
        }
    }
}

為了讓大家看到如何使用更新后的Storage屬性封裝器,我們來看一下接下來的例子。 想象一下,你需要存儲用戶登錄成功后服務(wù)端返回的用戶信息。首先,需要一個持有服務(wù)端返回的用戶信息的struct。這個struct必須遵循Codable協(xié)議,以至于他能被轉(zhuǎn)化為Data存儲到UserDefaults

struct User: Codable {
    var firstName: String
    var lastName: String
    var lastLogin: Date?
}

接下來,在UserDefaults封裝器中聲明一個User對象

struct AppData {
    @Storage(key: "username_key", defaultValue: "")
    static var username: String
    @Storage(key: "enable_auto_login_key", defaultValue: false)
    static var enableAutoLogin: Bool
    // Declare a User object
    @Storage(key: "user_key", defaultValue: User(firstName: "", lastName: "", lastLogin: nil))
    static var user: User
}

搞定了,UserDefaults封裝器現(xiàn)在可以存儲自定義對象了

let johnWick = User(firstName: "John", lastName: "Wick", lastLogin: Date())
// Set custom object to UserDefaults wrapper
AppData.user = johnWick
print(AppData.user.firstName) // John
print(AppData.user.lastName) // Wick
print(AppData.user.lastLogin!) // 2019-10-06 09:40:26 +0000

以上就是iOS數(shù)據(jù)持久化UserDefaults封裝器使用詳解的詳細內(nèi)容,更多關(guān)于iOS數(shù)據(jù)持久化UserDefaults的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論