Swift Nullability and Objective-C


Bridging-Headerファイルを使用すると、SwiftはObjective-Cとシームレスに呼び出すことができますが、SwiftとObjective-Cには大きな違いがあります.SwiftはOptionalタイプをサポートしています.例えばNSViewNSView?は、Objective-Cではこれに対して1つの表現しかありません.すなわちNSView *は、そのViewがnilであることを示すためにも非nilであることを示すためにも使用できます.この場合、SwiftコンパイラはこのNSViewがOptionalタイプであるかどうかを特定することができません.この場合、SwiftコンパイラはそれをNSView!として処理し、暗黙的にパッケージを取り外します.
以前に発表されたXcodeバージョンでは、アップルのいくつかのフレームワークがSwiftのOptionalタイプについていくつかの専門的な審査を行い、彼らのAPIがOptionalに適しているようにしたが、Xcode 6.3の発表は、Objetive-Cの新しい特性をもたらした:nullability注釈、この特性を利用して私たちも自分のコードに対して類似の処理を行うことができる.

コア:_nullableと_nonnull


この機能は、__nullable__nonnullの2つの新しいタイプの注釈をもたらしました.ご覧のように、__nullableNULLまたはnilの値を表すことができますが、__nonnullは正反対です.このルールに違反すると、コンパイラから警告が表示されます.
@interface AAPLList : NSObject <NSCoding, NSCopying>
//---
- (AAPLListItem * __nullable)itemWithName:(NSString * __nonnull)name;
@property (copy, readonly) NSArray * __nonnull allItems;
//---
@end

//--------------

[self.list itemWithName:nil]; // warning!
__nullable__nonnullのキーワードをどこでも使用できます.例えば、標準Cのconstと一緒に使用したり、ポインタに直接適用したりすることができます.しかし、多くの場合、これらの注釈は優雅な方法で書かれます.方法の定義や宣言では、タイプが簡単なオブジェクトまたはBlockポインタであれば、下線を引かない方法(nullableまたはnonnull)で左かっこの後ろに直接書くことができます.
- (nullable AAPLListItem *)itemWithName:(nonnull NSString *)name; - (NSInteger)indexOfItem:(nonnull AAPLListItem *)item;
@propertyの場合も、同じようにプロパティリストに書くことができます.
@property (copy, nullable) NSString *name;
@property (copy, readonly, nonnull) NSArray *allItems;

下線を引かない形式は、下線を引かない形式よりも簡潔に見えますが、ヘッダーファイルの各タイプに適用する必要があります.面倒だと思ってヘッダーファイルをより簡潔にしたい場合は、審査エリアに使用します.

レビューエリア(Audited Regions)


これらの注釈をより簡単に追加したい場合は、Objective-Cヘッダファイルの領域をレビュー(for nullability)が必要としてマークすることができます.この領域では、すべての簡単なポインタタイプがnonnullとして扱われています.私たちの前の例では、次のようになります.
NS_ASSUME_NONNULL_BEGIN
@interface AAPLList : NSObject <NSCoding, NSCopying>
//---
- (nullable AAPLListItem *)itemWithName:(NSString *)name;
- (NSInteger)indexOfItem:(AAPLListItem *)item;

@property (copy, nullable) NSString *name;
@property (copy, readonly) NSArray *allItems;
//---
@end
NS_ASSUME_NONNULL_END

// --------------

self.list.name = nil;   // okay

AAPLListItem *matchingItem = [self.list itemWithName:nil];  // warning!

Xcode 6.3(iOS 8.3 SDK)は、itemWithNameメソッドのnameパラメータがNullabilityフィーチャーを使用していないNS_ASSUME_NONNULL_BEGIN / ENDマクロを導入したが、nonnullとして扱われる
安全のため、このルールには例外があります.
  • typedefで定義されたタイプは、nullabilityのプロパティを継承しません.コンテキストに基づいてnullableまたはnon-nullableを簡単に選択するので、typedefで定義されたタイプは、レビュー領域内でもnonnullと見なされません.
  • id *のようなより複雑なポインタタイプは、例えば、nonnullのポインタをnullableのオブジェクト参照として指定するには、__nullable id * __nonnullを使用する必要があります.
  • は、NSError **のような特殊な方法パラメータによってエラーオブジェクトを返すタイプであり、常にnullableのポインタとしてnullableのポインタ:__nullable NSError ** __nullableを指すものと見なされる.

  • 詳細については、Error Handling Programming Guideを参照してください.

    互換性


    あなたのObjective-Cフレームワークの既存のコードは正しいですか?安全にタイプを変更できますか?Yes, it is.
  • 既存のコンパイルされたコードは、あなたのフレームワークを引き続き使用することができます.つまり、ABIは変化していません(コンパイラはエラーを報告しません).これは、既存のコードが実行時にnilの不正な伝達値をキャプチャしないことを意味します.
  • 新しいSwiftコンパイラで既存のソースコードをコンパイルし、あなたのフレームワークを使用すると、いくつかの不安全な動作でコンパイル時に追加の警告を受ける可能性があります.
  • nonnullは最適化に影響しません.特に、nonnullとマークされたパラメータがnilであるかどうかを実行時に確認することもできます.これは、必要な後方互換性が必要になる可能性があります.

  • 多くの場合、nullablenonnullを受け入れるべきです.現在使用されている断言や異常は乱暴です.約束違反はプログラマーがよく犯すエラーです(nullablenonnullはコンパイル時に問題を解決できます).特に、戻り値はあなたが制御できるものであり、non-nullableの戻りタイプに対してnilを返すべきではありません.これは後方互換性のためでない限り.

    Swiftに戻る


    次に、Objective-Cヘッダファイルにnullability注記を追加します.Swiftで使用します.Objective-Cに注記を追加する前に、次のようにします.
    class AAPLList : NSObject, NSCoding, NSCopying { 
        //---
        func itemWithName(name: String!) -> AAPLListItem!
        func indexOfItem(item: AAPLListItem!) -> Int
    
        @NSCopying var name: String! { get set }
        @NSCopying var allItems: [AnyObject]! { get }
        //---
    }

    注記を追加した後:
    class AAPLList : NSObject, NSCoding, NSCopying { 
        //---
        func itemWithName(name: String) -> AAPLListItem?
        func indexOfItem(item: AAPLListItem) -> Int
    
        @NSCopying var name: String? { get set }
        @NSCopying var allItems: [AnyObject] { get }
        //---
    }

    これらのSwiftコードは非常にはっきりしています.細部の変化しかありませんが、フレームワークをより快適に使用できます.