2015-09-08 2 views
107

С Xcode 6.3 были введены новые аннотации для лучшего выражения намерения API в Objective-C (и для обеспечения, конечно, более быстрой поддержки Swift). Эти аннотации были, конечно, nonnull, nullable и null_unspecified.Разница между обнуляемыми, __nullable и _Nullable в Objective-C

Но с Xcode 7, есть много предупреждений, появляющихся, таких как:

Pointer is missing a nullability type specifier (_Nonnull, _Nullable or _Null_unspecified).

В дополнение к этому, Apple использует другой тип допустимость пустых спецификаторов, маркировка их C код (source):

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.

Но я все еще смущен тем, почему у нас так много аннотаций, которые в основном делают то же самое.

Так что мой вопрос:

Что такое точное различие между этими аннотациями, как правильно разместить их и почему?

+3

Я прочитал этот пост, но он не объясняет разницу и почему у нас есть 3 разных типа аннотаций, и я действительно хочу понять, почему продолжал добавлять третий тип. – Legoless

+2

Это действительно не помогает @ Cy-4AH, и вы это знаете. :) – Legoless

+0

@ Нелегко, вы уверены, что внимательно прочитали его? он точно объясняет, где и как вы должны их использовать, каковы проверенные области, когда вы можете использовать другой для лучшей удобочитаемости, соображений совместимости и т. д. и т. д. ... вы можете не знать, что вы действительно хотите спросить, но ответ явно находится по ссылке. это, может быть, только я, но я не чувствую, что для объяснения их цели, копирования и вставки этого простого объяснения здесь будет объяснено, что ответ здесь будет действительно неудобным, я думаю. :( – holex

ответ

109

От clangdocumentation:

The nullability (type) qualifiers express whether a value of a given pointer type can be null (the _Nullable qualifier), doesn’t have a defined meaning for null (the _Nonnull qualifier), or for which the purpose of null is unclear (the _Null_unspecified qualifier). Because nullability qualifiers are expressed within the type system, they are more general than the nonnull and returns_nonnull attributes, allowing one to express (for example) a nullable pointer to an array of nonnull pointers. Nullability qualifiers are written to the right of the pointer to which they apply.

и

In Objective-C, there is an alternate spelling for the nullability qualifiers that can be used in Objective-C methods and properties using context-sensitive, non-underscored keywords

Таким образом, для возврата метода и параметров, которые вы можете использовать двойные-подчеркнули версии __nonnull/__nullable/__null_unspecified вместо либо однонаправленные, или вместо неосвещенных.Различие состоит в том, что одно и два символа подчеркивания должны быть помещены после определения типа, в то время как не подчеркнутые должны быть помещены перед определением типа.

Таким образом, следующие объявления эквивалентны и правильны:

- (nullable NSNumber *)result 
- (NSNumber * __nullable)result 
- (NSNumber * _Nullable)result 

Для параметров:

- (void)doSomethingWithString:(nullable NSString *)str 
- (void)doSomethingWithString:(NSString * _Nullable)str 
- (void)doSomethingWithString:(NSString * __nullable)str 

Для свойств:

@property(nullable) NSNumber *status 
@property NSNumber *__nullable status 
@property NSNumber * _Nullable status 

вещи однако усложнит когда двойные указатели или блоки, возвращающие что-то другое, чем void, являются invo lved, так как без подчеркивания те здесь не разрешены:

- (void)compute:(NSError * _Nullable * _Nullable)error 
- (void)compute:(NSError * __nullable * _Null_unspecified)error; 
// and all other combinations 

Аналогично с помощью методов, которые принимают блоки в качестве параметров, обратите внимание, что nonnull/nullable классификатор относится к блоку, а не тип возвращаемого, таким образом, следующие условия эквивалентны:

- (void)executeWithCompletion:(nullable void (^)())handler 
- (void)executeWithCompletion:(void (^ _Nullable)())handler 
- (void)executeWithCompletion:(void (^ __nullable)())handler 

Если блок имеет возвращаемое значение, то вы вынуждены в одной из версий подчеркиваний:

- (void)convertObject:(nullable id __nonnull (^)(nullable id obj))handler 
- (void)convertObject:(id __nonnull (^ _Nullable)())handler 
- (void)convertObject:(id _Nonnull (^ __nullable)())handler 
// the method accepts a nullable block that returns a nonnull value 
// there are some more combinations here, you get the idea 

Как вывод, вы можете использовать оба варианта, если компилятор может определить элемент для присвоения квалификатора.

+1

Кажется, что символы подчеркивания могут использоваться повсюду, поэтому я предполагаю, что я буду последовательно использовать их, а не использовать подчеркнутые версии в некоторых местах и без подчеркивания в других. Правильно? –

+0

@KartickVaddadi Да, правильно, вы можете последовательно использовать либо подчеркнутые подчеркивания, либо двойные подчеркнутые версии. – Cristik

+0

'_Null_unspecified' в Swift это переводит на факультативный« необязательный »или что? – Honey

9

Очень удобно это

NS_ASSUME_NONNULL_BEGIN 

и закрывание с

NS_ASSUME_NONNULL_END 

это аннулирует необходимость уровне кода :-) «nullibis», как это своего рода имеет смысл предположить, что все не является нулевым (или nonnull или _nonnull или __nonnull), если не указано иное.

