Не удалось "Dictionary.subscript.getter" все в пределах одного dispatchQueue - PullRequest
1 голос
/ 06 апреля 2020

У меня есть несколько производственных сбоев на iOS, которые выглядят так:

Crashed: com.superdupertango.Server.CallbackRunQueue
0  SDTServer                      0x102b78ed0 specialized Dictionary.subscript.getter + 4378562256 (<compiler-generated>:4378562256)
1  SDTServer                      0x102a22fec closure #1 in Server.processError(_:) + 4377161708 (<compiler-generated>:4377161708)
2  SDTServer                      0x10257ce90 thunk for @escaping @callee_guaranteed () -> () + 4372287120 (<compiler-generated>:4372287120)

Это код, вызывающий проблемы (весь код в этой области - Swift5):

    private let callbackRunQueue = DispatchQueue(label: "com.superdupertango.Server.CallbackRunQueue", qos: DispatchQoS.userInitiated, target: nil)
    var bodyCompletionBlocks: [String: ((Data?, Error?, String) -> Void)] = [:]

...

    private init() {
        NotificationCenter.default.addObserver(self, selector: #selector(self.processError(_:)), name: Notification.Name.SDTServerWriteFailed, object: nil)
    }

...

    @objc private func processError(_ notification: Notification) {
        guard let userInfo = notification.userInfo, let requestId = userInfo["requestId"] as? String else {
            return
        }
        self.callbackRunQueue.async {
            DLog("Server.processError (\(requestId)): Got Error for request. Shutting down request.")
            guard let bodyCompletionBlock = self.bodyCompletionBlocks[requestId] else {
                DLog("Server.processError (\(requestId)): Failed getting body completion block. Returning")
                return
            }
            bodyCompletionBlock(Data(), nil, requestId)
            self.bodyCompletionBlocks.removeValue(forKey: requestId)
            self.initialCompletionBlocks.removeValue(forKey: requestId)
        }
    }

Обратите внимание, что callbackRunQueue - это последовательная очередь.

Единственное значение словаря, которое извлекается внутри callbackRunQueue, это self.bodyCompletionBlocks:

            guard let bodyCompletionBlock = self.bodyCompletionBlocks[requestId] else {

Я нашел несколько ссылок на эту ошибку, но все они говорят, что это может быть проблема многопоточного доступа.

Однако в моем коде есть только 3 места, где есть доступ к self.bodyCompletionBlocks, и все они находятся внутри блоков callbackRunQueue.async или callbackRunQueue.sync. Также обратите внимание, что часть этого кода выполняется внутри потоков в GCDWebServer, но, как я уже говорил, я всегда гарантирую, что код выполняется в моей очереди callbackRunQueue, поэтому я не думаю, что это связано с GCDWebServer.

Я думал, что включение чувствительного к потокам кода в блоки asyn c или syn c последовательной очереди защитит от многопоточных проблем с доступом, подобных этой.

Есть идеи?

Спасибо!

...