Trong những tình huống nào, chúng tôi cần viết bộ định tính quyền sở hữu __autoreleasing theo ARC?


118

Tôi đang cố gắng hoàn thành câu đố.

__stronglà mặc định cho tất cả các con trỏ đối tượng có thể truy xuất được Objective-C như NSObject, NSString, v.v. Đây là một tham chiếu mạnh. ARC cân bằng nó với một -releaseở cuối phạm vi.

__unsafe_unretainedbằng cách cũ. Nó được sử dụng cho một con trỏ yếu mà không giữ lại đối tượng có thể truy xuất được.

__weakgiống như __unsafe_unretainedngoại trừ việc nó là một tham chiếu yếu tự động zeroing nghĩa là con trỏ sẽ được đặt thành nil ngay khi đối tượng được tham chiếu được phân bổ. Điều này giúp loại bỏ nguy cơ con trỏ treo lơ lửng và lỗi EXC_BAD_ACCESS.

Nhưng chính xác thì __autoreleasingtốt cho điều gì? Tôi đang gặp khó khăn khi tìm các ví dụ thực tế về thời điểm tôi cần sử dụng vòng loại này. Tôi tin rằng nó chỉ dành cho các hàm và phương thức mong đợi một con trỏ con trỏ chẳng hạn như:

- (BOOL)save:(NSError**);

hoặc là

NSError *error = nil;
[database save:&error];

theo ARC phải được khai báo theo cách này:

- (BOOL)save:(NSError* __autoreleasing *);

Nhưng điều này quá mơ hồ và tôi muốn hiểu đầy đủ tại sao . Đoạn mã mà tôi tìm thấy đặt __autoreleasing ở giữa hai ngôi sao, điều này trông kỳ lạ đối với tôi. Kiểu là NSError**(một con trỏ trỏ tới NSError), vậy tại sao lại đặt __autoreleasingở giữa các ngôi sao chứ không chỉ ở phía trước NSError**?

Ngoài ra, có thể có những tình huống khác mà tôi phải dựa vào __autoreleasing.


1
Tôi có cùng câu hỏi này và các câu trả lời bên dưới không hoàn toàn thuyết phục ... ví dụ: tại sao hệ thống không cung cấp các giao diện lấy các đối số NSError ** được khai báo với trình trang trí __autoreleasing như bạn và Ghi chú chuyển đổi sang Arc phát hành nói rằng họ nên là? ví dụ: Bất kỳ trong số nhiều quy trình này trong NSFileManager.h ??
Bố

Câu trả lời:


67

Bạn đúng. Như tài liệu chính thức giải thích:

__autoreleasing để biểu thị các đối số được truyền bằng tham chiếu (id *) và được tự động trả về.

Tất cả điều này được giải thích rất rõ trong hướng dẫn chuyển đổi ARC .

Trong ví dụ về NSError của bạn, khai báo có nghĩa là __strong:

NSError * e = nil;

Sẽ được chuyển đổi thành:

NSError * __strong error = nil;

Khi bạn gọi savephương thức của mình :

- ( BOOL )save: ( NSError * __autoreleasing * );

Sau đó, trình biên dịch sẽ phải tạo một biến tạm thời, được đặt tại __autoreleasing. Vì thế:

NSError * error = nil;
[ database save: &error ];

Sẽ được chuyển đổi thành:

NSError * __strong error = nil;
NSError * __autoreleasing tmpError = error;
[ database save: &tmpError ];
error = tmpError;

Bạn có thể tránh điều này bằng cách khai báo __autoreleasingtrực tiếp đối tượng lỗi dưới dạng .


3
Không, __autoreleasingchỉ được sử dụng cho các đối số được truyền bằng tham chiếu. Đây là một trường hợp đặc biệt, vì bạn có một con trỏ tới con trỏ của một đối tượng. Đó không phải là trường hợp của những thứ như hàm tạo tiện lợi, vì chúng chỉ trả về một con trỏ đến một đối tượng và khi ARC xử lý nó tự động.
Macmade

7
Tại sao bộ định lượng __autoreleasing lại được đặt ở giữa các ngôi sao, chứ không chỉ ở phía trước NSError **? Điều này trông kỳ lạ đối với tôi vì loại là NSError **. Hay là vì điều này đang cố gắng chỉ ra rằng con trỏ trỏ tới NSError * phải đủ điều kiện để trỏ đến một đối tượng đã được tự động phát hành?
Thành viên Tự hào

