Swift Nullability and Objective-C
Bridging-Headerファイルを使用すると、SwiftはObjective-Cとシームレスに呼び出すことができますが、SwiftとObjective-Cには大きな違いがあります.Swiftは
以前に発表されたXcodeバージョンでは、アップルのいくつかのフレームワークがSwiftのOptionalタイプについていくつかの専門的な審査を行い、彼らのAPIがOptionalに適しているようにしたが、Xcode 6.3の発表は、Objetive-Cの新しい特性をもたらした:
この機能は、
下線を引かない形式は、下線を引かない形式よりも簡潔に見えますが、ヘッダーファイルの各タイプに適用する必要があります.面倒だと思ってヘッダーファイルをより簡潔にしたい場合は、審査エリアに使用します.
これらの注釈をより簡単に追加したい場合は、Objective-Cヘッダファイルの領域をレビュー(for nullability)が必要としてマークすることができます.この領域では、すべての簡単なポインタタイプが
Xcode 6.3(iOS 8.3 SDK)は、itemWithNameメソッドのnameパラメータがNullabilityフィーチャーを使用していない
安全のため、このルールには例外があります. は、
詳細については、Error Handling Programming Guideを参照してください.
あなたのObjective-Cフレームワークの既存のコードは正しいですか?安全にタイプを変更できますか?Yes, it is.既存のコンパイルされたコードは、あなたのフレームワークを引き続き使用することができます.つまり、ABIは変化していません(コンパイラはエラーを報告しません).これは、既存のコードが実行時に 新しいSwiftコンパイラで既存のソースコードをコンパイルし、あなたのフレームワークを使用すると、いくつかの不安全な動作でコンパイル時に追加の警告を受ける可能性があります.
多くの場合、
次に、Objective-Cヘッダファイルにnullability注記を追加します.Swiftで使用します.Objective-Cに注記を追加する前に、次のようにします.
注記を追加した後:
これらのSwiftコードは非常にはっきりしています.細部の変化しかありませんが、フレームワークをより快適に使用できます.
Optional
タイプをサポートしています.例えばNSView
とNSView?
は、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つの新しいタイプの注釈をもたらしました.ご覧のように、__nullable
はNULL
または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.
nil
の不正な伝達値をキャプチャしないことを意味します.nonnull
は最適化に影響しません.特に、nonnull
とマークされたパラメータがnil
であるかどうかを実行時に確認することもできます.これは、必要な後方互換性が必要になる可能性があります.多くの場合、
nullable
とnonnull
を受け入れるべきです.現在使用されている断言や異常は乱暴です.約束違反はプログラマーがよく犯すエラーです(nullable
とnonnull
はコンパイル時に問題を解決できます).特に、戻り値はあなたが制御できるものであり、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コードは非常にはっきりしています.細部の変化しかありませんが、フレームワークをより快適に使用できます.