К сожалению, есть исключения из этого правила, а также ...

  • typedef s не предполагается __nonnull (примечание, nonnull не похоже на работу, должны использовать это некрасиво сводный брат)
  • id * нужен явный nullibi, но ничего себе за грех налог (_Nullable id * _Nonnull < - угадайте, что это значит ...)
  • NSError ** всегда предполагается обнуляемого

Таким образом, за исключением исключений и непоследовательных ключевых слов, вызывая такую ​​же функциональность, возможно, подход заключается в использовании уродливых версий __nonnull/__nullable/__null_unspecified и обмене, когда жалобщик жалуется ...? Может быть, поэтому они существуют в заголовках Apple?

Интересно, что-то вложило его в мой код ...Я отрекаюсь подчеркивания в коде (старая школа Apple, C++ стиль парень), поэтому я абсолютно уверен, что я не набирали их, но они появились (один пример из нескольких):

typedef void (^ DidReceiveChallengeBlock) (NSURLSessionAuthChallengeDisposition disposition, 
              NSURLCredential * __nullable credential); 

И еще более интересно, где он вставил __nullable это неправильно ... (ЕЕК @!)

Я действительно хотел бы просто использовать версию без подчеркивания, но, по-видимому, не полететь с компилятором, как это помечено как ошибка:

typedef void (^ DidReceiveChallengeBlock) (NSURLSessionAuthChallengeDisposition disposition, 
              NSURLCredential * nonnull credential); 
+1

Не подчеркивать можно использовать только после открытия круглой скобки, то есть (нет значения ... Просто чтобы сделать жизнь более интересной, я –

23

От the Swift blog:

This feature was first released in Xcode 6.3 with the keywords __nullable and __nonnull. Due to potential conflicts with third-party libraries, we’ve changed them in Xcode 7 to the _Nullable and _Nonnull you see here. However, for compatibility with Xcode 6.3 we’ve predefined macros __nullable and __nonnull to expand to the new names.

+3

В двух словах одно- и двухдисковые версии идентичны. –

+4

Также задокументированы в примечаниях к выпуску Xcode 7.0: «Двунаправленные классификаторы нулевой вероятности (__nullable, __nonnull и __null_unspecified) были переименованы для использования одного подчеркивания с заглавная буква: _Nullable, _Nonnull и _Null_unspecified, соответственно). Компилятор предопределяет сопоставление макросов из старых двухзначных имен в новые имена для совместимости источников. (21530726) " – Cosyn

17

мне очень понравилось this article, так что я просто показываю, что автор написал: https://swiftunboxed.com/interop/objc-nullability-annotations/

  • null_unspecified: мостов к Swift неявно развернутым необязательным. Это по умолчанию.
  • nonnull: значение не будет равно нулю; мосты к регулярной ссылке.
  • nullable: значение может быть равно нулю; мосты к дополнительному.
  • null_resettable: при чтении значение никогда не будет равным нулю, но вы можете установить его на нуль, чтобы сбросить его. Используется только для свойств.

Обозначения выше, то отличаются ли вы использовать их в контексте свойств или функций/переменных:

Pointers vs. Properties notation

Автор статьи также предоставил хороший пример:

// property style 
@property (nonatomic, strong, null_resettable) NSString *name; 

// pointer style 
+ (NSArray<NSView *> * _Nullable)interestingObjectsForKey:(NSString * _Nonnull)key; 

// these two are equivalent! 
@property (nonatomic, strong, nullable) NSString *identifier1; 
@property (nonatomic, strong) NSString * _Nullable identifier2; 
Смежные вопросы