Swift 5,“对内存的独占访问”强制现在默认为发布版本启用,如 Swift.org 博客文章中所述:
我理解这个特性背后的原因,但是有了新的Combine
框架,我觉得一些非常正常的设计模式现在会被打破,我很好奇如何最好地解决它们。
部分代码对Combine
模型中的更改做出反应是很自然的,因此它们可能需要从模型刚刚更改的属性中读取。但是他们不能再这样做了,因为它会在您尝试读取当前正在设置的值时触发内存异常。
考虑以下示例:
struct PasswordProposal {
let passwordPublisher = CurrentValueSubject<String, Never>("1234")
let confirmPasswordPublisher = CurrentValueSubject<String, Never>("1234")
var password:String {
get { passwordPublisher.value }
set { passwordPublisher.value = newValue }
}
var confirmPassword:String {
get { confirmPasswordPublisher.value }
set { confirmPasswordPublisher.value = newValue }
}
var isPasswordValid:Bool {
password == confirmPassword && !password.isEmpty
}
}
class Coordinator {
var proposal:PasswordProposal
var subscription:Cancellable?
init() {
self.proposal = PasswordProposal()
self.subscription = self.proposal.passwordPublisher.sink { [weak self] _ in
print(self?.proposal.isPasswordValid ?? "")
}
}
// Simulate changing the password to trigger the publisher.
func changePassword() {
proposal.password = "7890"
}
}
// --------------------------------
var vc = Coordinator()
vc.changePassword()
一旦changePassword()
被调用,互斥性强制执行将抛出异常,因为该属性password
将在当前被写入时尝试从中读取。
请注意,如果您将此示例更改为使用单独的后备存储属性而不是CurrentValueSubject
它,则会导致相同的异常。
但是,如果您PasswordProposal
从 a更改struct
为 a class
,则不再抛出异常。
当我考虑如何Combine
在现有代码库以及SwiftUI
. 在旧的委托模型中,委托从委托回调中查询发送对象是很常见的。在 Swift 5 中,我现在必须非常小心,这些回调没有一个可能从启动通知的属性中读取。
其他人是否遇到过这种情况,如果有,您是如何解决的?Apple 经常建议我们应该在structs
有意义的地方使用,但也许具有已发布属性的对象是它没有的那些领域之一?