-
Notifications
You must be signed in to change notification settings - Fork 0
TIPS Swiftから利用しやすいようにObjective Cを書く
コレクション要素の型指定ができる。
クラス名<型 *> *
Obj-C側で要素の型が未指定(id
型)の場合、SwiftではAny
型に変換される。
→要素アクセスのたびにダウンキャストが必要になり冗長
型指定するとSwiftにも指定が引き継がれ、対応する型の要素を持ったコレクションとなる。
→キャスト不要
@property NSArray *array;
// XcodeのGenerated Interfaceを利用して確認した値(以下同様)
// (↑jump bar 左端のボタンから)
open var array: [Any]!
@property NSArray<NSString *> *stringArray;
@property NSArray<NSNumber *> *numberArray;
open var stringArray: [String]!
open var numberArray: [NSNumber]!
特定の型のサブクラスであることを表現するためのキーワード。
Lightweight Genericsでの型指定は指定した型しか許容しない。
あるクラスのサブクラスのコレクションを定義する際に__kindof
を使用する。
@interface Fruits : NSObject
@end
@interface Apple : Fruits
@end
@interface Orange : Fruits
@end
@interface Dessert : NSObject
// Fruits型のサブクラス(Apple型やOrange型)の値を代入するとコンパイラに警告される
@property NSArray<Fruits *> *fruits;
@end
@interface Fruits : NSObject
@end
@interface Apple : Fruits
@end
@interface Orange : Fruits
@end
@interface Dessert : NSObject
// Fruits型のサブクラス(Apple型やOrange型)代入を許容
@property NSArray<__kindof Fruits *> *fruits;
@end
メソッドの引数やプロパティがObjective-Cのnil
やCポインタのNULL
を取るかどうかを指定する。
名称 | 説明 | Swiftインポート時の型 |
---|---|---|
nonnull |
プロパティがnilやNULLにならない | 非オプショナル型 |
nullable |
プロパティがnilやNULLになる可能性がある |
Optional<Wrapped> 型 |
null_unspecified |
プロパティがnilやNULLかどうかわからない デフォルト値 |
ImplicitlyUnwrappedOptional<Wrapped> 型 |
null_resettable |
プロパティは常に値を持っているが、nilの代入によってリセット可能 |
ImplicitlyUnwrappedOptional<Wrapped> 型 |
@property (nonnull) id nonnullValue;
@property (nullable) id nullableValue;
@property (null_unspecified) id nullUnspecifiedValue;
@property (null_resettable) id nullResettableValue;
open var nonnullValue: Any
open var nullableValue: Any?
open var nullUnspecifiedValue: Any!
open var nullResettableValue: Any!
同一ファイル内でひとつでもnull許容性の指定をすると、ファイル内の全てのメソッドの引数・戻り値、プロパティにnull強制を指定する必要がある。
(指定が漏れるとコンパイラに警告される)
全てに設定していく手間を省くにはNS_ASSUME_NONNULL_BEGIN
マクロとNS_ASSUME_NONNULL_END
マクロを利用する。
これらに囲まれた領域の値は、自動的にnonnull
となる。
nonull
以外の属性は明示的に指定する。
NS_ASSUME_NONNULL_BEGIN
@property id nonnullValue;
@property id hoge;
@property id fuga;
@property (nullable) id nullableValue;
@property (null_unspecified) id nullUnspecifiedValue;
@property (null_resettable) id nullResettableValue;
NS_ASSUME_NONNULL_END
open var nonnullValue: Any
open var hoge: Any
open var fuga: Any
open var nullableValue: Any?
open var nullUnspecifiedValue: Any!
open var nullResettableValue: Any!
自身と同じ型のインスタンスを返却する場合はid
型ではなくinstancetype
を利用する。
戻り値をid
型とした場合、戻り値はAny
型の値となり、型の情報が失われる。
戻り値をinstancetype
とした場合、戻り値はそのメソッドが属する型の値となり、Swiftから利用する際のダウンキャストが不要になる。
NSArray
、NSSet
、NSDictionary
などのObjective-Cのコレクションは、そのままでは要素がAny
型としてSwiftにインポートされる。
(1.
参照)
Lightweight Genericsを使うことにより要素の型もSwiftにインポートでき、Swiftから利用する際のダウンキャストが不要になる。
様々な型が代入される可能性がある型でも、特定の型のサブクラスに限定できる場合は__kindof
を利用する。
Objective-Cで特定のプロトコルに準拠した任意の型を表現する場合はid< プロトコル名 >
と記述する。
これにより予期せぬ型の値の代入を予防できる。
Lightweight Genericsやnull許容性アノテーションは、Objective-Cの実行コードに一切影響を与えない。
コンパイラは型情報を持っているが、実行コード生成時にそれらの状況は消去される。
つまり、コードに不整合がある場合にコンパイラが警告を出すが、ビルドは通り実行可能。
// Fruits.h
#import <Foundation/Foundation.h>
@interface Fruits : NSObject
- (nonnull instancetype)initWithName:(nonnull NSString *)name;
@end
// Fruits.m
#import "Fruits.h"
@implementation Fruits
// nonullを指定しているが、nilを返す
// 警告は出るが、実行可能
- (nonnull instancetype)initWithName:(nonnull NSString *)name {
return nil;
}
@end
Bridging-Header.h
#import "Fruits.h"
main.swift
let apple = Fruits(name: "Apple")
print(apple) // 実行時エラー