最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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來聲明一個屬性封裝器。你想要有一個字符串類型的屬性,每當這個屬性被進行讀寫操作的時候,控制臺就會輸出。你可以創(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一樣。然而,當定義一個屬性封裝器的時候,必須要有一個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)在開始準備實現(xiàn)我們的UserDefaults封裝器。總結(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,一個是defaultValue。key將作為UserDefaults讀寫時的鍵,而defaultValue則作為UserDefaults無值時候的返回值。

Storage屬性封裝器準備就緒后,我們就可以開始實現(xiàn)UserDefaults封裝器了。直截了當,我們只需要創(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)文章

  • iOS Xcode創(chuàng)建文件時自動生成的注釋方法

    iOS Xcode創(chuàng)建文件時自動生成的注釋方法

    下面小編就為大家分享一篇iOS Xcode創(chuàng)建文件時自動生成的注釋方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-01-01
  • iOS實現(xiàn)圓環(huán)比例圖

    iOS實現(xiàn)圓環(huán)比例圖

    這篇文章主要為大家詳細介紹了iOS實現(xiàn)圓環(huán)比例圖,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • iOS 漢字的拼音

    iOS 漢字的拼音

    本文通過一段代碼給代碼介紹了ios漢字的拼音知識及將漢字轉(zhuǎn)拼音的代碼,非常不錯,具有參考借鑒價值,感興趣的朋友一起看下吧
    2016-08-08
  • 如何在IOS中使用IBeacon

    如何在IOS中使用IBeacon

    這篇文章主要介紹了如何在IOS中使用IBeacon,想了解IBeacon的同學,一定要看一下
    2021-04-04
  • iOS中設(shè)置圓角的幾種方法示例

    iOS中設(shè)置圓角的幾種方法示例

    這篇文章主要介紹了iOS中設(shè)置圓角的三種方法,其中包括使用layer屬性、使用繪圖設(shè)置圓角以及通過另一張mask圖創(chuàng)建新圖,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-03-03
  • IOS 貝塞爾曲線(UIBezierPath)屬性、方法整理

    IOS 貝塞爾曲線(UIBezierPath)屬性、方法整理

    這篇文章主要介紹了IOS 貝塞爾曲線(UIBezierPath)屬性、方法的相關(guān)資料,這里整理了貝塞爾 曲線的基礎(chǔ)資料,對屬性及相應(yīng)的方法一一做了詳解,需要的朋友可以參考下
    2016-11-11
  • iOS開發(fā)檢測是否開啟定位、是否允許消息推送等權(quán)限的實例

    iOS開發(fā)檢測是否開啟定位、是否允許消息推送等權(quán)限的實例

    下面小編就為大家分享一篇iOS開發(fā)檢測是否開啟定位、是否允許消息推送等權(quán)限的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-01-01
  • iOS10推送之基礎(chǔ)知識(必看篇)

    iOS10推送之基礎(chǔ)知識(必看篇)

    相信每位iOS開發(fā)者們都知道,在iOS10更新之后,推送也是做了一些小小的修改,下面我就給大家仔細說說iOS10的推送,有需要的朋友們可以參考借鑒。下面來一起看看吧。
    2016-09-09
  • ios 單利的完整使用實例 及銷毀 宏定義

    ios 單利的完整使用實例 及銷毀 宏定義

    下面小編就為大家分享一篇ios 單利的完整使用實例 及銷毀 宏定義,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-01-01
  • IOS 聊天界面(自適應(yīng)文字)的實現(xiàn)

    IOS 聊天界面(自適應(yīng)文字)的實現(xiàn)

    本文主要介紹一個實現(xiàn)聊天界面的思路過程,具有很好的參考價值。下面跟著小編一起來看下吧
    2017-03-03

最新評論

嘉兴市| 湾仔区| 长治县| 友谊县| 平陆县| 平乐县| 吕梁市| 富平县| 滦南县| 宾川县| 稻城县| 阿合奇县| 游戏| 保德县| 永福县| 阜新| 滁州市| 舒兰市| 济南市| 张家港市| 枞阳县| 那曲县| 莱芜市| 康定县| 安新县| 肇东市| 永修县| 揭东县| 河间市| 四子王旗| 老河口市| 四子王旗| 林甸县| 寿宁县| 米脂县| 政和县| 临颍县| 惠安县| 榆树市| 米林县| 中西区|