Từ Transitioning to ARC Release NotesTại sao chúng ta phải đặt biến __block thành nil?
Qualifiers Sử dụng Lifetime để Tránh Cycles tham khảo mạnh
Bạn có thể sử dụng vòng đời để tránh chu kỳ tài liệu tham khảo mạnh mẽ. Đối với ví dụ , thông thường nếu bạn có biểu đồ các đối tượng được sắp xếp theo thứ tự cha mẹ và con bố mẹ và cha mẹ cần phải tham chiếu đến con cái của họ và ngược lại, sau đó bạn thực hiện mối quan hệ cha-con và mạnh mẽ và mối quan hệ minh bạch yếu. Các tình huống khác có thể nhiều hơn tinh tế, đặc biệt khi chúng liên quan đến các đối tượng khối.
Trong chế độ đếm tham chiếu thủ công,
__block id x;
có tác dụng không giữ lạix
. Ở chế độ ARC,__block id x;
mặc định để giữ lạix
(chỉ giống như tất cả các giá trị khác). Để có chế độ đếm tham chiếu thủ công hoạt động trong ARC, bạn có thể sử dụng__unsafe_unretained __block id x;
. Như tên__unsafe_unretained
ngụ ý, tuy nhiên, có một biến số không giữ lại là là nguy hiểm (vì nó có thể treo lơ lửng) và là do đó không khuyến khích. Hai tùy chọn tốt hơn là sử dụng__weak
(nếu bạn không cần hỗ trợ iOS 4 hoặc OS X v10.6) hoặc đặt giá trị__block
thànhnil
để phá vỡ chu kỳ lưu giữ.
Được rồi, vậy điều gì khác biệt về biến số __block
?
Tại sao đặt thành nil
tại đây? Biến số __block
có được giữ lại hai lần không? Ai giữ tất cả các tài liệu tham khảo? Khối? Heap? Ngăn xếp? Chủ đề? Cái gì?
Đoạn mã sau minh họa vấn đề này bằng cách sử dụng mẫu thỉnh thoảng được sử dụng trong tính toán tham chiếu thủ công.
MyViewController *myController = [[MyViewController alloc] init…];
// ...
myController.completionHandler = ^(NSInteger result) {
[myController dismissViewControllerAnimated:YES completion:nil];
};
[self presentViewController:myController animated:YES completion:^{
[myController release];
}];
Như đã trình bày, thay vào đó, bạn có thể sử dụng khuôn khổ vòng loại __block
và đặt biến MyController để nil
trong xử lý hoàn thành:
MyViewController * __block myController = [[MyViewController alloc] init…]; //Why use __block. my controller is not changed at all
// ...
myController.completionHandler = ^(NSInteger result) {
[myController dismissViewControllerAnimated:YES completion:nil];
myController = nil; //Why set to nil here? Is __block variable retained twice? Who hold all the reference? The block? The heap? The stack? The thread? The what?
};
Cũng tại sao myController
không được đặt để nil
bởi trình biên dịch. Tại sao chúng ta phải làm như vậy? Dường như là loại trình biên dịch biết khi nào myController sẽ không còn được sử dụng nữa, đó là khi khối hết hạn.
"Nhưng bản thân khối cũng sẽ giữ lại đối tượng vì nó được tham chiếu mạnh mẽ từ bên trong khối." Tại sao? Đóng cửa. –
Làm thế nào để thêm __block tạo ra bất kỳ sự khác biệt nào? –
Khi một khối chụp một con trỏ tới đối tượng mục tiêu-c, đối tượng đó sẽ được giữ lại trừ khi bạn sử dụng '__weak' hoặc' __unsafe_unretained' (hoặc '__block' trong mã không phải ARC). –