Lý do cơ bản này hoạt động là sự kết hợp của:
[1] Mục tiêu-C (và C) không được nhập mạnh vào thời gian biên dịch. Trong khi cảnh báo có thể được sản xuất bởi trình biên dịch, chúng thường có thể bị tắt tiếng bởi (đôi khi gõ không an toàn) phôi. nhiệm vụ của bạn trong trường hợp này là không hợp lệ như bạn đang gán một tham chiếu khối mà tuyên bố nó đòi hỏi một giá trị tham số tương thích với NSNumber *
khác tham khảo khối mà chỉ tuyên bố nó đòi hỏi một giá trị tham số tương thích với id
. Đây là loại không an toàn và đôi khi sẽ xuất hiện thời gian chạy lỗi, xem bên dưới.
[2] nhắn Objective-C runtime qua là năng động, có nghĩa là mã mục tiêu cho một tin nhắn được xác định là mã chạy. Điều này có nghĩa là tất cả việc bạn sử dụng số number
trong khối không cụ thể cho NSNumber
khi bạn vượt qua NSDate
khi chạy các phương pháp phù hợp vẫn được đặt động. Tuy nhiên thay đổi của bạn bar
tới:
void (^bar)(NSNumber *) = ^(NSNumber *number)
{
NSLog(@"Value is %@, class is %@, int value is %d.", number, [number class], [number intValue]);
};
và bạn sẽ thấy runtime lỗi.
[3] Cả [NSNumber numberWithInt:10]
và [NSDate date
] được khai báo để trở về giá trị của loại id
, không NSNumber *
& NSDate *
như bạn mong đợi. Điều này có nghĩa bạn không cần foo
, bạn có thể chỉ cần gõ:
bar([NSDate date]);
và nhận được kết quả tương tự mà không cần bất kỳ cảnh báo ... Như một ví dụ nữa xem xét việc này:
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
Đi xuống : Objective-C là không một loại ngôn ngữ an toàn, trình biên dịch sẽ trong nhiều trường hợp cảnh báo bạn về các vấn đề tiềm năng, nhưng nó sẽ không làm như vậy trong mọi trường hợp.
Đầu ra _is_ hoặc đầu ra _ sẽ là_? Bởi vì nếu bạn thử nghiệm và đó là đầu ra thực tế, thì nó được cho phép. – zneak
FYI này được gọi là * [hiệp phương sai và contravariance] (http://en.wikipedia.org/wiki/Covariance_and_contravariance_%28computer_science%29) *. –
Tôi sẽ sử dụng void (^ bar) (id) thay vì nếu bạn sử dụng nó như thế này. – Cthutu