范围崩溃的不可能指数

时间:2019-06-14 15:50:28

标签: swift

在我正在研究的应用程序中,我必须通过指定数组中元素的索引来获取数组的一个元素,例如array[index]。 这是一个简单的UICollectionView,其中填充了我从数组中获取的项目。

为了防止索引超出范围异常,我正在这样做:

guard index < array.count else { return }
return array[index]

即使有这个后卫,我在array[index]行上也得到了索引超出范围异常(但并非总是如此)。

我不知道怎么回事。

我什至还添加了另一张支票:

extension Collection where Indices.Iterator.Element == Index {
    subscript (optional index: Index) -> Iterator.Element? {
        return indices.contains(index) ? self[index] : nil
    }
}

所以我正在这样做(这是应用程序中的实际代码片段):

...
guard let section = chatSections[optional: indexPath.section] else {
    return nil
}
guard indexPath.item < section.itemViewModels.count else {
    return nil
}
return section.itemViewModels[optional: indexPath.item]

这并不总是发生,但有时我在那里出现了索引超出范围异常。

Exception

我整天都在调试,试图找出崩溃发生时的情况,以便我也许能找出原因,但这似乎是随机发生的。

有人知道这怎么可能吗?有人遇到过这种问题吗?

2 个答案:

答案 0 :(得分:1)

您是否有机会从后台线程/队列进行任何更新?如果是这样,请确保您的UI交互是在主线程/队列上完成的,并且您没有更改UI背后的数组内容。

也就是说,如果您要在一个队列中更改数组内容并尝试在这种情况下更新UI,则可能在数组修改到其他位置之前传递了保护声明,然后在其余时间执行与UI交互的代码,索引my不再有效。

没有更完整的图景,很难说是怎么回事,但是为防止神秘变化的数组索引而添加的所有这些边界检查是多线程恶作剧的重要线索。

答案 1 :(得分:-2)

  • 我相信您可以对数据源数组进行多重访问(尝试通过多线程访问该数组中的添加/删除操作)。
  • 要解决此问题,您应在访问数组时使用一些方法来强制同步,使用信号量或DispatchGroup的方法有多种。

我建议使用信号量,因为该数组被视为共享资源,例如:

    private let semaphore = DispatchSemaphore(value: 1)
    private var _array:[Item] = []
    var array:[Item] {
        get {
            semaphore.wait()
            let result = self._allMessages
            defer {
                semaphore.signal()
            } 
            return result
        }
        set {
            semaphore.wait()
            self. _array = newValue
            semaphore.signal()
        }
    }

并使用array变量访问数组数据源而不是私有_array