iOS : Изключенията на фоновата нишка не се сриват

Не намерих документация, която да е в съответствие с моя опит.

Това, което искам, е добър начин за обработка на Uncaught-Exceptions във фонова нишка. Този „начин“ трябва да позволи на приложението да се срине, но да изпълни някои много основни операции, преди да се срине (напр. запазване на стойност в UserDefaults, така че да може да бъде прегледана при следващо стартиране; плюс регистриране).

В основната нишка току-що настроих uncaughtExceptionHanlder и това работи добре. Въпреки това, във фонова нишка - изпълнена като NSOperation на NSOperationQueue - възниква изключение, но не и излизане от приложението: Срив. Приложението продължава да работи в повредено състояние.

Ръководството за програмиране на нишки обаче гласи:

Настройване на манипулатор на изключения Ако вашето приложение улавя и обработва изключения, кодът на вашата нишка трябва да е подготвен да улавя всички изключения, които могат да възникнат. Въпреки че е най-добре да се обработват изключения в точката, където те могат да възникнат, неуспехът да се улови хвърлено изключение в нишка води до излизане на приложението ви. Инсталирането на последен опит/улавяне във вашата рутинна процедура за въвеждане на нишка ви позволява да улавяте всички неизвестни изключения и да предоставяте подходящ отговор.

Един метод, който работи (по-долу), е вграждането на метода за извикване на нишка с try/catch и в случай на изключение, регистриране и след това извикване на abort(). Но това не може да е най-добрият начин да направите това. Бих искал да изпратя изключението към основната нишка и то да бъде обработено от манипулатора на неуловени изключения. Някой правил ли е това?

- (void)threadMethod
{
    @try
    {
        NSArray* aTest = [NSArray array];
        [aTest objectAtIndex:10];
    }
    @catch (NSException* e)
    {
        // Save to state to User Defaults.
        // Log any needed info.

        abort();
    }
    @finally
    {

    }
}

FYI: Работя с iOS6 с XCode 4.5 SDK.


person paiego    schedule 12.01.2013    source източник


Отговори (2)


  1. Нишките, управлявани от NSOperationQueue, се управляват от libdispatch, което прихваща изключения и извиква terminate, излизайки от приложението. Ако виждате различно поведение, вече правите нещо нередно.
  2. Запазването на данни в NSUserDefaults след изключение е съмнително предложение; тъй като Cocoa третира изключенията само като грешка на програмиста, той не прави никакви опити да се остави в използваемо състояние, след като някое е било хвърлено. Накратко, трябва да го третирате по същия начин, както бихте го третирали с „истински“ срив, сякаш са налични само API, безопасни за асинхронен сигнал. Всичко Objective-C автоматично отпада в това отношение.
  3. Вашият въпрос предполага, че се опитвате да докладвате за сривове. Бих препоръчал решение за докладване на сривове за тази цел, като PLCrashReporter. Има и редица услуги за анализ и разпространение, които вграждат докладване за сривове, включително HockeyApp, Crashlytics, TestFlight и QuincyKit. Има и други, а кой е подходящ за вас зависи от вашите нужди. Всички те ще се справят с всички трудни проблеми, свързани с безопасното обработване на сривове и изключения и запазването на данните за по-късно, без да се налага да се притеснявате за което и да е от тях.
person Gwynne Raskind    schedule 12.01.2013
comment
Това не е проблем с докладването на сривове. В случай на срив, искам да запазя информация за състоянието, използвана за следващото стартиране. - person paiego; 14.01.2013
comment
Накратко, бих казал, че най-добрият ви залог е да запишете данните във файл във възможно най-прост формат, който можете да управлявате, като използвате обикновените API на POSIX. Отново трябва да подчертая, че всичко Objective-C е опасно в момента, в който изключение е на път да срине приложението ви; всичко е в неизвестно състояние. Един много бърз, непонятен пример може да бъде: int fd = open(UTF8StringOfDocumentsDirectoryPlusFileNameSavedAtAppStartup, O_WRONLY | O_CREAT | O_TRUNC); if (fd != -1) { write(fd, "crashed", sizeof("crashed") - 1); close(fd); } - person Gwynne Raskind; 15.01.2013

За това, което правите, вярвам, че ще ви трябва код в основната ви нишка, който проверява за неща, които се случват във втората ви нишка. Тъй като нямате възможност действително да се свържете с главната нишка и да задействате събитие от фоновата нишка, най-вероятно ще сте блокирани да пишете нещо в основната си нишка, което проверява от време на време. Това каза, вероятно бихте могли да работите с NSNotificationCenter и да накарате основната нишка да има събитие, задействано, когато изключението е хвърлено от фоновата нишка. Късмет.

person Tony    schedule 13.01.2013