Потокобезопасный код Objective-C для предотвращения сбоя - PullRequest
2 голосов
/ 20 февраля 2012

Я получил отчет о сбое iPhone с SIGSEGV, и я думаю, что я сузил возможную причину и решение. Так как сбои, вызванные потоками, трудно отладить, я не могу воспроизвести эту проблему, но могу использовать некоторую помощь с моей гипотезой - это правильно?

Мой код использует ASIHttpRequest для загрузки набора файлов с использованием ASINetWorkQueue. Вот упрощенный образец

//initialize download queue and do this code block in a loop for each file

NSURL *fileURL = [NSURL URLWithString:...
__block ASIHTTPRequest *fileRequest = [ASIHTTPRequest requestWithURL:fileURL];

[fileRequest setCompletionBlock:^{
   //do some stuff   
}];
[fileRequest setFailedBlock:^{
    NSString *someError = [NSString stringWithFormat:...
    [self someErrorMethod:someError];       
}];

[downloadQueue addOperation:...

-(void)someErrorMethod(NSString *errorMessage) {
    DDLogWarn(errorMessage);

    if ([self downloadQueue]) {
        for (ASIHTTPRequest *request in [[self downloadQueue] operations]) {
            [request clearDelegatesAndCancel];
        }
        [[self downloadQueue] reset];
    }
 }

Верхние 2 строки отчета о сбое

  • libobjc.A.dylib 0x31846fbc objc_msgSend + 15
  • MyApp 0x0002cab5 - [Myapp someErrorMethod:] (MyApp.m:)

Я думаю о том, почему это произошло

  • Загрузка файла не удалась, а сбойный блок называется
  • Он обрабатывает каждый запрос, очищает делегатов и отменяет их, а затем сбрасывает очередь
  • Однако, пока он еще не запущен, загрузка другого файла завершается неудачно и поступает в сбойный обратный вызов блока
  • Однако, поскольку он был отменен, его сбойный блок был освобожден
  • Когда код пытается записать сообщение об ошибке, его память освобождается и непредсказуемые результаты следуют

Имеет ли это смысл? Так как я новичок в Objective-C, мой анализ правильный или я упускаю что-то очевидное?

Я думаю об использовании блокировки, чтобы сделать поток errorMethod безопасным в надежде, что это исправит эту проблему. Это похоже на правильное решение, основанное на коде выше?

Спасибо

1 Ответ

4 голосов
/ 20 февраля 2012

Это не похоже на вероятность. ASIHttpRequest вероятно выполняет все свои обратные вызовы в одном и том же потоке (в этом я вполне уверен).

Если бы мне пришлось угадывать, ваша ошибка, скорее всего, в этой строке:

DDLogWarn(errorMessage);

Первый параметр DDLogWarn - это формат, а не строка. Это может привести к сбою в любом случае, если errorMessage содержит%. То, что вы имели в виду:

DDLogWarn(@"%@", errorMessage);

Поскольку DDLogWarn() является методом varags, он начнет заменять (случайные) значения, найденные в стеке, на любые% подстановок в строке. Он будет читать стек до тех пор, пока у вас не закончится% замен. Если любая из подстановок% основана на указателе (например,% s или% @), то она будет следовать за указателем в случайном месте.

SEG_ACCERR означает, что вы запросили часть памяти, которой вы не владеете. SEG_MAPERR означает, что вы запросили фрагмент памяти, который не отображается. Либо является ожидаемым результатом следования полностью случайному указателю.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...