Sự khác biệt giữa tham chiếu __weak và __block là gì?


80

Tôi đang đọc tài liệu của Xcode và đây là điều khiến tôi khó hiểu:

__block typeof(self) tmpSelf = self;
[self methodThatTakesABlock:^ {
    [tmpSelf doSomething];
}];

Phần sau được sao chép từ tài liệu:

Một khối tạo thành một tham chiếu mạnh mẽ đến các biến mà nó nắm bắt. Nếu bạn sử dụng selftrong một khối, khối sẽ tạo thành một tham chiếu mạnh đến self, vì vậy nếu selfcũng có một tham chiếu mạnh đến khối (mà nó thường làm), thì một chu trình tham chiếu mạnh sẽ dẫn đến. Để tránh chu kỳ, bạn cần tạo một __blocktham chiếu yếu (hoặc ) cho bản thân bên ngoài khối, như trong ví dụ trên.

Tôi không hiểu 'yếu (hoặc __block)' nghĩa là gì?

__block typeof(self) tmpSelf = self;

__weak typeof(self) tmpSelf = self;

giống hệt ở đây?

Tôi tìm thấy một phần khác trong tài liệu:

Lưu ý: Trong môi trường thu gom rác, nếu bạn áp dụng cả hai __weak__blockbổ ngữ cho một biến, thì khối sẽ không đảm bảo rằng nó vẫn tồn tại.

Vì vậy, tôi hoàn toàn hoang mang.

Câu trả lời:


109

Từ tài liệu về __block

__block biến tồn tại trong bộ nhớ được chia sẻ giữa phạm vi từ vựng của biến và tất cả các khối và bản sao khối được khai báo hoặc tạo trong phạm vi từ vựng của biến. Do đó, bộ nhớ sẽ tồn tại sau sự phá hủy của khung ngăn xếp nếu bất kỳ bản sao nào của các khối được khai báo trong khung tồn tại sau phần cuối của khung (ví dụ: bằng cách được xếp vào hàng đâu đó để thực hiện sau). Nhiều khối trong một phạm vi từ vựng nhất định có thể sử dụng đồng thời một biến được chia sẻ.

Từ tài liệu về __weak

__weak chỉ định một tham chiếu không giữ cho đối tượng được tham chiếu tồn tại. Tham chiếu yếu được đặt thành nil khi không có tham chiếu mạnh nào đến đối tượng.

Vì vậy, chúng là những thứ khác nhau về mặt kỹ thuật. __block là để ngăn biến của bạn được sao chép từ phạm vi bên ngoài vào phạm vi khối của bạn. __weak là một con trỏ tự phân định điểm yếu.

Lưu ý rằng tôi đã nói về mặt kỹ thuật, vì đối với trường hợp của bạn, họ sẽ làm (gần như) điều tương tự. Sự khác biệt duy nhất là bạn có đang sử dụng ARC hay không. Nếu dự án của bạn sử dụng ARC và chỉ dành cho iOS4.3 trở lên, hãy sử dụng __weak. Nó đảm bảo tham chiếu được đặt thành nil nếu tham chiếu phạm vi toàn cầu được phát hành bằng cách nào đó. Nếu dự án của bạn không sử dụng ARC hoặc dành cho các phiên bản hệ điều hành cũ hơn, hãy sử dụng __block.

Có một sự khác biệt tinh tế ở đây, hãy chắc chắn rằng bạn hiểu nó.

CHỈNH SỬA: Một mảnh khác của câu đố là __unsafe_unretained. Công cụ sửa đổi này gần giống như __weak nhưng dành cho môi trường thời gian chạy trước 4.3. TUY NHIÊN, nó không được đặt thành nil và có thể khiến bạn bị treo con trỏ.


1
Điều này có còn áp dụng cho iOS7 bằng ARC không? Tôi đã chạy một trình mô tả và tôi thấy rằng các bộ điều khiển của tôi đang được phát hành ngay cả khi tôi không sử dụng __block hoặc __weak và tự tham chiếu trong một khối.
Jay Q.


1
Làm thế nào về việc sử dụng chúng cùng nhau? __block _weak NSString *strEg;?
CyberMew

5

Trong chế độ đếm tham chiếu thủ công, __block id x; có tác dụng không giữ lại x. Trong chế độ ARC, __block id x; mặc định giữ lại x (giống như tất cả các giá trị khác). Để có được hành vi của chế độ đếm tham chiếu thủ công trong ARC, bạn có thể sử dụng __unsafe_unretained __block id x ;. Tuy nhiên, như tên __unsafe_unretained ngụ ý, việc có một biến không được giữ lại là rất nguy hiểm (vì nó có thể bị treo) và do đó không được 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ành nil để phá vỡ chu kỳ lưu giữ.

tài liệu táo


0

Bên cạnh các câu trả lời khác về __blockvs __weak, có một cách khác để tránh chu kỳ giữ chân trong kịch bản của bạn.

@weakify(self);
[self methodThatTakesABlock:^ {
    @strongify(self);
    [self doSomething];
}];

Thông tin thêm về @Weakify @Strongify Macro


0

Khi sử dụng self-in block, nên sử dụng __weak , không phải __block vì nó có thể giữ lại self.

Trong trường hợp bạn cần bản thân mạnh mẽ, thì bạn có thể sử dụng như sau:

__weak typeof(self) *weakSelf = self;
[self methodThatTakesABlock:^{
    if (weakSelf) {
        __strong typeof(self) *strongSelf = weakSelf;
        [strongSelf doSomething];
    }
}];
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.