亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

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

想象一下,你有一個(gè)應(yīng)用想實(shí)現(xiàn)自動(dòng)登錄功能。你用UserDefaults封裝了關(guān)于UserDefaults的讀與寫(xiě)邏輯。你會(huì)用UserDefaults封裝來(lái)保持對(duì)自動(dòng)登錄”On/Off“狀態(tài)、userName的跟蹤。你可能會(huì)以下面這種方式來(lái)封裝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)
        }
    }
}

通過(guò)Swift5.1對(duì)于屬性封裝器的介紹,我們可以對(duì)上面的代碼進(jìn)行精簡(jiǎn),如下

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

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

什么是屬性封裝器?

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

可以通過(guò)關(guān)鍵字@propertyWrapper來(lái)聲明一個(gè)屬性封裝器。你想要有一個(gè)字符串類(lèi)型的屬性,每當(dāng)這個(gè)屬性被進(jìn)行讀寫(xiě)操作的時(shí)候,控制臺(tái)就會(huì)輸出。你可以創(chuàng)建一個(gè)名為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
        }
    }
}

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

接下來(lái),我們看看,如何使用Printable屬性封裝器

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

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

Set Value: Adidas
Get Value: Adidas

什么是UserDefault封裝器

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

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。有兩個(gè)屬性,一個(gè)是key,一個(gè)是defaultValue。key將作為UserDefaults讀寫(xiě)時(shí)的鍵,而defaultValue則作為UserDefaults無(wú)值時(shí)候的返回值。

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

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

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

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

同時(shí),我們來(lái)添加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
}

這個(gè)時(shí)候,會(huì)報(bào)下面兩種錯(cuò)誤:

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'

這是因?yàn)槲覀兊姆庋b器目前只支持String類(lèi)型。想要解決這兩個(gè)錯(cuò)誤,我們需要將我們的屬性封裝器進(jìn)行通用化處理

將屬性封裝器進(jìn)行通用化處理

我們必須改變屬性封裝器的wrappedValue的數(shù)據(jù)類(lèi)型來(lái)進(jìn)行封裝器的通用化處理,將String類(lèi)型改成泛型T。進(jìn)而,我們必須使用通用方式從UserDefaults讀取來(lái)更新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封裝器就可以存儲(chǔ)Bool類(lèi)型的數(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

存儲(chǔ)自定義對(duì)象

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

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

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

@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屬性封裝器,我們來(lái)看一下接下來(lái)的例子。 想象一下,你需要存儲(chǔ)用戶登錄成功后服務(wù)端返回的用戶信息。首先,需要一個(gè)持有服務(wù)端返回的用戶信息的struct。這個(gè)struct必須遵循Codable協(xié)議,以至于他能被轉(zhuǎn)化為Data存儲(chǔ)到UserDefaults

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

接下來(lái),在UserDefaults封裝器中聲明一個(gè)User對(duì)象

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)在可以存儲(chǔ)自定義對(duì)象了

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封裝器使用詳解的詳細(xì)內(nèi)容,更多關(guān)于iOS數(shù)據(jù)持久化UserDefaults的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論