Как вы реализуете глобальную обработку исключений iPhone?

У меня есть один сбой в приложении iPhone, который генерирует NSException. Отчеты о сбоях совершенно неоднозначны, когда ошибка и что именно вызывает ее. Есть ли у меня разумный способ установить обработчик исключения верхнего уровня где-нибудь, чтобы узнать, что его вызывает? Я не могу воспроизвести проблему самостоятельно, но некоторые из моих бета-пользователей, безусловно, могут.

Какой умный способ справиться с проблемой такого рода?

Ответ 1

Похоже, вы задаете здесь два вопроса: как установить обработчик исключения верхнего уровня; и как решить проблему определения того, что является основной причиной.

Захват исключения может быть выполнен несколькими различными способами, но для этого лучшим подходом было бы установить обработчик исключений, используя NSSetUncaughtExceptionHandler.

Когда в приложении создается исключение, он обрабатывается обработчиком исключений по умолчанию. Этот обработчик не делает ничего, кроме как регистрировать сообщение на консоли до закрытия приложения. Вы можете переопределить это, установив собственный собственный обработчик исключений, используя функцию, указанную выше. Лучшее место для этого было бы в приложении делегирования приложения applicationDidFinishLaunching:.

- (void)applicationDidFinishLaunching:(UIApplication *)application
{
    NSSetUncaughtExceptionHandler(&myExceptionHandler);
}

После того, как вы настроили пользовательский обработчик, вы захотите расширить вывод по умолчанию, помогая определить причину.

void myExceptionHandler(NSException *exception)
{
    NSArray *stack = [exception callStackReturnAddresses];
    NSLog(@"Stack trace: %@", stack);
}

К сожалению, по сравнению с OSX iPhone выглядит довольно ограниченным в отношении создания хорошей трассировки стека. Приведенный выше код приведет к некоторому, казалось бы, нежелательному результату; однако вы можете запустить этот вывод через инструмент atos, и вы должны иметь возможность генерировать полезную трассировку стека из него.

Другой вариант - следовать инструкциям этой статьи, которые помогут автоматически создать красивую трассировку стека.

Как это происходит на бета-тестерах, вам, возможно, придется потрудиться, чтобы заставить его работать на вас.

Вы говорите, что не смогли решить проблему самостоятельно, только ваши пользователи. В этом случае вы можете найти эту техническую ноту от Apple полезной:

https://developer.apple.com/library/content/technotes/tn2151/_index.html

UPDATE. Хотя этот пост по-прежнему содержит полезную информацию, некоторые из содержащихся ссылок мертвы необратимо. Рекомендуется использовать информацию из этого альтернативного сообщения.

Ответ 2

Если вы планируете сделать это самостоятельно, вы можете использовать один из этих подходов

Approach1:

void onUncaughtException(NSException* exception)
{
//save exception details
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  NSSetUncaughtExceptionHandler(&onUncaughtException);
  //Add coding to find if any exception has occurred from saved details if so send it to server or ask user to comment on the issue.
//Rest of the coding
}

Approach2:

void onUncaughtException(NSException* exception)
{

//Save exception details

}

int main(int argc, char *argv[])
{
    @autoreleasepool {

        NSSetUncaughtExceptionHandler(&onUncaughtException);

        return UIApplicationMain(argc, argv, nil, NSStringFromClass([SGGI_AppDelegate class]));
    }
}



-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
 {
      //Add coding to find if any exception has occurred from saved details if so send it to server or ask user to comment on the issue.
    //Rest of the coding
 }

Approcach3:

int main(int argc, char *argv[])
{
    @autoreleasepool {

        @try {

            return UIApplicationMain(argc, argv, nil, NSStringFromClass([SGGI_AppDelegate class]));
        }
        @catch (NSException *exception) {      
        //Save the exception
        }
        @finally {
        }

    }
}

-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
 {
      //Add coding to find if any exception has occurred from saved details if so send it to server or ask user to comment on the issue.
    //Rest of the coding
 }

Примечание:

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

  • Если вы собираетесь использовать NSUserDefaults для сохранения сведений об исключении, тогда вам нужно синхронизировать его во время сбоя, иначе он не будет сохраняться.

Следующий фрагмент кода выполняет задание.

   - (void)applicationWillTerminate:(UIApplication *)application
   {
       [[NSUserDefaults standardUserDefaults]synchronize];
   }
  • Если вы предпочитаете сохранять его в sqlite db, то он не нуждается в том, чтобы называть что-либо, чтобы его сохранить в момент сбоя.

Ответ 3

В XCode вы всегда должны установить глобальную точку останова для objc_exception_throw. Затем вы (обычно) получаете гораздо более значимую трассировку стека относительно того, что на самом деле пытается создать исключение.

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

Ответ 4

Также BugSense.com доступен и доступен для проектов iOS

Ответ 6

Другим вариантом отслеживания отчетов о сбоях является Правдоподобный CrashReporter, открытый исходный код, который автоматически отправляет вам отчеты о сбоях из поле.

Здесь также CrashReporterDemo, другой вариант с открытым исходным кодом, который представляет собой комбинацию правдоподобного CrashReporter и некоторого сервера кода для лучшего отслеживания отчетов о сбоях.

И наконец, там MacDevCrashReporter, служба, которая, похоже, имеет сходство с iOSExceptional.com, предлагаемая в другом ответ. Я понятия не имею, каковы условия их обслуживания, поскольку я не подписался на бета-версию. Определенно стоит проверить, прежде чем проникать слишком глубоко.

Ответ 7

Отъезд Crittercism. Это выше и выше того, о чем вы просите здесь, что позволяет вам получать эту информацию для всех пользователей, использующих ваше приложение, чтобы вы могли увидеть свой собственный сбой.

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

Вы также можете захотеть убедиться, что вы настроены на разрыв исключений Objetive-C. В Xcode 4 на вкладке точек останова вы можете добавить исключение Breakpoint Exception, которое разбивается на оба варианта С++ и Obj-C. Без этого большинство трассировок стека для исключенных исключений довольно бесполезны.

Удачи!