[譯] 讓我們來簡化 UserDefaults 的使用

talisk發表於2018-03-30

每個人都用 UserDefaults 來儲存一些簡單的資料,並且知道使用該儲存很容易。但是今天我會改善一點它的互動性!讓我們從最明顯的解決方案開始,並實現一些新穎且優雅的東西。?

想象一下我們有一個服務 —— SettingsService。這個服務掌握了應用的設定 —— 正在使用哪個主題(黑暗,明亮),是否啟用通知等等。為了實現它,大多數開發人員會首先考慮 UserDefaults。 當然,用哪種方式取決於具體情況,但先讓我們來簡化 UserDefaults

  1. 我們的第一個最簡方案
class SettingsService {

    private enum Keys {
        static let isNotificationsEnabled = "isNotificationsEnabled"
    }

    var isNotificationsEnabled: Bool {
        get {
            let isEnabled = UserDefaults.standard.value(forKey: Keys.isNotificationsEnabled) as? Bool
            return isEnabled ?? true
        }
        set {
            UserDefaults.standard.setValue(newValue, forKey: Keys.isNotificationsEnabled)
        }
    }
}
複製程式碼

為了簡單化,我直接使用 UserDefaults.standard,但在一個真實專案中,你最好把它存到一個 property 中,並使用依賴注入。

  1. 下一步,我想要擺脫 Keys 列舉——使用 #function 來代替:
class SettingsService {

    var isNotificationsEnabled: Bool {
        get {
            let isEnabled = UserDefaults.standard.value(forKey: #function) as? Bool
            return isEnabled ?? true
        }
        set {
            UserDefaults.standard.setValue(newValue, forKey: #function)
        }
    }
}
複製程式碼

看,怎麼樣!讓我們繼續:)

  1. 下標時間!我們剛剛把 value(forKey:) 方法封裝成支援範型的下標語法形式:
extension UserDefaults {

    subscript<T>(key: String) -> T? {
        get {
            return value(forKey: key) as? T
        }
        set {
            set(newValue, forKey: key)
        }
    }
}

class SettingsService {

    var isNotificationsEnabled: Bool {
        get {
            return UserDefaults.standard[#function] ?? true
        }
        set {
            UserDefaults.standard[#function] = newValue
        }
    }
}
複製程式碼

它看起來已經很整潔了!但是 Enums 呢??

enum AppTheme: Int {
    case light
    case dark
}

class SettingsService {

    var appTheme: AppTheme {
        get {
            if let rawValue: AppTheme.RawValue = UserDefaults.standard[#function], let theme = AppTheme(rawValue: rawValue) {
                return theme
            }
            return .light
        }
        set {
            UserDefaults.standard[#function] = newValue.rawValue
        }
    }
}
複製程式碼

這裡可以重構!

  1. 讓我們為 RawRepresentable 值編寫一個類似的 subscript
extension UserDefaults {
    
    subscript<T: RawRepresentable>(key: String) -> T? {
        get {
            if let rawValue = value(forKey: key) as? T.RawValue {
                return T(rawValue: rawValue)
            }
            return nil
        }
        set {
            set(newValue?.rawValue, forKey: key)
        }
    }
}

class SettingsService {
    
    var appTheme: AppTheme {
        get {
            return UserDefaults.standard[#function] ?? .light
        }
        set {
            UserDefaults.standard[#function] = newValue
        }
    }
}
複製程式碼

馬上完成啦!請注意,此擴充套件僅適用於使用 RawRepresentable 的列舉。


別忘了訂閱我的 telegram channel!第一時間瞭解 iOS 世界的有趣新聞和文章!


希望你能喜歡我寫的 extension!如果你有任何改進它的想法請告訴我!檢視 UserDefaults最新版本 extension 盡情地體驗一下吧:)

[譯] 讓我們來簡化 UserDefaults 的使用

這就是在構建 ITC 時候的我

一個在 Rosberry 工作的毛髮濃密的 iOS 工程師。熱衷響應式程式設計,開源愛好者,迴圈引用檢測人。:)

感謝 Evgeny MikhaylovRosberry


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章