我的应用程序在下面第2行排序时发生崩溃。当NSNotification
进入触发排序并刷新显示时,这发生在ViewController
的方法中。
我的理解是,第1行上的devices
数组是从字典创建的新数组,因此访问元素是非常安全的,即使字典可能会改变。
即使serialID
(aString?
)在排序过程中发生了变化,我也不认为这会导致崩溃。
我错过了什么?什么可能会导致排序中的错误访问?
1: var devices = deviceDict.valuesArray() // See Edit below
2: let sortedDevices = devices.sorted(by: { ($0.serialID ?? "") < ($1.serialID ?? "") })
我不知道如何复制这个。我只在下面这样的崩溃报告中看到过。
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000f9a70f7c0
VM Region Info: 0xf9a70f7c0 is not in any region. Bytes after previous region: 55741315009 Bytes before following region: 630130752
REGION TYPE START - END [ VSIZE] PRT/MAX SHRMOD REGION DETAIL
MALLOC_NANO 280000000-2a0000000 [512.0M] rw-/rwx SM=COW
---> GAP OF 0xd20000000 BYTES
commpage (reserved) fc0000000-1000000000 [ 1.0G] ---/--- SM=NUL ...(unallocated)
Termination Signal: Segmentation fault: 11
Termination Reason: Namespace SIGNAL, Code 0xb
Terminating Process: exc handler [4510]
Triggered by Thread: 9
...
Thread 9 Crashed:
0 libobjc.A.dylib 0x00000001a6ae2dd0 objc_release + 16 (objc-runtime-new.h:1589)
1 OAPP 0x00000001044c35e4 specialized UnsafeMutableBufferPointer._stableSortImpl(by:) + 364 (DeviceViewController.swift:0)
2 OAPP 0x00000001044c17f0 specialized MutableCollection<>.sort(by:) + 100
2 OAPP 0x00000001044baf60 DeviceViewController.generateDeviceList() + 1644
4 OAPP 0x00000001044b67ac DeviceViewController.refreshDeviceTableView() + 524 (DeviceViewController.swift:655)
5 OAPP 0x00000001044bb7a4 DeviceViewController.handleSyncStateNotification(_:) + 680 (DeviceViewController.swift:821)
...
编辑:deviceDict
实际上是在一个自定义类,包装一个字典一些线程安全的访问器,我把字典值转换为该类中的数组。(在我最初的帖子中,我试图简化代码,以免分散对数组操作的崩溃问题,但我似乎通过简化来混淆事情。对不起!)
public class SafeDict<Element> {
fileprivate let queue = DispatchQueue(label: "com.myapp.SafeDict", attributes: .concurrent)
fileprivate var dictionary:[String:Element] = [:]
...
public func valuesSafe() -> Dictionary<String, Element>.Values {
var returnValues: Dictionary<String, Element>.Values = Dictionary<String, Element>().values
queue.sync {
returnValues = self.dictionary.values
}
return returnValues
}
public func valuesArray() -> [Element] {
var values: [Element] = []
queue.sync {
for element in self.valuesSafe() {
values.append(element)
}
}
return values
}
}
devices
不是Array。这是Dictionary.Values
。这是一个延迟视图到deviceDict
但这些都不重要。在多个线程中对deviceDict的可变访问总是未定义的行为。如果serialID
可能在没有某种同步的情况下改变另一个线程,那么您已经犯了一个错误。deviceDict.values()
行无效;与以后的访问无关。
但是当然sorted
行更有可能出现未定义行为,因为它要遍历很多值,如果deviceDict
必须调整大小或以其他方式修改其备份存储,这些值可能会移动到内存中。