简体   繁体   English

如何观察继承对象属性的变化并存储以前的值?

[英]How to observe changes, and store previous values, of an inherited object's property?

Set Up:设置:

I'm subclassing SKSpriteNode() to create a custom subclass called SubNode() .我将SKSpriteNode()子类化以创建一个名为SubNode()的自定义子类。

The SKSPriteNode() class has a property called physicsBody which stores a SKPhysicsBody() object. SKSPriteNode() class 有一个名为physicsBody的属性,它存储一个SKPhysicsBody() object。 SKPhysicsBody has a property called 'velocity' that is a CGVector() SKPhysicsBody有一个名为“velocity”的属性,它是一个CGVector()

Goal:目标:

In my subclass I'd like to have a variable which always keeps the previous CGVector() .在我的子类中,我想要一个始终保留以前的CGVector()的变量。 Meaning as soon as I call subNode.physicsBody?.velocity = CGVector(dx: 10, dy: 10) for example.例如,只要我调用subNode.physicsBody?.velocity = CGVector(dx: 10, dy: 10)就意味着。 subNode.previousVelocity should be set to the previous subNode.physicsBody?.velocity value. subNode.previousVelocity应该设置为之前的subNode.physicsBody?.velocity值。

Issue问题

If velocity would just be an inherited property of the superclass I could just override the property and attach an didSet observer.如果velocity只是超类的继承属性,我可以override该属性并附加一个didSet观察者。 But since velocity is a property of SKPhysicsBody() and the SKPhysicsBody() object doesn't change when one of its properties changes, didSet doesn't get triggered and I'm unable to listen to its changes.但是由于velocitySKPhysicsBody()的一个属性,而SKPhysicsBody() object 在其中一个属性发生变化时不会发生变化, didSet不会被触发,我无法听到它的变化。

Please ask for more clarification if my explanation is unclear.如果我的解释不清楚,请要求更多澄清。

My subclass:我的子类:

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
        }
    }
}

Creating the object subNode from the SubNode() subclass, setting the physics body and then the velocity"从 SubNode() 子类创建 object 子节点,设置物理体,然后设置速度"

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)

This is only a partial answer.这只是部分答案。 Only an attempt to find a solution to the issue.只是试图找到解决问题的方法。

I've tried to somehow find a workaround.我试图以某种方式找到解决方法。 I noticed that as soon as the property of an object changes the getter of the object is triggered before.我注意到,只要 object 的属性发生更改,之前就会触发 object 的吸气剂。 I created the following playground file and it seems to work.我创建了以下游乐场文件,它似乎工作。 As soon as I change the text of the object, the previous name is stored in another variable.只要我更改 object 的文本,以前的名称就会存储在另一个变量中。 But from my testing this seems to work.但从我的测试来看,这似乎有效。 I'm not sure if my logic is correct or if I'm missing something, it might also be a bit too much to achieve something that should be simpler.我不确定我的逻辑是否正确,或者我是否遗漏了一些东西,实现应该更简单的东西也可能有点太多了。

Below I added the code for my subclass and from what I could test so far it actually works.下面我为我的子类添加了代码,并且到目前为止我可以测试它确实有效。 However I'd appreciate some feedback as in where there could be pitfalls to this solution.但是,我希望得到一些反馈,因为该解决方案可能存在缺陷。

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()

Using the above solution with my subclass:将上述解决方案与我的子类一起使用:

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
        }
    }
}

From my initial testing this seems to work so far:从我最初的测试来看,这似乎到目前为止有效:

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)

Update:更新:

One issue with this solution I have found is, that when the object from ObjectClass() is created as its own variable first and then changed through the variable directly, the getter of the subclass will not get triggered until it is accessed through the subclass.我发现这个解决方案的一个问题是,当 ObjectClass() 中的 object 首先创建为自己的变量,然后直接通过变量进行更改时,子类的 getter 将不会被触发,直到通过子类访问它。 It's not an issue in my case but definitely not ideal.就我而言,这不是问题,但绝对不理想。

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"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM