ARC - Ý nghĩa của __unsafe_unretained?


79

Chỉ muốn đảm bảo rằng tôi đã làm đúng:

  1. Tôi có cần những __unsafe_unretainđồ vật mà tôi không sở hữu không?
  2. Nếu một đối tượng là __unsafe_unretainedTôi có cần sử dụng assigntrong @property? Điều đó có nghĩa là đối tượng không được giữ lại và chỉ tham chiếu đến đối tượng mà tôi gán cho?
  3. Khi nào tôi muốn sử dụng nó ngoại trừ các đại biểu?
  4. Đó là một thứ ARC hay nó đã được sử dụng trước đây?

Câu trả lời:


192

Các LLVM Compiler 3.0 giới thiệu Bốn vòng loại quyền sở hữu mới: __strong, __autoreleasing, __unsafe_unretained, và __weak. Ba đầu tiên có sẵn ngay cả bên ngoài ARC, theo thông số kỹ thuật .

Như Joshua chỉ ra, theo mặc định, tất cả các con trỏ được ngụ ý là __strongnằm trong ARC. Điều này có nghĩa là khi một đối tượng được gán cho con trỏ đó, nó được giữ lại miễn là con trỏ đó tham chiếu đến nó. Điều này tốt cho hầu hết mọi thứ, nhưng nó mở ra khả năng cho các chu kỳ lưu giữ, như tôi mô tả trong câu trả lời của tôi ở đây . Ví dụ: nếu bạn có một đối tượng chứa một đối tượng khác như một biến thể hiện, nhưng đối tượng thứ hai đó có một liên kết mạnh trở lại đối tượng đầu tiên làm đại biểu của nó, thì hai đối tượng sẽ không bao giờ được giải phóng.

Đó là vì lý do này mà các __unsafe_unretainedvà các __weakvòng loại tồn tại. Cách sử dụng phổ biến nhất của chúng là cho các đại biểu, nơi bạn sẽ xác định một thuộc tính cho đại biểu đó với thuộc tính weakhoặc unsafe_unretained( assignlà hiệu quả unsafe_unretained), sau đó khớp với thuộc tính đó bằng cách đánh dấu biến phiên bản tương ứng bằng __weakhoặc __unsafe_unretained. Điều này có nghĩa là biến thể hiện đại biểu sẽ vẫn trỏ trở lại đối tượng đầu tiên, nhưng nó sẽ không khiến đối tượng đó được giữ lại, do đó phá vỡ chu kỳ giữ lại và cho phép cả hai đối tượng được giải phóng.

Ngoài các đại biểu, điều này hữu ích để phá vỡ bất kỳ chu kỳ lưu giữ nào khác có thể hình thành trong mã của bạn. Một cách hữu ích, công cụ Rò rỉ giờ đây bao gồm chế độ xem Chu kỳ, hiển thị các chu kỳ lưu giữ mà nó phát hiện ra trong ứng dụng của bạn dưới dạng đồ họa.

Cả hai __unsafe_unretained__weakngăn chặn việc giữ lại các đối tượng, nhưng theo những cách hơi khác nhau. Đối với __weak, con trỏ tới một đối tượng sẽ chuyển đổi sang vị niltrí giao dịch của đối tượng mà nó trỏ tới, đây là hành vi rất an toàn. Như tên của nó, __unsafe_unretainedsẽ tiếp tục trỏ đến bộ nhớ nơi một đối tượng đã ở đó, ngay cả sau khi nó đã được định vị. Điều này có thể dẫn đến sự cố do truy cập đối tượng được phân bổ theo thỏa thuận đó.

Tại sao bạn sẽ sử dụng __unsafe_unretainedsau đó? Thật không may, __weakchỉ được hỗ trợ cho iOS 5.0 và Lion làm mục tiêu triển khai. Nếu bạn muốn nhắm mục tiêu trở lại iOS 4.0 và Snow Leopard, bạn phải sử dụng bộ định lượng __unsafe_unretainedhoặc sử dụng cái gì đó như MAZeroingWeakRef của Mike Ash .


2
Và tất nhiên __unsafe_unretainedcó thể hữu ích cho việc xác định các mảng C NSStringhằng số và những thứ tương tự, ví dụ:NSString __unsafe_unretained *myStrings = { @"Foo", @"Bar", @"Baz", nil };
jlehr

2
@shannoga - Không, bạn phải chỉ định theo cách thủ công làm định __weakmức cho nó để sử dụng những loại con trỏ đó. Bạn vẫn có thể sử dụng __unsafe_unretainedvới mục tiêu 5.0 hoàn toàn và nó sẽ không hoạt động như thế nào __weak. Nếu bạn muốn thứ gì đó sẽ chuyển đổi giữa hai chế độ tùy thuộc vào việc mục tiêu của bạn có hỗ trợ nó hay không, bạn có thể sử dụng định nghĩa dành riêng cho trình biên dịch như tôi đề xuất ở đây: stackoverflow.com/a/8594878/19679
Brad Larson

4
@jlehr - NSString *myStrings = { @"Foo", @"Bar" };không phải là cú pháp Objective-C hợp lệ; @"Foo"có loại NSString*của chính nó. Có lẽ bạn muốn nói NSString *myStrings[] = { @"Foo", @"Bar" };, nhưng trong trường hợp đó, tôi không thực sự hiểu làm thế nào __unsafe_unretainedsẽ đặc biệt hữu ích.
Quuxplusone

2
@Quuxplusone Đúng trên cả hai số - Tôi đang trộn các mảng C với các cấu trúc. Những gì tôi nên nói là __unsafe_unretainedcó thể là thành viên hữu ích C struct rằng điểm đến hằng NSString, ví dụ:struct foo { __unsafe_unretained NSString * const s; int x; };
jlehr

1
Cũng có ý nghĩa đối với Class. Xem: stackoverflow.com/a/14245894/392847
Quintin Willison

4
  1. Không, bạn cũng có thể sử dụng weakcho các đối tượng mà bạn không sở hữu.
  2. Không, bạn cũng có thể sử dụng unsafe_unretainedtrên tài sản.
  3. Sự hiểu biết của tôi là unsafe_unretainedcác vật phẩm giống như vậy weak, không có thêm sự an toàn khi dọn chúng ra khi vật phẩm mà chúng trỏ tới được giải phóng (và chi phí đi kèm với nó).
  4. Đây hoàn toàn là một thứ ARC.

Trên thực tế, kỳ lạ thay, unsafe_unretainediVars, khi được thiết lập trong thời gian chạy, hoạt động giống như các iVars, strongđiều này khiến tôi tin rằng đó unsafe_unretainedchỉ đơn giản là một gợi ý của trình biên dịch, trong khi yếu thì không. Biết thêm thông tin ở đây: stackoverflow.com/questions/11621028/...
Richard J. Ross III

4

__unsafe_unretainedgiống với những gì lưu trữ mặc định của một đối tượng trước ARC. Với ARC, mặc định bây giờ __strongcó nghĩa là bạn có một tham chiếu đến nó cho đến khi tham chiếu của bạn vượt ra ngoài phạm vi.


1

Một quan sát khác trên __unsafe_unretained: Tôi gặp sự cố trong ứng dụng của mình trên thiết bị chứ KHÔNG phải trên trình mô phỏng với iVars được khai báo là __unsafe_unretained! Vâng, đó là một lỗi trong mã từ quá trình di chuyển ARC, nhưng đây là lần đầu tiên tôi nhận thấy sự khác biệt như vậy giữa thiết bị và trình mô phỏng.

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.