Подтвердить что ты не робот

Как использовать NSSetUncaughtExceptionHandler в Swift

В Objective-C я вызываю метод NSSetUncaughtExceptionHandler(&exceptionHandler) для регистрации исключений. Как он называется в Swift?

4b9b3361

Ответ 1

Update

С Swift 2 вы можете передавать функции Swift и замыкания в качестве указателя функции C. См. ответ Martin R ниже.

Оригинальный ответ

Вы не можете, начиная с Xcode 6 beta 6.

Swift поддерживает прокрутку указателей функций, но их обрабатывают почти как непрозрачные указатели. Вы не можете ни определять указатель функции C функции Swift, ни вызывать вызов функции C в Swift.

Это означает, что вы вызываете NSSetUncaughtExceptionHandler() из Swift, но обработчик должен быть реализован в Objective-C. Вам нужен заголовочный файл:

volatile void exceptionHandler(NSException *exception);
extern NSUncaughtExceptionHandler *exceptionHandlerPtr;

и в реализации вам нужно что-то вроде этого:

volatile void exceptionHandler(NSException *exception) {
    // Do stuff
}
NSUncaughtExceptionHandler *exceptionHandlerPtr = &exceptionHandler;

После импорта файла заголовка в заголовке моста Swift вы можете настроить обработчик исключений, как обычно:

NSSetUncaughtExceptionHandler(exceptionHandlerPtr)

Ответ 2

Начиная с Swift 2 (Xcode 7), вы можете передавать функции/замыкания Swift параметрам, принимающим указатель на функцию C. Из примечаний к выпуску Xcode 7:

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

Итак, это компилируется и работает:

func exceptionHandler(exception : NSException) {
    print(exception)
    print(exception.callStackSymbols)
}

NSSetUncaughtExceptionHandler(exceptionHandler)

Или с "встроенным" закрытием:

NSSetUncaughtExceptionHandler { exception in
    print(exception)
    print(exception.callStackSymbols)
}

Это делает то же самое, что и соответствующий код Objective C: он перехватывает необработанные NSException. Так что это будет поймано:

let array = NSArray()
let elem = array.objectAtIndex(99)

ПРИМЕЧАНИЕ: - Он не перехватывает никаких ошибок Swift 2 (из throw) или ошибок времени выполнения Swift, поэтому он не перехватывается:

let arr = [1, 2, 3]
let elem = arr[4]

Ответ 3

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

Этот код для swift 4. Добавьте в didFinishLaunchingWithOptions():

NSSetUncaughtExceptionHandler { exception in
            print("Error Handling: ", exception)
            print("Error Handling callStackSymbols: ", exception.callStackSymbols)

            UserDefaults.standard.set(exception.callStackSymbols, forKey: "ExceptionHandler")
            UserDefaults.standard.synchronize()
        }

А код добавь в fistViewController viewLoad()

// ERROR ExceptionHandler
        if let exception = UserDefaults.standard.object(forKey: "ExceptionHandler") as? [String] {

            print("Error was occured on previous session! \n", exception, "\n\n-------------------------")
            var exceptions = ""
            for e in exception {
                exceptions = exceptions + e + "\n"
            }
            AlertFunctions.messageType.showYesNoAlert("Error was occured on previous session!", bodyMessage: exceptions, {

            }, no: {
                UserDefaults.standard.removeObject(forKey: "ExceptionHandler")
                UserDefaults.standard.synchronize()
            })
        }

РЕДАКТИРОВАТЬ: код работает. Но вам нужно заново открыть приложение после ошибки.

Ответ 4

Свифт 5:

1. Добавьте этот метод в AppDelegate:

    func storeStackTrace() {
        NSSetUncaughtExceptionHandler { exception in
            print(exception)
            // do stuff with the exception
        }
     }

2. Вызвать этот метод из didFinishLaunchingWithOptions и вызвать исключение сразу после

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
            storeStackTrace()

            let exception = NSException(name: NSExceptionName(rawValue: "arbitrary"), reason: "arbitrary reason", userInfo: nil)
            exception.raise()


    }

3. Следите за выводом на консоль, он немедленно распечатает исключение, которое вы только что вызвали, начиная с указанной вами причины.