Ios 使用PropertyWrapper实现UserDefaults会导致奇怪的问题

Ios 使用PropertyWrapper实现UserDefaults会导致奇怪的问题,ios,swift,key-value-observing,property-wrapper,Ios,Swift,Key Value Observing,Property Wrapper,我正在尝试使用@propertyWrapper实现UserDefaults类。我试图做的是为我的应用程序用户首选项创建一个包装器类。所以我写了下面的代码 @propertyWrapper struct Storage<T> { private let key: String private let defaultValue: T var projectedValue: Storage<T> { return self } var wrapp

我正在尝试使用
@propertyWrapper
实现UserDefaults类。我试图做的是为我的应用程序用户首选项创建一个包装器类。所以我写了下面的代码

@propertyWrapper
struct Storage<T> {
    private let key: String
    private let defaultValue: T
    var projectedValue: Storage<T> { return self }
    var wrappedValue: T {
        get {
            return UserDefaults.standard.string(forKey: key) as? T ?? defaultValue
        }
        set {
            UserDefaults.standard.set(newValue, forKey: key)
        }
    }

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

    func observe(change: @escaping (T?, T?) -> Void) -> NSObject {
        return DefaultsObservation(key: key) { old, new in
            change(old as? T, new as? T)
        }
    }
}
另外,我的AppData类如下所示

struct AppData {
    @Storage(key: "layout_key", defaultValue: "list")
    static var layout: String
}
但是,当我尝试添加和侦听更改
布局
属性时,它无法正常工作

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    AppData.$layout.observe { old, new in
        print(old)
    }
}
当我调试它时,
deinit
会在调用
viewwillbeen
方法时立即工作。当我注释掉去除观察者的方法时,一切都很完美。我认为关闭Denit会导致一些内存问题。所以我不想把它评论掉。我遗漏了什么以及如何解决它?

方法
观察(更改:@escaping(T?,T?)
初始化
DefaultsObservation
对象并返回值。没有对此对象的任何强引用,因此它被解除分配并调用
deInit
。您需要保留此对象的强引用。例如

var valueObserver: NSObject? = nil
override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    valueObserver = AppData.$layout.observe { old, new in
        print(old)
    }
}
方法
observe(更改:@escaping(T?,T?)
初始化
DefaultsObservation
对象并返回值。此对象没有任何强引用,因此它被解除分配并调用
deInit
。您需要保留此对象的强引用。例如

var valueObserver: NSObject? = nil
override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    valueObserver = AppData.$layout.observe { old, new in
        print(old)
    }
}

可能是不相关的,但是有一个类型的错误。<代码>字符串(代码:<代码> >用户错误< /COD>总是返回代码>字符串< /代码>(或<代码> nIL/COD>)。要更通用,你必须写<代码>对象(FROKE:字符串(FracK:<代码> > <代码错误> <代码> >始终返回代码>字符串< /代码>(或<代码> nIL/COD>)。为了更通用,您必须编写<代码>对象(FROKE:)谢谢,我认为编写更通用的代码。