#nil
nilはObjective-Cのオブジェクト(id型)に対して空という意味を表します。
このnilはnullオブジェクトを表し、オブジェクトが未初期化であることや、クリアした状態であることを指します。
NSString example = nil;
#Nil
NilはObjective-Cのクラスに対して空という意味を表します。
Class Animals = Nil;
#NULL
ポインタ(メモリー上のアドレスを記憶する変数の型のこと)に対して空という意味。
このNULLはC言語互換のNULL。
Objective-CはC言語と互換性がある。
char *pointer = NULL;
#NSNull
空の意味を表すオブジェクト。
NSNullはクラスであり、nullを表すオブジェクト。
シングルトンインスタンスなので、常に同じ一つのインスタンスを指す
NSArray *array = [NSArray arrayWithObjects:@"value1", [NSNull null], @"value3", nil];
#nilに関する注意点
objective-Cでnullを表現するときは、nilを用います。
しかしNSArrayやNSDictionaryなどのコレクションにはnilを追加することができません。
そのため、その場合はnilの代わりに[NSNull null]を使う必要があります。
nilを使用した場合
//配列を作成
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:0];
[array addObject:@"value1"];
[array addObject:nil]; //エラーになる
[array addObject:@"value3"];
[NSNull null]を使用した場合
//配列を作成
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:0];
[array addObject:@"value1"];
[array addObject:[NSNull null]]; //エラーにならない
[array addObject:@"value3"];
しかしその一方でNSArrayやNSDictionaryにもnilが必要な場合があります。
それが以下のコードです。
nilが配列の一番後ろに指定されていると思います。これは最後にnilを付け加えることで、要素の終端位置を示すために使われます。そのため、この場合は逆にnilを指定しないとエラーを引き起こすので注意が必要です。
NSArray *array = [NSArray arrayWithObjects:@"value1", @"value2", @"value3", nil];
#nil、NSNullチェックに関する注意点
nilとNSNullは全くの別物としてプログラム上で扱われるので、nilチェックだけしているとNSNullが値に入ってきた際に、nullチェックをスルーしエラーを引き起こす原因になるので注意が必要です。
誤ったnullチェックの例
//配列を作成
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:0];
[array addObject:@"value1"];
[array addObject:[NSNull null]];
[array addObject:@"value3"];
//配列から0番目の要素を取得
NSString *str = [array objectAtIndex:0];
//if文でnilチェックしかしておらず、NSNullがチェックできない。
if(str != nil && str.length > 0){
NSLog(@"%@%@", @"間違った判定1", [array objectAtIndex:0]);
}
//この場合は中身が空でも常に真と評価して意図しないことになるのでNG
if(str){
NSLog(@"%@%@", @"間違った判定2",[array objectAtIndex:0]);
}
正しいnullチェックの例
//配列を作成
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:0];
[array addObject:@"value1"];
[array addObject:[NSNull null]];
[array addObject:@"value3"];
//配列から0番目の要素を取得
NSString *str = [array objectAtIndex:0];
//変数strの中身が空ではない場合ログが出力される
if(! [str isEqual:[NSNull null]] && [str length] > 0){
NSLog(@"%@%@", @"正しい判定", [array objectAtIndex:0]);
}
#メッセージの送信の違い
nilは他のプログラミング言語と違い、メッセージの送信が許されます。メッセージを送るというのは、Javaなどでいうクラスのインスタンスのメソッドを呼び出すことに当たります。
そのため下記のコードのようにnilチェックをしなくても大丈夫です。
メッセージを送信した時の返り値は、返り値の型がid型のメッセージの場合はnilを返し、
intのようなC言語の型の場合は0を返します。
C言語のstructのような場合は返却値は未定義です。
//nilチェックする場合
if (foo != nil) {
[foo method];
}
//nilチェックしなくても大丈夫
Foo *foo = nil;
[foo method];
一方NSNullの場合はメッセージを送信すると、NSINvalidArgumentExceptionの例外を投げ、これをキャッチしなかった場合はクラッシュするので注意が必要です。
#参考
https://www.itcowork.co.jp/blog/?p=939
https://dev.classmethod.jp/articles/objective-c%E3%81%A7nil%E3%81%AB%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E3%82%92%E9%80%81%E3%82%8B%E3%81%A8%E3%81%AF/