Что такое Foundation._GenericObjCError.NilError? - PullRequest
1 голос
/ 11 апреля 2019

Я вызываю какой-то старый код Objective-C из Swift, и он часто выдает эту ошибку, даже если кажется, что ничего не пошло не так:

do {
    try objCObject.someMethod()
}
catch {
    print(error)
    // Trying to handle the error here
}

Где сигнатура Objective-C этого метода похожаthis:

- (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 Ответ

0 голосов
/ 11 апреля 2019

Это вызвано тем, что метод Objective C использует стандартный подход Какао к выбрасыванию ошибок: примите NSError ** в качестве последнего параметра и верните BOOL с YES, указывающим на успех.Если это работает как задумано, возвращаемое значение будет когда-либо только NO, если произошла ошибка, и затем соответственно установит объект NSError **.

Swift ожидает, что это будеткак работают все методы Objective-C с этой сигнатурой.

То, что вы видите, это то, что происходит, когда один из этих методов по какой-то причине плохо себя ведет и возвращает false без установки параметра 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
    }
}

Если автор задокументировал, что это указывает на состояние ошибки

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

Если вы автор

Это просто.Просто измените свой API, чтобы он возвращал 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;
    }
}
...