Xcode 6.3では、Objective-CでAPIの意図をよりよく表現するために新しい注釈が導入されました(そして、Swiftのサポートを改善するためにもちろん)。これらの注釈は、もちろんnonnull
、nullable
、およびnull_unspecified
でした。
しかし、Xcode 7では、次のような多くの警告が表示されます。
ポインターにnullability型指定子(_Nonnull、_Nullable、または_Null_unspecified)がありません。
それに加えて、Appleは別のタイプのヌル値指定子を使用して、Cコードをマークします( source ):
CFArrayRef __nonnull CFArrayCreate(
CFAllocatorRef __nullable allocator, const void * __nonnull * __nullable values, CFIndex numValues, const CFArrayCallBacks * __nullable callBacks);
要約すると、これらの3つの異なるNULL可能性アノテーションがあります。
nonnull
、nullable
、null_unspecified
_Nonnull
、_Nullable
、_Null_unspecified
__nonnull
、__nullable
、__null_unspecified
どの注釈を使用する理由と場所を知っていても、どの種類の注釈を使用するか、どこで、なぜ使用するかについて少し混乱しています。これは私が集めることができるものです:
nonnull
、nullable
、null_unspecified
を使用する必要があります。nonnull
、nullable
、null_unspecified
を使用する必要があります。__nonnull
、__nullable
、__null_unspecified
を使用する必要があります。_Nonnull
、_Nullable
、_Null_unspecified
を使用する必要があります。しかし、基本的に同じことを行う非常に多くの注釈がある理由について、私はまだ混乱しています。
だから私の質問は:
それらの注釈の正確な違いは何ですか、それらを正しく配置する方法と理由は何ですか?
clang
から ドキュメント :
Nullability(type)修飾子は、指定されたポインター型の値がnullになる可能性があるか(
_Nullable
修飾子)、nullに定義された意味がないか(_Nonnull
修飾子)、またはnullの目的が不明であるか(_Null_unspecified
修飾子)。 nullability修飾子は型システム内で表現されるため、nonnull
およびreturns_nonnull
属性よりも一般的であり、null不可能なポインターの配列へのNULL可能ポインターを表現できます。 Nullability修飾子は、適用先のポインターの右側に書き込まれます。
、そして
Objective-Cには、コンテキスト依存のアンダースコアなしのキーワードを使用して、Objective-Cのメソッドとプロパティで使用できるnullability修飾子の代替スペルがあります
そのため、メソッドの戻り値とパラメーターには、単一の下線付きの代わりに、または下線なしの代わりに、二重下線付きバージョン__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
結論として、コンパイラーが修飾子を割り当てるアイテムを決定できる限り、いずれかを使用できます。
Swiftブログ から:
この機能は、キーワード__nullableおよび__nonnullを使用してXcode 6.3で最初にリリースされました。サードパーティのライブラリとの競合の可能性があるため、Xcode 7ではこれらを_Nullableおよび_Nonnullに変更しました。ただし、Xcode 6.3との互換性のために、__ nullableおよび__nonnullのマクロを事前定義して、新しい名前に展開しています。
私は本当にこの記事が好きだったので、著者が書いたことを単に示しています: https:// swiftunboxed .com/interop/objc-nullability-annotations /
null_unspecified:
は、Swift暗黙的にアンラップされたオプションにブリッジします。これはdefaultです。nonnull
:値はnilになりません。通常の参照への橋渡し。nullable
:値はnilにできます。オプションへのブリッジ。null_resettable
:読み取り時に値がnilになることはありませんが、nilに設定してリセットすることができます。プロパティにのみ適用されます。上記の表記は、プロパティまたは関数/変数のcontextで使用するかどうかによって異なります。
記事の著者はまたニースの例を提供しました:
// 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;
とても便利です
NS_ASSUME_NONNULL_BEGIN
そして閉じる
NS_ASSUME_NONNULL_END
これは、特に注記がない限り、everythingがnull以外(またはnonnull
または_nonnull
または__nonnull
)であると仮定するのが合理的であるため、コードレベル 'nullibis'の必要性を無効にします。
残念ながら、これにも例外があります...
typedef
sは__nonnull
であるとは見なされません(注、nonnull
は機能しないようです。使用する必要があるのはugいハーフブラザーです)id *
は明示的なnullibiを必要としますが、sin-taxを驚かせます(_Nullable id * _Nonnull
<-意味を推測します...)NSError **
は常にNULL可能と想定されますしたがって、例外の例外と同じ機能を引き出す一貫性のないキーワードでは、おそらくアプローチはapproachいバージョン__nonnull
/__nullable
/__null_unspecified
を使用し、コンパイラーが不平を言ったときに交換することです...?おそらくそれがAppleヘッダーに存在するのでしょうか?
興味深いことに、何かが私のコードにそれを入れました...私はコードでアンダースコアを嫌います(古い学校Apple C++スタイルの男)。 :
typedef void ( ^ DidReceiveChallengeBlock ) ( NSURLSessionAuthChallengeDisposition disposition,
NSURLCredential * __nullable credential );
さらに興味深いことに、__ nullableを挿入した場所が間違っています...(eek @!)
私は本当に非アンダースコアバージョンを使用できればいいのにと思いますが、明らかにこれはエラーとしてフラグが付けられているため、コンパイラでは飛ぶことはありません:
typedef void ( ^ DidReceiveChallengeBlock ) ( NSURLSessionAuthChallengeDisposition disposition,
NSURLCredential * nonnull credential );