NSNullはnilとして振舞うべきじゃないかなー。unrecognized selectorで例外なげるんじゃなくて。
@k_katsumi 私もそう思います。サブクラス化するなりカテゴリで上書きするなりして nil として振る舞えるようにできないですかね?
@griffin_stewie URL こんな感じでOKっす。
2011-04-11 21:47:58 via Echofon to @griffin_stewie
@k_katsumi おお!でも、カテゴリで既存メソッドの上書きはあんまりやりたくないですね。
とか思ってたのですが、そう考える人はやっぱりほかにもいるようです。
NSNullはどんなメッセージ送ってもnilを返してほしいなぁ
たとえば私がいちばん面倒だなと思うのはjson-frameworkがnullをNSNullにマッピングするので(nilはNSArrayやNSDictionaryに格納できないため)でWeb APIからのレスポンスをParseする際に、値がセットされるときとnullがセットされるときと両方あるような場合、ハンドリングがとたんに面倒になるのですね。
NSString *results = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil]; NSDictionary *dic = [results JSONValue]; NSString *shortURL = [[[dic objectForKey:@"results"] objectForKey:longURL] objectForKey:@"shortUrl"];
上記の場合、longURL の値が NSNull だったとすると objectForKey: の呼び出しが失敗してクラッシュします。
このとき NSNull が nil だとしたら、nil へのメッセージは単に無視されるので問題ないわけなのでそうなっていたら便利なのにという話です。
というわけで、下記のようなカテゴリをどこかに書いておくと、NSNull へのメッセージはすべて無視されるので、まるで nil のように扱えて便利です。
何をしているかというと、メッセージフォワーディングの仕組みが動作するように methodSignatureForSelector: および forwardInvocation: をオーバーライドします。
そうすると存在しないメソッドを呼びだそうとするとこれらのメソッドが呼ばれるので、forwardInvocation: メソッドで NSNull に存在しないメソッドの呼び出しは無視するように処理を変更しています。
[参考]Does Objective-C use short-circuit evaluation? - Stack Overflow
@implementation NSNull(IgnoreMessages) - (void)forwardInvocation:(NSInvocation *)anInvocation { if ([self respondsToSelector:[anInvocation selector]]) { [anInvocation invokeWithTarget:self]; } } - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { NSMethodSignature *sig=[[NSNull class] instanceMethodSignatureForSelector:aSelector]; // Just return some meaningless signature if (sig == nil) { sig = [NSMethodSignature signatureWithObjCTypes:"@^v^c"]; } return sig; } @end