【问题标题】:WillSet/DidSet not being invoked on realm property未在领域属性上调用 WillSet/DidSet
【发布时间】:2020-07-20 13:52:12
【问题描述】:

我有一个问题,因为 willSetdidSet 没有被动态领域对象调用。

代码示例:

try! realm.write {
    sut = Backup()
    realm.add(sut) // here willSet and didSet are invoked with nil object
}

XCTAssertFalse(sut.didEditPatient) // ok
try! realm.write {
    print("CHECKING: will add the patient")
    let patient = Patient()
    realm.add(patient)
    sut.patient = patient // nothing gets printed here!
    print("CHECKING: added the patient")
}

XCTAssertTrue(sut.didEditPatient) // fails
XCTAssertNotNil(sut.patient) // ok

Backup 类是这样定义的:

final class Backup: Object {
    @objc dynamic var patient: Patient? {
        willSet {
            print("CHECKING: willSet: \(String(describing: newValue))")
            if newValue != patient {
                didEditPatient = true
            }
        }
        didSet { print("CHECKING: didSet: \(String(describing: patient))") }
    }
    @objc dynamic var didEditPatient: Bool = false

控制台的输出是:

  • 检查:willSet:无
  • 检查:didSet:无
  • CHECKING:将添加患者
  • 检查:已添加患者

虽然我更希望在 will add the patientadded the patient 之间,但我应该得到带有耐心对象的 willSetdidSet。显然,耐心不是零。

【问题讨论】:

  • 我发布了一个答案,但现在我查看了代码,发现有问题或者我忽略了某些东西。在您的realm.write 中,您正在添加一个新的空患者realm.add(Patient()),但随后您将分配一个患者来像这样sut.patient = patient,但问题是patient var 是从哪里来的?换句话说,patient 似乎是未定义的 sut.patient = patient <---- This?
  • @Jay 你是对的。这是我在 SOF 中编写的用于简化实际解决方案的虚拟代码,显然我在这里犯了一个错误。修正了该声明。

标签: swift dynamic realm getter-setter


【解决方案1】:

realm repo 中描述了一个关于此的问题:


我建议使用没有逻辑的私有持久化属性,以及具有 willSet/didSet 功能的非持久化计算属性:

class Model : RLMObject {
    private dynamic var backingProp = 0

    var prop : Int {
        get {
            return backingProp
        }
        set(newValue) {
            // do willSet stuff
            backingProp = newValue
            // do didSet stuff
        }
    }

    override class func ignoredProperties() -> [AnyObject]! {
        return ["prop"]
    }
}

这有点冗长,但为领域中的对象和独立对象提供了相同的行为。


来源:https://github.com/realm/realm-cocoa/issues/870#issuecomment-54543539

【讨论】:

  • 欢迎来到 SO!仅链接的答案在这里被认为是低质量的。如果链接过时,您的回答将不会提供任何信息。引用非现场资源时,请始终确保在您的答案中包含足够的信息,以便即使链接停止工作,它也对未来的读者有用。如果这不可能,您应该在链接中留下评论,而不是发布答案。
  • 喜欢这个答案,但我认为它并不能真正回答问题; OP 想要使用 willSet 和 didSet 但 prop 属性由领域管理。您实际上可以在没有支持属性的情况下做到这一点。更重要的是,尽管问题存在歧义,因为看起来他们正试图将属性设置为非托管属性 - 请参阅我对问题的评论。
  • 酷。我在这里唯一要指出的是,您不必override ignoredProperties。我从Realm.Object 继承,只有@objc dynamic var 将被视为领域属性,其他所有内容都将被忽略。也许使用RLMObject 它曾经有所不同,但我想这在现代 Realm 版本中不可用(我使用的是 realm/realm-cocoa 5.0)。我什至检查了 Realm Browser 以确保不会创建这样的列。
【解决方案2】:

这很容易解决。只需在写入 Realm 之前更新对象属性。 willSet 和 didSet 是 Swift 构造,而不是 Objc。

let p = Patient()
try! realm.write {
    print("CHECKING: will add the patient")
    sut.patient = p // moved before add to realm.
    realm.add(p)
    print("CHECKING: added the patient")
}

将打印

CHECKING: will add the patient
willSet
didSet
CHECKING: added the patient

你想要的顺序。

【讨论】:

  • 只有在对象刚刚创建且未添加到领域时才使用它才是正确的。如果之前已经添加,那么它仍然不会显示消息。显然会导致生产中的错误,例如有人编辑对象,有一个协议方法来更新它,例如。 func didUpdate(patient: Patient?) 其中他还设置了backup.patient = oldValue,因为他不知道对象是否被添加、删除或编辑,并且 willSet/didSet 在所有情况下都不会触发。所以我更愿意继续使用上面引用的领域问题页面中建议的其他解决方案。
  • 此外,我只是出于好奇而对其进行了测试,但它不起作用。 let patient = Patient(id: 5); try! realm.write {print("CHECKING: will add the patient"); sut.patient = patient; realm.add(patient); print("CHECKING: added the patient")}@objc dynamic var patient: Patient? { willSet { print("willSet: \(String(describing: newValue))") }; didSet { print("didSet: \(String(describing: patient))") } } 结果为 willSet: nil; didSet: nil; CHECKING: will add the patient; CHECKING: added the patient
  • @Vive 很有趣。在 Will Print 之后我的回答中的那部分是从 Xcode 控制台复制和粘贴的,这表明,至少对于发布的代码,它确实适用于被调用的函数。在你的问题中,那些根本没有被调用。很好奇为什么 newValue 是 nil 。我同意拥有由 objc Realm 对象支持的 Swift 属性是最好的解决方案——尤其是计算值。
  • 确实很有趣。你是用 Realm 测试它还是只是空旷的操场?我想指出,我上面的评论也是从我的代码中复制的,我昨天改变了这个顺序。在第一行之前创建 SUT 时会打印 nil。但是,在我交换患者sut.patient = p 的地方,即使是在添加到领域之前,也不会打印任何内容。在我的问题中,印刷品的工作方式相同。无论如何,我不会继续使用这个解决方案,因为它以后不会更新 - 正如我在第一条评论中所写的那样。有意思,谢谢你的回答
猜你喜欢
  • 2016-10-01
  • 2019-12-20
  • 1970-01-01
  • 1970-01-01
  • 2014-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多