sindresorhus / Defaults

💾 Swifty and modern UserDefaults
https://swiftpackageindex.com/sindresorhus/Defaults/documentation/defaults
MIT License
1.97k stars 117 forks source link

class type update is invalid #117

Closed GanZhiXiong closed 1 year ago

GanZhiXiong commented 1 year ago

The code below test41 update name and age is invalid, I don't know why?

class GanUser2: Codable, Defaults.Serializable {
    var name: String
    var age: String

    init(name: String, age: String) {
        self.name = name
        self.age = age
    }
}

extension Defaults.Keys {
    static let ganUser2 = Key<GanUser2>("ganUser2", default: GanUser2(name: "a", age: "1"))
}

final class GanTests: XCTestCase {
    override func setUp() {
        super.setUp()
//      Defaults.removeAll()
    }

    override func tearDown() {
        super.tearDown()
//      Defaults.removeAll()
    }

    func test31() {
        print(Defaults[.ganUser2].name, Defaults[.ganUser2].age)
    }
    func test41() {
        Defaults[.ganUser2].name = "b"
        Defaults[.ganUser2].age = "2"
        print(Defaults[.ganUser2].name, Defaults[.ganUser2].age)
    }
}
GanZhiXiong commented 1 year ago

There is no problem if you change class GanUser2 to struct GanUser2

hank121314 commented 1 year ago

This is an expected behavior. When GanUser2 is a class, it will not trigger the setter, which means UserDefaults will not update by this instruction. When GanUser2 is a struct, the setter will be triggered and update the value in UserDefaults.

If you want to use GanUser2 as a class, consider creating a new instance just like changing struct properties does. ex.

Defaults[.ganUser2] =  GanUser2(name: "b", age: "2")
GanZhiXiong commented 1 year ago

@hank121314 Thank you very much for your reply. I just started using swift and I am not very familiar with swift.😃

why class not support trigger the setter?

hank121314 commented 1 year ago

It is in-depth swift compiler knowledge. Defaults use a subscription to access the UserDefaults storage with Key. In swift, there are multiple subscription access strategies depending on the type of variable. For class, the access strategy will be DirectToAccessor, which means it will only use a getter. For struct, the access strategy will be MaterializeToTemporary, which means it will use both getter and setter.

GanZhiXiong commented 1 year ago

The reply was prompt and clear. Thank you very much!