2012-01-10 37 views
5

Mike Ash has written this introduction to ARC nơi ông giới thiệu một cái gì đó như:Khi nào và tại sao tôi muốn khai báo biến cục bộ dưới dạng __weak bằng ARC?

__weak Foo *_weakFoo = [object foo]; 

Tại sao tôi muốn làm điều đó cho một biến tạm thời địa phương? __weak là một tham chiếu zeroing sẽ tự động đặt con trỏ _weakFoo thành nil ngay khi đối tượng được tham chiếu bị deallocated. Ngoài ra, __weak chỉ có sẵn trong iOS> = 5.

Khi tôi chạy vào rắc rối khi tôi chỉ đơn giản là thực hiện điều này ?:

Foo *_weakFoo = [object foo]; 

này luôn được dự kiến ​​sẽ trả về một đối tượng hoặc nil. Dự đoán của tôi là:

Foo *_weakFoo = [object foo]; 
[self doSomethingStupid]; // does something bad so foo gets deallocated 
[_weakFoo doIt]; // CRASH! msg sent to deallocated instance 0x123456 

Một điều vẫn còn lỗi với ARC là: Khi nào tôi biết rằng tôi không cần một đối tượng nữa? Tôi muốn lập luận rằng khi tôi đặt con trỏ thành nil hoặc một cái gì đó khác, nó chỉ ra rằng đối tượng được tham chiếu trước đây không cần thiết bởi chủ sở hữu này nữa và do đó có thể có thể biến mất. Nhưng vấn đề là: tôi đặt nó thành không. Vì vậy, nó là nil anyways!

Vì vậy, khi nào __weak cho một biến địa phương có ý nghĩa, và loại điều điên rồ nào tôi phải làm ở một nơi khác để tôi thực sự cần điều đó?

Trả lời

9

Tôi sử dụng __weak biến cục bộ nếu tôi phải thao tác self bên trong một khối để tránh chu kỳ lưu giữ. Hãy xem xét ví dụ này, nơi tôi đang sử dụng GCD và chặn để thực hiện một yêu cầu mạng cho một chuỗi, và sau đó thiết lập nó trên một nhãn được khai báo bởi lớp, trong trường hợp này là TurtlesViewController.

__weak TurtlesViewController *weakSelf = self; 
dispatch_queue_t networkQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 

dispatch_async(networkQueue, ^{ 

    // Kick off a network task for some data that is going to populate a label declared on our class 
    NSString *returnString = [networkDataSource retrieveTurtleTime]; 

    // Dispatch back to the main thread to populate the UILabel 
    dispatch_async(dispatch_get_main_queue(), ^{ 

     // Using self.label here creates a retain cycle. Self owns the block and the block has captured self 
     self.label.text = returnString; 

     // Instead, we use weakSelf for our reference to the label as it will be torn down by ARC at the end of the loop. 
     weakSelf.label.text = returnString; 
    }); 
}); 
+1

Làm thế nào có thể có chu kỳ lưu giữ? – openfrog

+1

@openfrog - Khối đặc biệt này có thể không có nguy cơ lớn nhất là một chu kỳ giữ lại, nhưng một trong đó tôi đã chạy vào sẽ là các nhà quan sát dựa trên khối cho các thông báo (sử dụng '-addObserverForName của NSNotificationCenter's: queue: queue: usingBlock:'). Nếu bạn thiết lập một người quan sát như vậy trong một đối tượng, và tham khảo một cái gì đó trên 'self', bạn sẽ thiết lập một chu kỳ như đối tượng giữ trên khối và khối giữ trên đối tượng. –

+2

Sau khi viết điều này, tôi nhận ra rằng đây không phải là ví dụ tốt nhất bởi vì dispatch_async() sao chép khối, nhưng chỉ cho đến khi kết thúc phương thức. Một ví dụ tốt hơn sẽ được sử dụng NSBlockOperation kể từ khi một thể hiện của sở hữu như vậy được truyền trong khối cho suốt đời của đối tượng, làm cho các chu trình giữ lại nhiều khả năng hơn. –

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