В Xcode 6.3 появились новые аннотации для лучшего выражения намерений API в Objective-C (и, конечно, для обеспечения лучшей поддержки Swift). Эти аннотации были, конечно nonnull
, nullable
и null_unspecified
.
Но с Xcode 7 появляется много предупреждений, таких как:
В указателе отсутствует спецификатор типа обнуляемости (_Nonnull, _Nullable или _Null_unspecified).
В дополнение к этому Apple использует другой тип спецификаторов обнуляемости, помечая их C-код ( источник ):
CFArrayRef __nonnull CFArrayCreate(
CFAllocatorRef __nullable allocator, const void * __nonnull * __nullable values, CFIndex numValues, const CFArrayCallBacks * __nullable callBacks);
Итак, подведем итог, теперь у нас есть эти 3 различные аннотации обнуляемости:
nonnull
,nullable
,null_unspecified
_Nonnull
,_Nullable
,_Null_unspecified
__nonnull
,__nullable
,__null_unspecified
Несмотря на то, что я знаю, почему и где использовать какую аннотацию, меня немного смущает, какой тип аннотации мне следует использовать, где и почему. Вот что я мог бы собрать:
- Для свойств следует использовать
nonnull
,nullable
,null_unspecified
. - Для параметров методы следует использовать
nonnull
,nullable
,null_unspecified
. - Для методов C следует использовать
__nonnull
,__nullable
,__null_unspecified
. - Для других случаев, например, двойные указатели я должен использовать
_Nonnull
,_Nullable
,_Null_unspecified
.
Но я все еще не понимаю, почему у нас так много аннотаций, которые в основном делают одно и то же.
Итак, мой вопрос:
В чем разница между этими аннотациями, как правильно их разместить и почему?
Ответы:
Из
clang
документации :, и
Таким образом, для возвратов методов и параметров вы можете использовать версии с двойным подчеркиванием
__nonnull
/__nullable
/__null_unspecified
вместо одинарных или подчеркнутых версий . Разница в том, что одинарные и двойные подчеркнутые должны быть помещены после определения типа, в то время как не подчеркнутые должны быть помещены перед определением типа.Таким образом, следующие объявления эквивалентны и являются правильными:
Для параметров:
Для свойств:
Однако, все усложняется, когда задействованы двойные указатели или блоки, возвращающие что-то отличное от void, так как здесь не допускаются знаки подчеркивания:
Аналогично методам, которые принимают блоки в качестве параметров, обратите внимание, что спецификатор
nonnull
/nullable
применяется к блоку, а не к его типу возврата, поэтому следующие условия эквивалентны:Если блок имеет возвращаемое значение, то вы вынуждены перейти к одной из версий подчеркивания:
В заключение вы можете использовать любой из них, при условии, что компилятор может определить элемент для назначения классификатора.
источник
_Null_unspecified
в Swift это переводится как необязательный? необязательно или как?Из блога Swift :
источник
Мне очень понравилась эта статья , поэтому я просто показываю, что написал автор: https://swiftunboxed.com/interop/objc-nullability-annotations/
null_unspecified:
мосты к Свифту неявно развернуты необязательно. Это по умолчанию .nonnull
: значение не будет равно нулю; мосты к регулярной ссылке.nullable
: значение может быть ноль; мосты по желанию.null_resettable
: значение никогда не может быть равно нулю при чтении, но вы можете установить его равным нулю, чтобы сбросить его. Относится только к свойствам.Приведенные выше обозначения отличаются, используете ли вы их в контексте свойств или функций / переменных:
Автор статьи также привел хороший пример:
источник
Очень удобно это
и в заключение
Это сведет на нет необходимость в уровне кода 'nullibis' :-), так как имеет смысл предполагать, что все не является нулевым (или
nonnull
или_nonnull
или__nonnull
), если не указано иное.К сожалению, есть и исключения из этого ...
typedef
s не предполагается__nonnull
(обратите внимание,nonnull
похоже, не работает, должны использовать его уродливый сводный брат)id *
нужен явный нулиби, но вау налог на грех (_Nullable id * _Nonnull
<- угадайте, что это значит ...)NSError **
всегда предполагается обнуляемымТаким образом , за исключением исключений и непоследовательными ключевыми словами , вызывающим такую же функциональность, возможно, подход заключается в использовании уродливых версий
__nonnull
/__nullable
/__null_unspecified
и свопа , когда компилятор жалуется ...? Может быть, поэтому они существуют в заголовках Apple?Интересно, что кое-что вставило это в мой код ... Я ненавижу подчеркивать в коде (парень старой школы в стиле Apple C ++), поэтому я абсолютно уверен, что я их не печатал, но они появились (один пример из нескольких):
И еще интереснее то, куда он вставил __nullable - неправильно ... (eek @!)
Я действительно хотел бы просто использовать версию без подчеркивания, но, видимо, это не работает с компилятором, поскольку это помечено как ошибка:
источник