Swift 不应该发生的快速内存冲突
我正在从事一个SwiftUI项目,在那里我使用MVVM架构 从SwiftUI视图更改视图模型对象属性时,会导致视图模型对象中的内存冲突崩溃 错误类型为:同时访问0x600003591b48,但修改需要独占访问 在步骤中,会发生以下情况:Swift 不应该发生的快速内存冲突,swift,swiftui,Swift,Swiftui,我正在从事一个SwiftUI项目,在那里我使用MVVM架构 从SwiftUI视图更改视图模型对象属性时,会导致视图模型对象中的内存冲突崩溃 错误类型为:同时访问0x600003591b48,但修改需要独占访问 在步骤中,会发生以下情况: 视图模型属性已从视图更改 查看模型属性更改模型属性 模型属性通知有关更改的信息 视图模型接收更改通知 视图模型访问模型对象 内存冲突导致崩溃 相关代码片段如下所示。Xcode项目是一个标准的SwiftUI项目 首先单击“添加”按钮,然后单击“修改”按钮后,将发生
import Foundation
import SwiftUI
import Combine
struct ContentView: View {
@ObservedObject var item: ViewModel<Model> = ViewModel<Model>()
var body: some View {
VStack {
Button("Add", action: { item.add(model:Model()) })
Button("Modify", action: { item.selected.toggle() })
}
}
}
protocol ModelType {
var objectDidChange: ObservableObjectPublisher { get }
var selected: Bool { get set }
}
class Model: ModelType {
let objectDidChange = ObservableObjectPublisher()
var selected = false {
didSet {
objectDidChange.send()
}
}
}
class ViewModel<Model:ModelType>: ObservableObject {
var selected = false {
didSet {
model.selected = selected
}
}
func add(model: Model) {
self.model = model
cancellable = model.objectDidChange.sink(receiveValue: { _ in
self.update()
})
}
private var model: Model! = nil
private var cancellable: AnyCancellable? = nil
func update() {
// Crash log: Simultaneous accesses to 0x600003591b48, but modification requires exclusive access.
print("update \(model.selected)")
}
}
<代码>导入基础
导入快捷键
进口联合收割机
结构ContentView:View{
@ObservedObject变量项:ViewModel=ViewModel()
var body:一些观点{
VStack{
按钮(“添加”,操作:{item.Add(model:model())})
按钮(“修改”,操作:{item.selected.toggle()})
}
}
}
协议模型类型{
var objectDidChange:observeObjectPublisher{get}
选择的变量:Bool{get set}
}
类模型:ModelType{
让objectDidChange=observeObjectPublisher()
所选变量=false{
迪塞特{
objectDidChange.send()
}
}
}
类ViewModel:ObservableObject{
所选变量=false{
迪塞特{
model.selected=已选择
}
}
func添加(模型:模型){
self.model=model
Cancelable=model.objectDidChange.sink(receiveValue:{in
self.update()
})
}
私有风险值模型:模型!=nil
私有var可取消:anyCancelable?=nil
func update(){
//崩溃日志:同时访问0x600003591b48,但修改需要独占访问。
打印(“更新\(所选型号)”)
}
}
简短版本:对于
型号
,需要任何对象
长版本:
你试图从<代码> >模型> <代码>中读取,而你正处于“代码>自我>模型< /代码>的中间。当您说“如果将“更新”代码移到“receiveValue”闭包中,则不会发生错误”时,这是不完全正确的。我想你的意思是你写了这个:
cancellable = model.objectDidChange.sink(receiveValue: { _ in
print("update \(model.selected)")
})
这很有效,但这是完全不同的代码model
在本例中是局部变量,而不是属性self.model
。如果您这样写,您将得到相同的崩溃:
cancellable = model.objectDidChange.sink(receiveValue: { _ in
print("update \(self.model.selected)")
})
让您来到这里的路径是:
- ViewModel.selected.didSet
- 写信给Model.selected为什么不使用ObserveObject协议(和@Published)?好问题?是的。作为简化的一部分,我将其删除,以查看它是否会改变有关错误的某些内容。它没有改变任何东西,我也没有把原来的代码放回去;这就是我删除评论的原因。我想出来了。我正在写,谢谢你的回答。我怀疑这就是问题所在,首先,我尝试像这样约束泛型。我是这样做的:class ViewModel:observeObject不幸的是,这并没有产生与直接在协议上设置约束相同的效果。我将状态更改为unanswered,因为我仍然很难找到适合我的解决方案。问题是让协议从任何对象继承只能部分解决问题。如果添加更多继承,问题仍然存在。例如,如果协议是这样构造的:
我就无法重现后一个示例(ModelType需要AnyObject和其他两个协议)。您需要发布代码来演示这一点。(我可以复制protocolmodeltype:AnyObject、ProtocolA、ProtocolB
崩溃,我建议你为它打开一个Swift bug。尽管我有点怀疑需要这么多的协议和层,但这应该会起作用;你的设计可能过于复杂了。即使如此,它也应该会起作用。)如果将“objectDidChange”发布者放入ProtocolA,而“selected”布尔属性,加上ProtocolB中加入了一个新的description()函数,就会发生崩溃。然而,我注意到它不会崩溃的组合。最后,我无法避免在我的原始项目中有很多协议,因此,我现在使用一种黑客方法,防止视图模型属性导致回调到视图模型对象。我认为这一切都是一个应该报告的bug,希望有一天能够解决(在我最初的项目中,约束协议继承了7-9个次要协议)。我再次改变了主意。原始帖子没有将泛型约束为类,因此答案是正确的。此外,我将在Swift中以错误的形式报告该问题。模型:AnyObject&ModelType
print("update \(model!)")
protocol ModelType: AnyObject { ... }