Сбой iOS - имя селектора найдено в текущих регистрах аргументов: сохранить - PullRequest
0 голосов
/ 12 октября 2018

В панели инструментов хоккейного приложения я получаю сбои со следующими подсказками:

Тип исключения: SIGTRAP Коды исключений: # 0 при 0x1943f61e8 Сбой потока: 7 Информация о приложении: имя селектора, найденное в регистре текущего аргумента:retain

Тип исключения: SIGSEGV Коды исключений: SEGV_ACCERR at 0x568855a90 Сбой потока: 18 Информация о приложении: имя селектора objc_msgSend (): retain

Обе группы аварийного обращения используют один и тот же код, но каким-то образом они имеют разныеописание сбоя, которое, по моему мнению, должно быть той же основной причиной.

Вот как выглядит мой код:

поток 1:

dispatch_queue_t queue;
@synchronized (self) {
    queue = _mySerialQueue;
}
dispatch_async(queue, ^{ // Crash happens here
    if (_ivar) {
        ...
    }
});

поток 2:

@synchronized (self) {
    _mySerialQueue = dispatch_queue_create(...);
}

Может ли этот код столкнуться с проблемой ARC?

1 Ответ

0 голосов
/ 12 октября 2018

При условии, что (пожалуйста, проверьте это)

  • _mySerialQueue является переменной экземпляра
  • _mySerialQueue доступен только в @synchronized(self) блоках
  • Вы не получаете доступ к _mySerialQueue через какое-либо свойство или кодировку значения ключа ([theObject valueForKey:"mySerialQueue"])
  • Весь код, который вы разместили, работает с ARC

Я вижу только одну причину, почемуприведенный выше код может привести к сбою, как это происходит.Я все еще не уверен на 100%, но вот мой выстрел:

self находится в процессе освобождения, когда происходит сбой.Это можно проверить, если вы очистите iVar в dealloc:

- (void)dealloc {
    @synchronized(self) {
        _mySerialQueue = nil;
    }

    // ...
}

, эти сбои будут крайне редкими, например, как минимум один из ста.Если это случается чаще, я думаю, что проблема в другом месте.

После изменения приложение все равно будет аварийно завершать работу, но EXC_BAD_ACCESS будет находиться в нижней области памяти, потому что вы разыменовываете нулевой указатель при вызовеdispatch_async(nil, ...).Место сбоя, скорее всего, будет 0x00000050 или аналогично низким адресом.

Почему я так думаю? Когда объект разрушается, iVars уничтожаются в отдельном проходеметод с именем .cxx_destruct.Когда это происходит, iVar может быть в процессе освобождения, но в то же время переменная все еще указывает на объект, потому что он никогда не очищается.

Важно: Если это работает, он просто заменит один редкий сбой на другой редкий сбой, потому что это будет означать, что где-то есть условие гонки self.


Другое возможное решение - попытаться воспроизвести проблему с дезинфицирующее средство для нитей .В большинстве случаев он может довольно быстро отследить такие проблемы.

...