ARC và cầu nối đúc


166

Với ARC, tôi không còn có thể đúc CGColorRefđến id. Tôi đã học được rằng tôi cần phải thực hiện một dàn diễn viên bắc cầu. Theo tài liệu clang :

Một dàn diễn viên cầu nối được một dàn diễn viên C-phong cách chú thích với một trong ba từ khóa:

(__bridge T) opchuyển toán hạng sang kiểu đích T. Nếu T là một loại con trỏ đối tượng có thể giữ lại, thì opphải có một loại con trỏ không thể giữ lại. Nếu Tlà một loại con trỏ không thể giữ lại, thì op phải có một loại con trỏ đối tượng có thể giữ lại. Nếu không, các diễn viên là không thành hình. Không có chuyển quyền sở hữu và ARC không chèn hoạt động.

(__bridge_retained T) opđưa toán hạng, phải có loại con trỏ đối tượng có thể giữ lại, đến loại đích, phải là loại con trỏ không thể giữ lại. ARC giữ lại giá trị, tuân theo các tối ưu hóa thông thường trên các giá trị cục bộ và người nhận có trách nhiệm cân bằng +1 đó.

(__bridge_transfer T) opđưa toán hạng, phải có loại con trỏ không thể giữ lại, đến loại đích, phải là loại con trỏ đối tượng có thể giữ lại. ARC sẽ giải phóng giá trị ở cuối biểu thức đầy đủ kèm theo, tuân theo các tối ưu hóa thông thường trên các giá trị cục bộ.

Các phôi này được yêu cầu để chuyển các đối tượng vào và ra khỏi điều khiển ARC; xem cơ sở lý luận trong phần chuyển đổi các con trỏ đối tượng có thể giữ lại.

Sử dụng một __bridge_retainedhoặc __bridge_transferđúc hoàn toàn để thuyết phục ARC phát ra một giữ lại hoặc phát hành không cân bằng, tương ứng, là hình thức kém.

Trong những tình huống tôi sẽ sử dụng từng loại?

Ví dụ, CAGradientLayercó một thuộc colorstính chấp nhận một mảng CGColorRefs. Tôi đoán là tôi nên sử dụng __brigeở đây, nhưng chính xác lý do tại sao tôi nên (hoặc không nên) không rõ ràng.


17
Bạn đã xem WWDC 2011 phiên 323 chưa? Điều đó giải thích ARC tốt hơn nhiều so với tôi có thể ở đây. Nó bao gồm tất cả các chi tiết từ đầu đến cuối. Đây là phiên phải xem cho mọi nhà phát triển Mac / iOS.
rbrown

Điều này cũng có thể giúp: stackoverflow.com/questions/14352494/ từ
Ewan Mellor

Liên kết với phiên WWDC, việc tìm kiếm không phải là chuyện nhỏ: developer.apple.com/ideo/play/wwdc2011/323 - Bit có liên quan là vào lúc 23:15
Daniel

Câu trả lời:


215

Tôi đồng ý rằng mô tả là khó hiểu. Vì tôi chỉ cần nắm bắt chúng, tôi sẽ cố gắng tóm tắt:

  • (__bridge_transfer <NSType>) ophoặc cách khác CFBridgingRelease(op)được sử dụng để tiêu thụ số lượng giữ lại CFTypeReftrong khi chuyển nó sang ARC. Điều này cũng có thể được đại diện bởiid someObj = (__bridge <NSType>) op; CFRelease(op);

  • (__bridge_retained <CFType>) ophoặc cách khác CFBridgingRetain(op)được sử dụng để chuyển NSObjectgiao cho đất CF trong khi vẫn giữ số đếm giữ lại +1. Bạn nên xử lý một CFTypeRefbạn tạo theo cách này giống như bạn sẽ xử lý một kết quả CFStringCreateCopy(). Điều này cũng có thể được đại diện bởiCFRetain((__bridge CFType)op); CFTypeRef someTypeRef = (__bridge CFType)op;

  • __bridgechỉ phân đoạn giữa vùng đất con trỏ và vùng đối tượng Objective-C. Nếu bạn không có xu hướng sử dụng các chuyển đổi ở trên, hãy sử dụng chuyển đổi này.

Có lẽ điều này là hữu ích. Bản thân tôi, tôi thích các CFBridging…macro hơn một chút so với các diễn viên đơn giản.


Các đối tượng có giữ được số lượng tăng thêm 1 cung khi bạn sử dụng __bridge_transfer không? Nếu không, có vẻ như thời điểm CFRelease () được gọi là đối tượng đã biến mất và chỉ vào không có gì. Tương tự, khi bạn sử dụng __bridge_retain, ARC có làm giảm số lần giữ lại của op không? Khác, có vẻ như các đối tượng sẽ không bao giờ được phát hành đúng.
Tony

