建立双向数据绑定注意事项
基本数据类型的的读写是同步执行的,只有向 大小树 的上级更新状态才是异步的。
这也意味着直接同时对一个原始数据绑定观察者和写者,会导致死锁。
extends Node
const Utils = Gdvm.Utils
const DataTree = Gdvm.DataTree
const ObserverPackTree = Gdvm.ObserverPackTree
const WriterPackTree = Gdvm.WriterPackTree
const DataNode = Gdvm.DataNode
const DataNodeInt = Gdvm.DataNodeInt
class ObjWithInt:
signal changed
var data: int:
set(value):
data = value # !!!!!!!!!!!!!!!!!
changed.emit()
func _ready() -> void:
var obj := ObjWithInt.new()
var data_tree := DataTree.new(0)
var observer := ObserverPackTree.new({
"base": obj,
"options": ObserverPackTree.opts({
"path": ":data",
"changed": func(source: Object, _property_path: NodePath) -> Signal:
return (source as ObjWithInt).changed
})
})
data_tree.observe(observer)
var root := data_tree.get_root() as DataNodeInt
var _writer := WriterPackTree.new(root, {
"base": obj,
"options": WriterPackTree.opts({
"path": ":data"
})
})
prints("Initial data node value:", root.value()) # 0
prints("Initial target value:", obj.data) # 0
root.render(1)
prints("Root rendered node value:", root.value()) # 1
prints("Root rendered target value:", obj.data) # 1
obj.data = 2
prints("Target changed node value:", root.value()) # 2
prints("Target changed target value:", obj.data) # 2
为此,你应该额外写一个卫士来防止重复修改,把 data 属性改成这样:
var data: int:
set(value):
if value != data:
# 防死循环设计
data = value
changed.emit()
单项数据绑定是GDVM的核心规则之一,所以不太推荐有双向数据绑定需求的场景使用它。