用于追踪属性访问的库。
可以获取以下信息
警告 它不能正确工作,具体取决于 Swift 优化标志的设置。在默认设置下,只有 Debug 构建版本有效。
例如,当我们定义
struct Item {
@Traced(trace(_:_:))
var title = "hello"
}
func trace<P, V>(_ access: PropertyAccess<P, V>, _ tracedKeyPath: KeyPath<P, Traced<P, V>>?) {
print("\n[Access]------------------")
print("\(access.accessor.description)")
print("called from: \(access.callStackInfo.demangledSymbolName ?? "unknown")")
if let parent = access.parent {
print("parent: \(parent)")
}
if let keyPath = access.keyPath {
print("keyPath: \(keyPath)")
}
if let tracedKeyPath {
print("tracedKeyPath: \(tracedKeyPath)")
}
print("----------------------------")
}
假设执行以下操作
let item = Item()
print(item.title)
item.title = "new value"
item.printTitle()
此时,将调用指定的 trace
函数,输出如下
[Access]------------------
getter(String): initial value
called from: PropertyTracerTests.PropertyTracerTests.test() -> ()
----------------------------
initial value
[Access]------------------
setter(String): initial value => new value
called from: PropertyTracerTests.PropertyTracerTests.test() -> ()
----------------------------
[Access]------------------
getter(String): new value
called from: PropertyTracerTests.PropertyTracerTests.Item.printTitle() -> ()
----------------------------
new value
也可以设置要在回调中接收的附加信息,如下所示
struct Item {
// specify parent and variable type
@Traced<Item, String>(trace(_:_:))
var title = "initial value"
init(title: String = "initial value") {
self.title = title
// parent object
_title.parent.value = copiedOwn
// keyPath
_title.keyPath.value = \Self.title
// traced keyPath
_title.tracedKeyPath.value = \Self._title
}
func printTitle() {
print(title)
}
func copiedOwn() -> Self {
let copied = self
return self
}
}
例如,如果在上面描述的 trace
函数中直接访问父属性会发生什么?
在 trace
函数中访问属性将导致进一步调用 trace
函数,从而导致无限循环。
因此,有一些方法允许在不追踪的情况下操作值。
不追踪地获取值
let title = item._title.untracedGet()
不追踪地设置值
let newTitle = "new"
item._title.untracedSet(newTitle)
停止追踪
item._title.untraced()
重新开始追踪
item._title.traced()
以下定义将导致追踪 Item 类型的所有属性。
它由宏定义,parent
和 keyPath
会自动设置。
附加了 @NoTraced
属性的属性将被排除在追踪之外。
@PropertyTraced(trace(_:_:))
class ClassType1 {
static let staticVar = ""
var value1: String = "こんにちは"
var value2: Int = 12
@NoTraced
var value3: Double = 1.0
func modify() {
value1 = "hello"
value2 *= 2
value3 = 14
}
}
func trace(_ access: AnyPropertyAccess, _ tracedKeyPath: AnyKeyPath?) {
print("\n[Access]------------------")
print("\(access.accessor.description)")
print("called from: \(access.callStackInfo.demangledSymbolName ?? "unknown")")
if let parent = access.parent {
print("parent: \(parent)")
}
if let keyPath = access.keyPath {
print("keyPath: \(keyPath)")
}
if let tracedKeyPath {
print("tracedKeyPath: \(tracedKeyPath)")
}
print("----------------------------")
}
PropertyTracer 在 MIT 许可证下发布。请参阅 LICENSE