2
Khi ở trong vùng đất ARC, bạn không nghĩ về việc giữ lại số lượng nữa, chỉ về các tham chiếu mạnh và yếu.
monkeydom

4
Phải, nếu bạn chỉ ở trong vùng đất vòng cung thì mạnh / yếu là đủ, tuy nhiên khi bạn đang chuyển đổi các vật thể giữa môi trường vòng cung và không vòng cung, bạn vẫn phải suy nghĩ về hàm ý đếm giữ dưới mui xe
Tony

3
Không hẳn vậy. Bạn cần suy nghĩ về việc ra vào đất ARC. Và điều này là khá đáng nhớ của việc nắm bắt tự động. (đủ thú vị: ARC sửa một mô hình phổ biến như lấy một đối tượng ra khỏi từ điển và sau đó xóa nó trước khi sử dụng, v.v.)
monkeydom

3
sử dụng công cụ Trình phân tích (shift + lệnh + B) có thể giúp giải quyết loại nghi ngờ đó, vì nó sẽ cho bạn biết bằng ngôn ngữ tự nhiên nếu mã hiện tại bị rò rỉ bộ nhớ. Nếu vậy, có lẽ bạn đang sử dụng một diễn viên giữ lại trong khi bạn nên sử dụng một diễn viên không giữ lại. nếu Trình phân tích không cảnh báo bạn về bất cứ điều gì trong các dòng mã đó, thì có lẽ bạn đang làm tốt với mã hiện tại
Fabio Napodano

55

Tôi tìm thấy một lời giải thích khác trong tài liệu iOS mà tôi nghĩ là dễ hiểu hơn:

  • __bridge chuyển một con trỏ giữa Objective-C và Core Foundation mà không chuyển quyền sở hữu.

  • __bridge_retained (CFBridgingRetain)chuyển một con trỏ Objective-C sang một con trỏ Core Foundation và cũng chuyển quyền sở hữu cho bạn.

    Bạn có trách nhiệm gọi CFRelease hoặc một chức năng liên quan để từ bỏ quyền sở hữu đối tượng.

  • __bridge_transfer (CFBridgingRelease)di chuyển một con trỏ không phải Objective-C sang Objective-C và cũng chuyển quyền sở hữu sang ARC.

    ARC có trách nhiệm từ bỏ quyền sở hữu đối tượng.

Nguồn: Các loại cầu nối miễn phí


33

Tiếp theo, trong trường hợp cụ thể này, nếu bạn đang ở trên iOS, Apple khuyên bạn nên sử dụng UIColor và -CGColorphương thức của nó để trả lại CGColorRef vào colorsNSArray. Trong phần Ghi chú chuyển đổi sang ARC , trong phần "Trình biên dịch xử lý các đối tượng CF được trả về từ các phương thức ca cao", nó được chỉ ra rằng sử dụng một phương thức -CGColortrả về một đối tượng Core Foundation sẽ tự động được trình biên dịch xử lý đúng cách.

Vì vậy, họ đề nghị sử dụng mã như sau:

CAGradientLayer *gradientLayer = (CAGradientLayer *)[self layer];
gradientLayer.colors = [NSArray arrayWithObjects:(id)[[UIColor darkGrayColor] CGColor],
                                                 (id)[[UIColor lightGrayColor] CGColor], nil];

Lưu ý rằng ngay từ bây giờ, mã ví dụ của Apple đang thiếu (id) cast tôi có ở trên, điều này vẫn cần thiết để tránh lỗi trình biên dịch.


Bạn thường có thể thoát khỏi chỉ bằng cách chuyển đối tượng đầu tiên sang (id) thay vì tất cả chúng, nếu bạn thích.
Philippe Sabourin

1
Câu hỏi này hỏi về việc truyền với ARC, nơi mã bạn đã dán không hợp pháp.
Joey Hagedorn

11
@JoeyHagedorn - Có lẽ bạn đã bỏ lỡ tài liệu tham khảo của tôi về tài liệu ARC trong câu đầu tiên trong câu trả lời của tôi, nhưng không chỉ hợp lệ theo ARC, đây là cách tiếp cận được đề xuất để cung cấp các tham chiếu CGColorRef vào NSArrays từ các phương thức chuyển đổi UIColor này. Tôi và nhiều người khác sử dụng mã chính xác này trong các ứng dụng hỗ trợ ARC. Việc truyền ngay tới (id) từ một phương thức trả về đối tượng Core Foundation sẽ tự động kết nối đối tượng đó với ARC đúng cách.
Brad Larson
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.