2016-05-11 14 views
5

Ngữ nghĩa của việc nắm bắt một biến bằng một khối trong mục tiêu-C là gì?Các quy tắc cho việc nắm bắt biến theo khối trong mục tiêu-C

#import <Foundation/Foundation.h> 

#include <stdio.h> 

int main() 
{ 
    NSMutableArray *arr = [NSMutableArray array]; 
    for (int i = 0; i < 100; ++i) { 
    int j = i; 
    [arr addObject:^(void) {printf("%d %d\n", i, j); }]; 
    } 
    for (void (^blk)(void) in arr) { 
    blk(); 
    } 
} 

Tôi đã expecing này để in cái gì đó như:

100 0 
100 1 
... 
100 99 

Thay vào đó, nó in:

99 99 
99 99 
... 
99 99 

Làm thế nào là nó thậm chí có thể rằng nó giải thích j như bằng 99? j thậm chí không còn sống ngoài vòng lặp.

+1

Strange. Tôi đã mong đợi đầu ra là '0 0',' 1 1', ... '99 99'. – rmaddy

+1

Đây là một ý nghĩ. Bên trong vòng lặp 'for' thứ hai, hãy ghi lại địa chỉ của' blk'. Bạn thực sự có thể có cùng một khối trong mảng 100 lần và tất cả chúng đều tham chiếu khối cuối cùng đã nắm bắt các giá trị cuối cùng của vòng lặp. – rmaddy

+0

@rmaddy: Bạn đúng về kỳ vọng đầu tiên của mình https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithBlocks/WorkingwithBlocks.html Trích dẫn tiền: "Chỉ giá trị được ghi lại, trừ khi bạn chỉ định khác". –

Trả lời

6

Vì bạn không sử dụng ARC! Không có nó, khối của bạn không được sao chép. Bạn chỉ nhận được may mắn và chạy khối cuối cùng mỗi lần duy nhất.

3

Lý do bạn nhìn thấy 99 99 nhiều lần chỉ đơn giản là do hành vi không xác định.

Chúng ta hãy là người đầu tiên cho vòng lặp:

for (int i = 0; i < 100; ++i) { 
    int j = i; 
    dispatch_block_t block = ^(void) {printf("%d %d\n", i, j); }; 
    [arr addObject:block]; 
} 

[Tôi đã rút khỏi khối cho rõ ràng.]

Bên này cho vòng lặp, khối được tạo ra. Nó được tạo ra trên ngăn xếp và không bao giờ di chuyển đến heap vì không có bản sao của khối để làm như vậy.

Mỗi lần quanh vòng lặp, rất có khả năng (tốt, chắc chắn là thực sự) rằng cùng một không gian ngăn xếp được sử dụng cho khối. Và sau đó địa chỉ của khối (trong ngăn xếp) được thêm vào arr. Cùng một địa chỉ mỗi lần. Nhưng đó là một sự thực hiện mới của khối mỗi lần.

Khi ra khỏi vòng lặp đầu tiên, arr chứa cùng giá trị 100 lần. Và giá trị đó trỏ đến khối được tạo cuối cùng, vẫn còn trên ngăn xếp. Nhưng nó chỉ vào một khối trên ngăn xếp mà không còn có thể được truy cập một cách an toàn vì nó nằm ngoài phạm vi.

Trong trường hợp của ví dụ này, tuy nhiên, không gian ngăn xếp chiếm đóng bởi khối bởi may mắn (OK, mã đơn giản) đã không được sử dụng lại. Vì vậy, khi bạn đi và sử dụng khối, nó "hoạt động".

Giải pháp đúng là sao chép khối khi được thêm vào mảng. Hoặc bằng cách gọi số copy hoặc cho phép ARC thực hiện điều đó cho bạn. Bằng cách đó, khối được sao chép vào heap và bạn có một khối tính tham chiếu sẽ tồn tại miễn là cần thiết bởi mảng và phạm vi mà nó được tạo ra.

Nếu bạn muốn tìm hiểu thêm về cách làm việc khối và hiểu câu trả lời này sâu hơn, sau đó tôi đề nghị giải thích của tôi ở đây:

http://www.galloway.me.uk/2012/10/a-look-inside-blocks-episode-1/ http://www.galloway.me.uk/2012/10/a-look-inside-blocks-episode-2/ http://www.galloway.me.uk/2013/05/a-look-inside-blocks-episode-3-block-copy/

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