development

Objective-C에서 nullable, __nullable 및 _Nullable의 차이점

big-blog 2020. 6. 21. 19:07
반응형

Objective-C에서 nullable, __nullable 및 _Nullable의 차이점


Xcode 6.3에는 Objective-C 에서 API의 의도를 더 잘 표현 하기 위해 (그리고 물론 더 나은 Swift 지원을 보장하기 위해) 새로운 주석이 도입되었습니다 . 이러한 주석은 물론 있었다 nonnull, nullable하고 null_unspecified.

그러나 Xcode 7에서는 다음과 같은 많은 경고가 나타납니다.

포인터에 널 입력 가능 유형 지정자가 없습니다 (_Nonnull, _Nullable 또는 _Null_unspecified).

그 외에도 Apple은 다른 유형의 Null 허용 지정자를 사용하여 C 코드 ( source )를 표시합니다.

CFArrayRef __nonnull CFArrayCreate(
CFAllocatorRef __nullable allocator, const void * __nonnull * __nullable values, CFIndex numValues, const CFArrayCallBacks * __nullable callBacks);

요약하자면 이제 다음과 같은 세 가지 nullable 주석이 있습니다.

  • 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 문서 :

널 입력 가능 (유형) 규정자는 주어진 포인터 유형의 값이 널 ( _Nullablequalifier) ​​일 수 있는지, 널 ( qualifier)에 대해 정의 된 의미가 없거나 널 _Nonnull의 목적이 명확하지 않은 ( _Null_unspecifiedqualifier) ​​여부를 나타 냅니다. . 널 입력 가능 규정자는 유형 시스템 내에서 표현되기 때문에 nonnullreturns_nonnull속성 보다 일반적 이므로 널이 아닌 포인터 배열에 대한 널 입력 가능 포인터를 표현할 수 있습니다. Nullability 한정자는 해당 포인터 오른쪽에 기록됩니다.

,

Objective-C에는 문맥에 맞지 않는 밑줄이없는 키워드를 사용하여 Objective-C 메소드 및 특성에 사용할 수있는 널 입력 가능 규정 자에 대한 대체 철자가 있습니다.

그래서 메소드가 리턴 및 사용할 수있는 매개 변수에 대한 이중 밑줄 버전 __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와 다른 것을 반환하는 이중 포인터 또는 블록이 포함되면 문제가 복잡해집니다.

- (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

결론적으로 컴파일러가 한정자를 할당 할 항목을 결정할 수있는 한 둘 중 하나를 사용할 수 있습니다.


에서 스위프트 블로그 :

이 기능은 키워드 __nullable 및 __nonnull과 함께 Xcode 6.3에서 처음 릴리스되었습니다. 타사 라이브러리와의 잠재적 충돌로 인해 Xcode 7의 라이브러리가 _Nullable 및 _Nonnull로 변경되었습니다. 그러나 Xcode 6.3과의 호환성을 위해 매크로 __nullable 및 __nonnull을 사전 정의하여 새 이름으로 확장했습니다.


I really liked this article, so I am merely showing what the author wrote: https://swiftunboxed.com/interop/objc-nullability-annotations/

  • null_unspecified: bridges to a Swift implicitly-unwrapped optional. This is the default.
  • nonnull: the value won’t be nil; bridges to a regular reference.
  • nullable: the value can be nil; bridges to an optional.
  • null_resettable: the value can never be nil when read, but you can set it to nil to reset it. Applies to properties only.

The notations above, then differ whether you use them in the context of properties or functions/variables:

Pointers vs. Properties notation

The author of the article also provided a nice example:

// 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;

Very handy is

NS_ASSUME_NONNULL_BEGIN 

and closing with

NS_ASSUME_NONNULL_END 

This will nullify the need for the code level 'nullibis' :-) as it sort of makes sense to assume that everything is non-null (or nonnull or _nonnull or __nonnull) unless otherwise noted.

Unfortunately there are exceptions to this as well...

  • typedefs are not assumed to be __nonnull (note, nonnull does not seem to work, have to use it's ugly half brother)
  • id * needs an explicit nullibi but wow the sin-tax ( _Nullable id * _Nonnull <- guess what that means...)
  • NSError ** is always assumed nullable

So with the exceptions to the exceptions and the inconsistent keywords eliciting the same functionality, perhaps the approach is to use the ugly versions __nonnull / __nullable / __null_unspecified and swap when the complier complains... ? Maybe that is why they exist in the Apple headers?

Interestingly enough, something put it into my code... I abhor underscores in code (old school Apple C++ style guy) so I am absolutely sure I did not type these but they appeared (one example of several):

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

And even more interestingly, where it inserted the __nullable is wrong... (eek@!)

I really wish I could just use the non-underscore version but apparently that does not fly with the compiler as this is flagged as an error:

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

참고URL : https://stackoverflow.com/questions/32452889/difference-between-nullable-nullable-and-nullable-in-objective-c

반응형