1
@Proud Member liên quan đến nhận xét đầu tiên của bạn - điều đó không chính xác (nếu tôi hiểu bạn đúng) - hãy xem câu trả lời của Glen Low bên dưới. Đối tượng lỗi được tạo và gán cho một biến tự động giảm giá trị (biến mà bạn đã chuyển vào) bên trong hàm lưu. Việc gán này khiến đối tượng được giữ lại và tự động cài đặt tại thời điểm đó. Việc khai báo hàm lưu ngăn chúng ta gửi nó bất kỳ thứ gì khác ngoài một biến tự động giảm giá trị vì đó là những gì nó cần - đó là lý do tại sao trình biên dịch tạo ra một biến tạm thời nếu chúng ta cố gắng.
Colin

2
Vậy tại sao dường như không có giao diện nào của Apple có điều này? ví dụ: mọi thứ trong NSFileManager.h?
Bố

1
@Macmade: Tình cờ tôi nhận thấy rằng câu trả lời của bạn đã được chỉnh sửa (bởi stackoverflow.com/users/12652/comptrol ) và tôi có ấn tượng rằng ít nhất những thay đổi đối với ví dụ đầu tiên của bạn ("ngầm định ... sẽ được chuyển thành ...) sai, vì vòng loại __strong đã được chuyển từ dòng thứ hai sang dòng đầu tiên. Có lẽ bạn có thể kiểm tra điều đó.
Martin R

34

Theo dõi câu trả lời của Macmade và câu hỏi tiếp theo của Thành viên Tự hào trong phần bình luận, (cũng sẽ đăng điều này dưới dạng bình luận nhưng nó vượt quá số ký tự tối đa):

Đây là lý do tại sao giá trị định lượng biến __autoreleasing được đặt giữa hai dấu sao.

Để mở đầu, cú pháp chính xác để khai báo một con trỏ đối tượng với một định nghĩa là:

NSError * __qualifier someError;

Trình biên dịch sẽ tha thứ cho điều này:

__qualifier NSError *someError;

nhưng nó không chính xác. Xem hướng dẫn chuyển đổi ARC của Apple (đọc phần bắt đầu "Bạn nên trang trí các biến một cách chính xác ...").

Để giải quyết câu hỏi hiện tại: Con trỏ kép không thể có bộ định tính quản lý bộ nhớ ARC vì con trỏ trỏ đến địa chỉ bộ nhớ là con trỏ tới kiểu nguyên thủy, không phải là con trỏ tới một đối tượng. Tuy nhiên, khi bạn khai báo một con trỏ kép, ARC muốn biết các quy tắc quản lý bộ nhớ cho con trỏ thứ hai là gì. Đó là lý do tại sao các biến con trỏ kép được chỉ định là:

SomeClass * __qualifier *someVariable;

Vì vậy, trong trường hợp đối số phương thức là con trỏ NSError kép, kiểu dữ liệu được khai báo là:

- (BOOL)save:(NSError* __autoreleasing *)errorPointer;

trong tiếng Anh nói rằng "con trỏ đến một con trỏ đối tượng __autoreleasing NSError".


15

Đặc điểm kỹ thuật ARC cuối cùng nói rằng

Đối với các đối tượng __autoreleasing, con trỏ mới được giữ lại, tự động phân bổ và lưu trữ vào lvalue bằng cách sử dụng ngữ nghĩa nguyên thủy.

Vì vậy, ví dụ, mã

NSError* __autoreleasing error = someError;

thực sự được chuyển đổi thành

NSError* error = [[someError retain] autorelease];

... đó là lý do tại sao nó hoạt động khi bạn có một tham số NSError* __autoreleasing * errorPointer, phương thức được gọi sau đó sẽ gán lỗi cho *errorPointervà ngữ nghĩa trên sẽ bắt đầu.

Bạn có thể sử dụng __autoreleasingtrong một ngữ cảnh khác để buộc một đối tượng ARC vào nhóm tự động vui lòng, nhưng điều đó không hữu ích lắm vì ARC dường như chỉ sử dụng nhóm tự động phát hành tại phương thức trả về và đã tự động xử lý.

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.