2012-05-17 9 views
5

Điều này có được phép không và tại sao?Có được phép 'thay đổi'/lạm dụng/ghi đè chữ ký của một khối trong Mục tiêu C như sau không?

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

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

Output là:

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

tôi không thể tìm thấy bất cứ điều gì liên quan đến giải thích điều này. Bạn có thể cung cấp một liên kết đến đặc tả khối c mục tiêu bao gồm điều này không?

Hiện nay tôi đang làm việc trên một khối dựa UITableView lớp con và nó sẽ làm cho mọi việc dễ dàng hơn rất nhiều, nếu tôi là an toàn để sử dụng này.

+0

Đầ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

+1

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) *. –

+0

Tôi sẽ sử dụng void (^ bar) (id) thay vì nếu bạn sử dụng nó như thế này. – Cthutu

Trả lời

6

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][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.

+0

Cảm ơn lời giải thích tuyệt vời của bạn.Điều này có nghĩa là, ngay cả khi tôi có một nhiệm vụ không hợp lệ [1], tôi sẽ không gặp phải bất kỳ lỗi thời gian chạy nào miễn là tôi đảm bảo rằng tất cả việc sử dụng 'số' bên trong khối đó cũng có thể cho lớp thâm nhập (trong trường hợp này là NSDate). – Klaas

Các vấn đề liên quan