#objective-c #swift #runtime-error
#objective-c #swift #ошибка во время выполнения
Вопрос:
Я вызываю какой-то старый код Objective-C из Swift, и он часто выдает эту ошибку, даже если кажется, что ничего не пошло не так:
do {
try objCObject.someMethod()
}
catch {
print(error)
// Trying to handle the error here
}
Где сигнатура Objective-C этого метода выглядит следующим образом:
- (BOOL) someMethodWithError: (NSError **) outError;
Ввод точки останова внутри, чтобы catch
я мог увидеть это с помощью консоли LLDB.
(lldb) po error
Foundation._GenericObjCError.nilError
(lldb) po error as NSError
Error Domain=Foundation._GenericObjCError Code=0 "(null)"
Что здесь происходит и как мне с этим справиться? Когда я пытаюсь написать специальный случай для этого в Swift, я получаю это:
/Path/To/My Code.swift:200:27: error: module 'Foundation' has no member named '_GenericObjCError'
catch Foundation._GenericObjCError.nilError {
^~~~~~~~~~ ~~~~~~~~~~~~~~~~~
Ответ №1:
Это происходит, когда метод Objective-C использует стандартный подход Cocoa к выдаче ошибок: принимает an NSError **
в качестве последнего параметра и возвращает a BOOL
с YES
указанием успеха. Если это работает так, как задумано, возвращаемое значение будет только в том NO
случае, если произошла ошибка, а затем NSError **
соответствующим образом установит объект.
Swift ожидает, что так будут работать все методы Objective-C с этой подписью.
То, что вы видите, это то, что происходит, когда один из этих методов по какой-либо причине ведет себя неправильно и возвращает NO
значение без установки NSError **
параметра на что-либо (или явно устанавливая его на nil
).
Это может быть связано с рядом факторов, таких как возврат кода ошибки, который неявно преобразуется в BOOL
(таким образом, код 0
успеха преобразуется в код NO
сбоя), или запись его строки возврата таким образом, что его логика не всегда возвращается YES
при успешном завершении, или потому, что на самом деле былошибка, но автор не знал, что установить NSError **
и т. Д.
Что касается решения этой проблемы, вот что я бы сделал:
Если вы не знаете намерения автора или автор задокументировал, что это указывает на состояние успеха
В этом случае, я думаю, безопаснее предположить, что автор просто допустил ошибку и вернул неверное значение. Лучше всего полностью игнорировать выданную ошибку.
do {
try objCObject.someMethod()
}
catch {
let nsError = (error as NSError)
if nsError.code == 0,
nsError.domain == "Foundation._GenericObjCError" {
print("Got invalid error from Objective-C")
}
else {
// Actually handle your error here
}
}
Если автор задокументировал, что это указывает на состояние ошибки
В этом случае рассматривайте это как ошибку, задокументированную автором. При желании вы можете настроить приведенный выше пример кода для обработки этой ошибки.
Если вы являетесь автором
Это просто. Просто измените свой метод так, чтобы он возвращался только NO
тогда, когда вы находитесь в реальном состоянии ошибки, и всегда проверяйте, что NSError **
для объекта был установлен допустимый объект ошибки, если вызывающий запросил это.
- (BOOL) someMethodWithError: (NSError **) outError {
[self.something attempt];
if (!self.something.succeeded) {
if (nil != outError) {
*outError = [self makeSomeDescriptiveErrorFromSomething: self.something];
}
return NO;
}
else {
return YES;
}
}