Исключение не улавливается

Crashlytics сообщает, что следующая строка иногда выдает NSInternalInconsistencyException:

let attrStr = try NSMutableAttributedString(
        data: modifiedFont.data(using: String.Encoding.unicode, 
        allowLossyConversion: true)!,
        options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue],
        documentAttributes: nil)

Здесь меня не так интересует, почему это происходит (есть вопрос трехлетней давности), поскольку я перехватываю / обрабатываю это исключение. Я пробовал сделать это так:

do {
    let attrStr = try NSMutableAttributedString(
       data: modifiedFont.data(using: String.Encoding.unicode, allowLossyConversion: true)!,
       options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue],
       documentAttributes: nil)

     self.attributedText = attrStr
} catch {
    self.attributedText = nil
    self.text = text.stripHTML()
}

... но по какой-то причине это не работает - об исключении все еще сообщается.

Я пытаюсь понять это правильно? Можно ли его вообще поймать? Если нет, то какие у меня варианты?


person TimSim    schedule 27.06.2019    source источник
comment
Swift имеет обработку ошибок, а не обработку исключений. Вы не можете поймать исключение с помощью Swift; просто нужно избегать этого. Некоторые из предоставленных вами ссылок подразумевают, что этот вызов не должен выполняться в фоновом потоке.   -  person vacawama    schedule 27.06.2019
comment
stackoverflow.com/a/28916420/1630618   -  person vacawama    schedule 27.06.2019
comment
stackoverflow.com/questions/32758811/   -  person Sulthan    schedule 29.06.2019


Ответы (3)


Swift преобразует методы Objective-C с возвращаемыми значениями NULL и завершающими NSError** параметрами в методы, которые генерируют Swift. Но в Objective-C вы также можете создавать исключения. Они отличаются от NSErrors, и Swift их не улавливает. На самом деле ловить их в Swift невозможно. Вам нужно будет написать оболочку Objective-C, которая перехватывает исключение и передает его обратно каким-либо образом, с которым Swift может справиться.

Вы можете найти это в документе Apple Обработка ошибок какао в Swift в разделе < em> Обработка исключений в разделе Только для Objective-C.

Получается, что вы можете его поймать, но стоит подумать, стоит ли вам это делать (см. Комментарии от @Sulthan ниже). Насколько мне известно, большинство фреймворков Apple не безопасны для исключений (см .: Исключения и фреймворки какао), поэтому вы не можете просто поймать исключение и продолжить работу, как будто ничего не произошло. Лучше всего сохранить все, что можно, и выйти как можно скорее. Еще одна проблема, которую следует учитывать, заключается в том, что, если вы не повторно выбросите исключение, такие фреймворки, как Crashlytics, не будут сообщать вам об этом. Итак, если вы все же решили его поймать, вы должны зарегистрировать его и / или повторно выбросить, чтобы вы знали, что это происходит.

person idz    schedule 27.06.2019
comment
Таким образом, не рекомендуется перехватывать исключения Objective-C, потому что их распространение часто оставляет объекты в недопустимом состоянии, и вы не можете успешно восстановить их. - person Sulthan; 28.06.2019
comment
Да, но вы можете сделать все возможное, чтобы выйти изящно (например, сохранить любые данные пользователя, которые вы можете, зарегистрировать любые данные, которые могут быть полезны). - person idz; 28.06.2019
comment
Это правда, для этого может быть шанс, но я не думаю, что сейчас ОП хочет это сделать. - person Sulthan; 28.06.2019
comment
@ Сультан, это хороший аргумент. Я обновлю ответ, добавив немного дополнительной информации. - person idz; 28.06.2019

NSInternalInconsistencyException - это исключение Objective-C, которое не может быть перехвачено кодом Swift. Вы можете поймать этот тип исключения только с помощью кода Objective-C, поэтому вам нужно будет создать оболочку Objective-C, чтобы поймать это из кода Swift, например, с помощью следующего метода Objective-C:

+ (NSException *)tryCatchWithBlock:(void (^)(void))block {
    @try {
        block();
    } @catch (NSException *exception) {
        return exception;
    } @catch (id exception) {
        return [NSException exceptionWithName:NSGenericException reason:nil userInfo:nil];
    }
    return nil;
}

Этот метод является частью моей библиотеки под названием LSCategories: https://github.com/leszek-s/LSCategories с различными полезными категориями / расширениями, так что вы также можете легко интегрировать эту библиотеку с CocoaPods в свой проект Swift, а затем вы можете поймать NSInternalInconsistencyException, обернув свой быстрый код следующим образом:

let objcException = NSException.lsTryCatch {
    // put your swift code here
}

Вот как вы можете поймать это исключение, если хотите это сделать. Но что еще более важно, вы должны выяснить, почему это исключение возникает в вашем случае. Возможно, вы вызываете свой код в фоновом потоке.

person Leszek Szary    schedule 28.06.2019
comment
Не могли бы вы указать на объявление конкретного метода вместо большого репозитория утилит? Или лучше, не могли бы вы скопировать здесь реализацию метода? В противном случае это не сработает как ответ, и это скорее самореклама. - person Sulthan; 28.06.2019
comment
Кстати, ваш lsDateWithStringWithISO8601 не будет работать правильно, если вы не установите часовой пояс и заметите, что большинство функций контрольной суммы (crc32, adler) доступны в zlib. - person Sulthan; 28.06.2019
comment
Спасибо за замечание об ISO8601, и да, я знаю, что эти контрольные суммы также доступны в zlib. - person Leszek Szary; 28.06.2019

Я предполагаю, что сбой происходит, когда вы пытаетесь преобразовать modifiedFont в Data.
modifiedFont.data(using: String.Encoding.unicode, allowLossyConversion: true)! Скорее всего, вы получите ту же ошибку, если переместите строку преобразования данных за пределы области try-catch. Во избежание сбоя не применяйте принудительное развертывание (!).

Он перехватывается, если во время инициализации NSMutableAttributedString возникает какая-либо ошибка.

person hasankose    schedule 27.06.2019