UserDefault属性包装不保存值低于iOS 13的iOS版本

UserDefault property wrapper not saving values iOS versions below iOS 13(UserDefault属性包装不保存值低于iOS 13的iOS版本)
本文介绍了UserDefault属性包装不保存值低于iOS 13的iOS版本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用属性包装来保存我的用户默认值。在iOS 13设备上,该解决方案效果很好。但是,在iOS 11和iOS 12上,这些值不会保存到用户默认设置中。我读到属性包装是向后兼容的,所以我不知道为什么这在较旧的iOS版本上不起作用。

这是属性包装:

@propertyWrapper
struct UserDefaultWrapper<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 {
            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)

            UserDefaults.standard.set(data, forKey: key)
            UserDefaults.standard.synchronize()
        }
    }
}

struct UserDefault {
    @UserDefaultWrapper(key: "userIsSignedIn", defaultValue: false)
    static var isSignedIn: Bool
}

然后我可以像这样设置该值:

UserDefault.isSignedIn = true

我是否使用了错误的属性包装?还有谁在旧版iOS上遇到属性包装的问题吗?

推荐答案

与属性包装无关!问题是,在iOS 12和更早版本中,像Bool(或字符串等)这样的简单值虽然可以作为可编码结构的属性编码(例如),但不能对本身进行JSON编码。错误(您要丢弃的错误)对此非常清楚:

顶级布尔编码为数字JSON片段。

要查看此内容,只需运行以下代码:

    do {
        _ = try JSONEncoder().encode(false)
        print("succeeded")
    } catch {
        print(error)
    }

在iOS 12上,我们得到错误。在iOS 13上,我们得到"succeeded"

但如果我们包装Bool(或字符串等)在可编写代码的结构中,一切正常:

    struct S : Codable { let prop : Bool }
    do {
        _ = try JSONEncoder().encode(S(prop:false))
        print("succeeded")
    } catch {
        print(error)
    }

这在iOS 12iOS 13上都可以正常工作。

这一事实表明了一个解决方案!重新定义属性包装器,以便它将其值包装在泛型包装器结构中:

struct UserDefaultWrapper<T: Codable> {

    struct Wrapper<T> : Codable where T : Codable {
        let wrapped : T
    }

    private let key: String
    private let defaultValue: T

    init(key: String, defaultValue: T) {
        self.key = key
        self.defaultValue = defaultValue
    }

    var wrappedValue: T {
        get {
            guard let data = UserDefaults.standard.object(forKey: key) as? Data 
                else { return defaultValue }
            let value = try? JSONDecoder().decode(Wrapper<T>.self, from: data)
            return value?.wrapped ?? defaultValue
        }
        set {
            do {
                let data = try JSONEncoder().encode(Wrapper(wrapped:newValue))
                UserDefaults.standard.set(data, forKey: key)
            } catch {
                print(error)
            }
        }
    }
}

现在可以在iOS 12iOS 13上运行。


顺便说一句,我实际上认为保存为属性列表比保存为JSON更好。但这对这个问题总体上没有什么不同。您也不能将空Bool编码为属性列表。您仍然需要包装器方法。

这篇关于UserDefault属性包装不保存值低于iOS 13的iOS版本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

Why local notification is not firing for UNCalendarNotificationTrigger(为什么没有为UNCalendarNotificationTrigger触发本地通知)
iOS VoiceOver functionality changes with Bundle Identifier(IOS画外音功能随捆绑包标识符而变化)
tabbar middle tab out of tabbar corner(选项卡栏中间的选项卡角外)
Pushing UIViewController above UITabBar(将UIView控制器推送到UITabBar上方)
Dropbox Files.download does not start when number of files in folder is gt; 1000(当文件夹中的文件数为1000时,Dropbox Files.Download不会启动)
How can I sync two flatList scroll position in react native(如何在本机Reaction中同步两个平面列表滚动位置)