【发布时间】:2018-06-08 13:57:02
【问题描述】:
我的应用程序因以下消息而崩溃:
同时访问0x7fa4a8e10d68,但修改需要独占访问。
如何找出0x7fa4a8e10d68 对应的内容?当我尝试搜索它时它没有出现,请参阅我附加的图像。
根据提供的屏幕截图,如何知道是gallaryModel 还是galleries[indexPath.row] 是问题所在?
【问题讨论】:
我的应用程序因以下消息而崩溃:
同时访问0x7fa4a8e10d68,但修改需要独占访问。
如何找出0x7fa4a8e10d68 对应的内容?当我尝试搜索它时它没有出现,请参阅我附加的图像。
根据提供的屏幕截图,如何知道是gallaryModel 还是galleries[indexPath.row] 是问题所在?
【问题讨论】:
您可以通过多种方式对此进行调查。在简单的情况下,运行时错误消息可以为您提供足够的线索来确定冲突是什么。例如,在您的情况下,错误消息会通知您当前访问是 修改 - 因此在这样的行中:
galleryModel.requestNameUpdate(for: galleries[indexPath.row], with: resulting)
假设galleryModel是一个值类型,而requestNameUpdate是一个mutating方法,则必须与galleryModel发生冲突,因为该行上的所有其他访问都是读取。
在大多数情况下,您可以使用的另一个选项是查看先前访问发生的位置,这应该可以为您提供足够的信息来推断哪个变量存在冲突。为了演示,让我们考虑以下程序:
func bad(_ x: inout [String], _ body: () -> Void) {
body()
}
var s = [String]()
var a = "hello"
do {
bad(&s) {
s.append(a) // Thread 1: Simultaneous accesses to 0x100556a50 [...]
}
}
在 Xcode 中运行它会暂停上述行的执行:
如果我们点击堆栈跟踪中的“上一次访问(修改)开始于”(以红色突出显示),Xcode 将向我们显示上一次访问开始的行:
在这个例子中,这些信息足以知道变量 s 是冲突的变量。
在更一般的情况下,您可以检查变量的内存地址以确定哪个是冲突的。继续上一个示例,我们可以在变量查看器中右键单击任何显示的变量,然后通过选择“查看内存 [...]”来调出内存查看器:
这将为我们提供变量的地址(以红色突出显示)。如果此地址与错误消息中显示的地址匹配(例如在本例中),我们就发现了冲突。
另一个选项是查看反汇编,看看如果没有发生冲突,我们会尝试做什么。我们可以在调试器中通过运行disassemble -a <address> 并使用swift_beginAccess 上方的堆栈帧的地址来执行此操作:
然后您想要导航到上面以红色突出显示的偏移量,在本例中为 + 174,它为我们提供了调用 swift_beginAccess 后的位置:
然后我们可以看到,如果不是因为冲突,我们会调用Array 的append(_:) 方法(在+ 193),因为这是由swift_beginAccess/ 保护的调用swift_endAccess 对。由此我们可以推断出冲突的变量一定是s。
【讨论】:
gallaryModel 的看法是正确的-它是struct,功能标记为mutating。非常感谢!
我的问题是我使一个类符合一个没有用:class 或:AnyObject 标记的协议。在我添加之后
即
protocol MyProtocol: AnyObject {} //crashing happening without :AnyObject
class MyClass: MyProtocol {...}
崩溃停止了!
【讨论】: