Что ненулевая функция Obj-C возвращает в Swift?

У меня есть объективная библиотека c, которую можно использовать в Swift с помощью заголовка моста.

Один из моих общедоступных методов помечен как возвращающий nonnull, но на самом деле в некоторых случаях он может возвращать nil.

Я ожидал, что код Swift, вызывающий этот метод, вылетит из-за «развертки необязательного значения nil», но на самом деле это не так.

Цель-C:

- (nonnull UserService *)users
{
    if (!_users && [self checkStarted]) {
        _users = [[UserService alloc] init];
    }
    return _users;
}

-(BOOL) checkStarted
{
    return NO;
}

Быстрый заголовок:

Заголовок генерации выглядит следующим образом:

func users() -> UserService

Быстрое использование:

let userService = sdk.users()

Когда я po возвращаю значение, я получаю этот результат

po userService
<uninitialized>

Как так?


person Jan    schedule 17.10.2016    source источник
comment
Какая версия Свифта?   -  person par    schedule 17.10.2016
comment
Я возвращаю ноль (обновлен исходный вопрос, чтобы сделать его более понятным). Свифт 3   -  person Jan    schedule 17.10.2016
comment
Если userService может быть нулевым, просто напишите let userService : UserService? = sdk.users(). Теперь, если это nil, вы можете узнать это связно.   -  person matt    schedule 17.10.2016
comment
Если метод Objective-C может возвращать nil, почему он помечен как nonnull вместо nullable?   -  person rmaddy    schedule 17.10.2016
comment
@rmaddy Потому что это плохой API? Даже собственные API Apple допускают эту ошибку в нескольких печально известных местах. Это просто то, что вы должны обойти.   -  person matt    schedule 17.10.2016
comment
Ну, это ошибка в моем коде, которая может возвращать ноль. Не должно. Я пытаюсь понять, почему он не падает   -  person Jan    schedule 17.10.2016
comment
Я предполагаю, что поведение не определено. Вы пробовали print(userService) или даже обращались к одному из его свойств?   -  person Martin R    schedule 17.10.2016
comment
да, я вызвал для него метод, и ничего не произошло. Как будто это нулевой объект в Objc   -  person Jan    schedule 17.10.2016
comment
Кстати, анализатор Clang должен выявлять такие ошибки.   -  person matt    schedule 17.10.2016
comment
Если это вообще поможет, я бы не стал ожидать разворачивания необязательного значения nil из-за того, что вы никогда не разворачиваете необязательное значение. Бьюсь об заклад, Мартин Р прав в отношении неопределенного поведения, поскольку текущая реализация просто дает вам результат, который не дает сбоев, потому что в этом случае он отправляет через среду выполнения Objective-C.   -  person Tommy    schedule 17.10.2016
comment
Анализатор clang этого не улавливает.   -  person Jan    schedule 18.10.2016


Ответы (1)


Возможно, есть недоразумение: во многих языках программирования вы можете сделать много ошибок, например, аннотировать ограничение значения, а затем не выполнить его. Я десятки раз читал стандарт C, в котором много подобных ошибок. В результате обычно получается неопределенное поведение. Дело не в том, что результатом является определенный крах. Такого "обещания" я еще не читал. И это не имеет смысла.

Итак, проще говоря: поведение не определено. Неопределенное поведение включает в себя вероятность того, что ничего не выйдет из строя.

Как это может случиться?

Аннотирование, отличное от null, дает компилятору возможность сделать код лучше в одних ситуациях, а в других нет. Компилятор может получить преимущество за счет оптимизации. Но, конечно, бывают ситуации, когда компилятор не может этого сделать.

Поскольку вы получаете объект Objective-C, каждое сообщение для этого объекта должно быть отправлено во время выполнения. Невозможно сделать это во время компиляции (по крайней мере, методы могут быть заменены, методы могут быть перезаписаны в подклассах и т. д.), даже если вы используете этот объект в Swift. Динамическая диспетчеризация — это то, как работает Objective-C, даже если вы поместите его в контекст просеивания.

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

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

Может быть. Может быть нет. Это не определено.

person Amin Negm-Awad    schedule 17.10.2016