IOS-SWIFT- 如何解决Apple文档代码中关于KVO的警告?为什么 Xcode 自动更正引入了错误?
IOS-SWIFT- How to resolve the warning from the Apple Documentation Code about KVO? Why Xcode auto correction introduced an error?
为了学习KVO,我复制了https://developer.apple.com/documentation/swift/cocoa_design_patterns/using_key_value_observing_in_swift的代码。如下
class MyObjectToObserve: NSObject {
@objc dynamic var myDate = NSDate(timeIntervalSince1970: 0) // 1970
func updateDate() {
myDate = myDate.addingTimeInterval(Double(2 << 30)) // Adds about 68 years.
}
}
class MyObserver: NSObject {
@objc var objectToObserve: MyObjectToObserve
var observation: NSKeyValueObservation?
init(object: MyObjectToObserve) {
objectToObserve = object
super.init()
observation = observe(
\.objectToObserve.myDate,
options: [.old, .new]
) { object, change in
print("myDate changed from: \(change.oldValue!), updated to: \(change.newValue!)")
}
}
}
let observed = MyObjectToObserve()
let observer = MyObserver(object: observed)
observed.updateDate()
倒数第二行将导致警告,因为未使用 observer
。在我按照 Xcode 的建议将 let observer
替换为 _
之后,警告消失了,但它会给出运行时错误:
线程 1:EXC_BAD_ACCESS(代码=EXC_I386_GPFLT)
我的目标是获得以下问题的答案:
1.Does 谁知道为什么会出错?
2.How 解决警告?
3.Is Swift 中的 KVO 这个例子是最新的吗?语法级别?
Apple 文档中的代码片段仅作为示例 - 这不是完整的实现。
据推测,您将使用 observer
执行其他操作,此时您将不再收到 "not used" 警告。
示例用法(仅用于演示,不被视为生产代码):
class ExampleViewController: UIViewController {
var observed: MyObjectToObserve!
var observer: MyObserver!
override func viewDidLoad() {
super.viewDidLoad()
observed = MyObjectToObserve()
observer = MyObserver(object: observed)
}
@IBAction func didTap(_ sender: Any) {
observed.updateDate()
}
}
创建一个新的视图控制器;将其 class 设置为 ExampleViewController
;添加一个按钮并将其连接到 @IBAction func didTap
.
运行 应用程序.. 每次点击按钮时,您都会在调试控制台中看到 print()
输出。
具有讽刺意味的是,Apple 的示例比它需要的更复杂。也就是说,甚至不需要 MyObserver
对象。您可以简单地在您实际观察的对象上调用 observe
。
这看起来像下面这样:
class MyObjectToObserve: NSObject {
@objc dynamic var myDate = NSDate(timeIntervalSince1970: 0) // 1970
func updateDate() {
myDate = myDate.addingTimeInterval(Double(2 << 30)) // Adds about 68 years.
}
}
let observed = MyObjectToObserve()
let observation = observed.observe(\MyObjectToObserve.myDate, options: [.old, .new]) { object, change in
print("myDate changed from: \(change.oldValue!), updated to: \(change.newValue!)")
}
observed.updateDate()
不幸的是,这个更简单的版本仍然存在原来的问题。您需要 let observation = ...
将其保持在 KVO 工作的范围内,然后您会收到警告。
所以要抑制警告,您需要对结果做一些事情。添加以下行:
_ = observation.hash // Suppress warning on observation
希望编译器能优化它(如果不是,它只是分配一个整数,所以开销可以忽略不计),但它确实可以抑制警告。我包含注释,以便下一个查看代码的程序员不会删除看似无用的行。
注意:我很少再使用 KVO,因为我发现 Combine 更强大,也更少麻烦。然而,有时它仍然是必要的。即使在大多数情况下,我的代码看起来更像@DonMag 的代码,其中对必要对象的引用作为控制器的成员保存。我确实使用这种抑制“hack”的地方是在我的一些单元测试中,我在其中手动设置 KVO 并且不希望我的代码显示警告。
为了学习KVO,我复制了https://developer.apple.com/documentation/swift/cocoa_design_patterns/using_key_value_observing_in_swift的代码。如下
class MyObjectToObserve: NSObject {
@objc dynamic var myDate = NSDate(timeIntervalSince1970: 0) // 1970
func updateDate() {
myDate = myDate.addingTimeInterval(Double(2 << 30)) // Adds about 68 years.
}
}
class MyObserver: NSObject {
@objc var objectToObserve: MyObjectToObserve
var observation: NSKeyValueObservation?
init(object: MyObjectToObserve) {
objectToObserve = object
super.init()
observation = observe(
\.objectToObserve.myDate,
options: [.old, .new]
) { object, change in
print("myDate changed from: \(change.oldValue!), updated to: \(change.newValue!)")
}
}
}
let observed = MyObjectToObserve()
let observer = MyObserver(object: observed)
observed.updateDate()
倒数第二行将导致警告,因为未使用 observer
。在我按照 Xcode 的建议将 let observer
替换为 _
之后,警告消失了,但它会给出运行时错误:
线程 1:EXC_BAD_ACCESS(代码=EXC_I386_GPFLT)
我的目标是获得以下问题的答案:
1.Does 谁知道为什么会出错?
2.How 解决警告?
3.Is Swift 中的 KVO 这个例子是最新的吗?语法级别?
Apple 文档中的代码片段仅作为示例 - 这不是完整的实现。
据推测,您将使用 observer
执行其他操作,此时您将不再收到 "not used" 警告。
示例用法(仅用于演示,不被视为生产代码):
class ExampleViewController: UIViewController {
var observed: MyObjectToObserve!
var observer: MyObserver!
override func viewDidLoad() {
super.viewDidLoad()
observed = MyObjectToObserve()
observer = MyObserver(object: observed)
}
@IBAction func didTap(_ sender: Any) {
observed.updateDate()
}
}
创建一个新的视图控制器;将其 class 设置为 ExampleViewController
;添加一个按钮并将其连接到 @IBAction func didTap
.
运行 应用程序.. 每次点击按钮时,您都会在调试控制台中看到 print()
输出。
具有讽刺意味的是,Apple 的示例比它需要的更复杂。也就是说,甚至不需要 MyObserver
对象。您可以简单地在您实际观察的对象上调用 observe
。
这看起来像下面这样:
class MyObjectToObserve: NSObject {
@objc dynamic var myDate = NSDate(timeIntervalSince1970: 0) // 1970
func updateDate() {
myDate = myDate.addingTimeInterval(Double(2 << 30)) // Adds about 68 years.
}
}
let observed = MyObjectToObserve()
let observation = observed.observe(\MyObjectToObserve.myDate, options: [.old, .new]) { object, change in
print("myDate changed from: \(change.oldValue!), updated to: \(change.newValue!)")
}
observed.updateDate()
不幸的是,这个更简单的版本仍然存在原来的问题。您需要 let observation = ...
将其保持在 KVO 工作的范围内,然后您会收到警告。
所以要抑制警告,您需要对结果做一些事情。添加以下行:
_ = observation.hash // Suppress warning on observation
希望编译器能优化它(如果不是,它只是分配一个整数,所以开销可以忽略不计),但它确实可以抑制警告。我包含注释,以便下一个查看代码的程序员不会删除看似无用的行。
注意:我很少再使用 KVO,因为我发现 Combine 更强大,也更少麻烦。然而,有时它仍然是必要的。即使在大多数情况下,我的代码看起来更像@DonMag 的代码,其中对必要对象的引用作为控制器的成员保存。我确实使用这种抑制“hack”的地方是在我的一些单元测试中,我在其中手动设置 KVO 并且不希望我的代码显示警告。