5

これは許可されていますか、またその理由は何ですか?

void (^bar)(NSNumber *) = ^(NSNumber *number) {
    NSLog(@"Value is %@, class is %@.", number, [number class]);
};
bar([NSNumber numberWithInt:10]);

void (^foo)(id) = bar;
foo([NSDate date]);

出力は次のとおりです。

Value is 10, class is __NSCFNumber.
Value is 2012-05-17 18:54:14 +0000, class is __NSDate.

これを説明する関連するものは何も見つかりませんでした。これをカバーするObjectiveCブロック仕様へのリンクを提供できますか?

現在、私はブロックベースのUITableViewサブクラスに取り組んでおり、これを安全に使用できれば、作業がはるかに簡単になります。

4

1 に答える 1

6

これが機能する根本的な理由は、次の組み合わせです。

[1] Objective-C(およびC)は、コンパイル時に強く型付けされません。警告はコンパイラーによって生成される場合がありますが、通常は(タイプが安全でない場合もある)キャストによって消音される可能性があります。この場合の割り当ては無効です。これは、と互換性のある引数値が必要であると宣言するブロック参照を、と互換性のある引数値NSNumber *必要であると宣言するだけの別のブロック参照に割り当てるためidです。これはタイプが安全ではなく、ランタイムエラーが発生することがあります。以下を参照してください。

[2] Objective-Cのランタイムメッセージパッシングは動的です。つまり、メッセージのターゲットコードは、コードの実行時に決定されます。これは、ブロック内でのすべての使用が実行時に渡すときにnumber非固有であるため、適切なメソッドが動的に配置されることを意味します。ただし、次のように変更してください。NSNumberNSDatebar

void (^bar)(NSNumber *) = ^(NSNumber *number)
{
   NSLog(@"Value is %@, class is %@, int value is %d.", number, [number class], [number intValue]);
};

ランタイムエラーが表示されます。

[3][NSNumber numberWithInt:10]と]の両方が、予想どおり&ではなく[NSDate date、タイプの値を返すように宣言されています。これは、あなたが必要としないことを意味します、あなたはただタイプすることができます:idNSNumber *NSDate *foo

bar([NSDate date]);

警告なしで同じ結果が得られます...さらなる例として、これを検討してください。

NSNumber *num = [NSNumber numberWithInt:3];
NSDate *date = num;         // produces a warning
id erase = num;             // erase type info and do...
date = erase;               // effectively the same assignment, no warning

道を譲る:Objective-Cはタイプセーフな言語ではありません。コンパイラは多くの場合、潜在的な問題について警告しますが、すべての場合にそうなるわけではありません。

于 2012-05-17T20:17:27.067 に答える