【问题标题】:How to observe changes, and store previous values, of an inherited object's property?如何观察继承对象属性的变化并存储以前的值?
【发布时间】:2021-01-22 22:12:47
【问题描述】:

设置:

我正在继承 SKSpriteNode() 以创建一个名为 SubNode() 的自定义子类。

SKSPriteNode() 类有一个名为physicsBody 的属性,它存储一个SKPhysicsBody() 对象。 SKPhysicsBody 有一个名为“velocity”的属性,即CGVector()

目标:

在我的子类中,我希望有一个变量始终保持以前的CGVector()。例如,只要我打电话给subNode.physicsBody?.velocity = CGVector(dx: 10, dy: 10) 就意味着。 subNode.previousVelocity 应设置为之前的 subNode.physicsBody?.velocity 值。

问题

如果velocity 只是超类的继承属性,我可以只使用override 属性并附加didSet 观察者。但由于velocitySKPhysicsBody() 的属性,并且SKPhysicsBody() 对象在其属性之一更改时不会更改,因此didSet 不会被触发,我无法听到它的更改。

如果我的解释不清楚,请要求进一步澄清。

我的子类:

class SubNode: SKSpriteNode {
    
    var previousVelocity: CGVector = .zero

    // This doesn't get triggered because the physiceBody object doesn't change when one of its properties changes.
    override var physicsBody: SKPhysicsBody? {
        didSet {
            previousVelocity = oldValue?.velocity
        }
    }
    
    // If velocity would be a property of the superclass, this would trigger.
    override var velocity: CGVector {
        didSet {
            previousVelocity = oldValue
        }
    }
}

从 SubNode() 子类创建对象 subNode,设置物理体,然后设置速度"

let subNode = SubNode()
subNode.physicsBody = SKPhysicsBody()
subNode.physicsBody?.velocity = CGVector(dx: 10, dy: 10)
subNode.physicsBody?.velocity = CGVector(dx: 0, dy: 0)
//should be true: subnode.previousVelocity == CGVector(dx: 10, dy: 10)

【问题讨论】:

    标签: swift inheritance overriding subclass property-observer


    【解决方案1】:

    这只是部分答案!只是试图找到问题的解决方案。

    我试图以某种方式找到解决方法。我注意到,一旦对象的属性发生变化,对象的 getter 就会被触发。我创建了以下游乐场文件,它似乎工作。一旦我更改了对象的文本,以前的名称就会存储在另一个变量中。但从我的测试来看,这似乎有效。我不确定我的逻辑是否正确,或者我是否遗漏了什么,实现应该更简单的东西也可能有点太多了。

    下面我为我的子类添加了代码,并且从我目前可以测试的结果来看,它确实有效。不过,我希望得到一些反馈,因为此解决方案可能存在缺陷。

    import UIKit
    
    class ObjectClass {
        var name: String = "Initial Name"
    }
    
    class SuperClass {
        var object: ObjectClass?
    }
    
    class SubClass: SuperClass {
        
        var _oldObjectName: [String?] = [nil]
        
        var oldObjectName: String? {
            _ = object?.name
            return _oldObjectName.first ?? nil
        }
        
        override var object: ObjectClass? {
            get {
                // Is also being called before the object has been written to.
                if !_oldObjectName.contains(super.object?.name) {
                    _oldObjectName.append(super.object?.name)
                    _oldObjectName = _oldObjectName.suffix(2)
                }
                return super.object
            }
            set {
                super.object = newValue
            }
        }
    }
    
    let subClass = SubClass()
    
    subClass.object = ObjectClass()
    

    将上述解决方案与我的子类一起使用:

    class SubNode: SKSpriteNode {
        
        private var _previousVelocity: [CGVector?] = []
        var previousVelocity: CGVector {
            _ = physicsBody?.velocity
            return (_previousVelocity.first ?? CGVector.zero)!
        }
        
        override var physicsBody: SKPhysicsBody? {
            get {
                if !_previousVelocity.contains(super.physicsBody?.velocity) {
                    _previousVelocity.append(super.physicsBody?.velocity)
                    _previousVelocity = _previousVelocity.suffix(2)
                }
                return super.physicsBody
            }
            set {
                super.physicsBody = newValue
            }
        }
    }
    

    从我最初的测试来看,这似乎到目前为止有效:

    let subNode = SubNode()
    subNode.physicsBody = SKPhysicsBody()
    subNode.physicsBody?.velocity = CGVector(dx: 10, dy: 10)
    subNode.physicsBody?.velocity = CGVector(dx: 0, dy: 0)
    //true: subnode.previousVelocity == CGVector(dx: 10, dy: 10)
    

    更新:

    我发现这个解决方案的一个问题是,当 ObjectClass() 中的对象首先创建为自己的变量,然后直接通过变量进行更改时,子类的 getter 将不会被触发,直到通过它访问子类。在我的情况下这不是问题,但绝对不理想。

    let subClass = SubClass()
    
    let object = ObjectClass()
    
    subClass.object = object
    
    // This won't trigger the getter obviously since the subclass is not accessed.
    object.name = "New Name"
    object.name = "Another Name"
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-06
      • 2014-04-18
      • 2020-04-07
      • 2018-10-05
      • 2017-09-07
      • 1970-01-01
      • 1970-01-01
      • 2014-12-20
      相关资源
      最近更新 更多