NSString tới CFStringRef và CFStringRef tới NSString trong ARC?


87

Tôi đang cố gắng hiểu cách chính xác để nhận NSStringtừ a CFStringReftrong ARC? Tương tự cho đi theo hướng ngược lại, CFStringRefđể NSStringtrong ARC?

Cách chính xác để làm điều này mà không tạo rò rỉ bộ nhớ là gì?


4
CFStringRef foo (__bridge CFStringRef)theNSString;NSString *bar = (__bridge NSString *)theCFString;

Bạn có thể giải thích chi tiết điều gì đang thực sự xảy ra khi hai tùy chọn đó được sử dụng không?
zumzum

Không hẳn. Tôi không sử dụng ARC, vì vậy tất cả những gì tôi biết là bạn phải làm điều này, nhưng không phải lý do tại sao.

1
@GabrielePetronella ARC được cho là giúp mã hóa dễ dàng, mã ngắn hơn, dễ đọc hơn và giảm khả năng mắc lỗi của con người. Vì vậy, bây giờ thay vì phải quan tâm đến số lượng tham chiếu bằng các đối tượng retaining và release-ing, bây giờ chúng ta phải sử dụng các phôi "đẹp" như __bridge_transfer, __unsafe_unretained__autoreleasing. Không ai không có thời gian cho việc đó. (Và nghiêm túc, đó là khó khăn hơn để đọc Theo tôi, nó đã không tạo điều kiện quản lý bộ nhớ gì cả..)

1
@ H2CO3 cảm ơn bạn đã trả lời. Tôi phản đối kịch liệt, đặc biệt là với câu cuối cùng, nhưng tôi tôn trọng quan điểm của bạn :)
Gabriele Petronella

Câu trả lời:


177

Thông thường

NSString *yourFriendlyNSString = (__bridge NSString *)yourFriendlyCFString;

CFStringRef yourFriendlyCFString = (__bridge CFStringRef)yourFriendlyNSString;

Bây giờ, nếu bạn muốn biết tại sao lại có __bridgetừ khóa đó, bạn có thể tham khảo tài liệu của Apple . Ở đó bạn sẽ tìm thấy:

__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_retainedhoặc chuyển CFBridgingRetaincon trỏ Objective-C tới 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 hàm liên quan để từ bỏ quyền sở hữu đối tượng.

__bridge_transferhoặc CFBridgingReleasedi chuyển con trỏ không phải Objective-C sang Objective-C và cũng chuyển quyền sở hữu cho ARC. ARC có trách nhiệm từ bỏ quyền sở hữu đối tượng.

Có nghĩa là trong các trường hợp trên, bạn đang truyền đối tượng mà không thay đổi quyền sở hữu. Điều này ngụ ý rằng trong cả hai trường hợp, bạn sẽ không phụ trách việc xử lý bộ nhớ của các chuỗi.

Cũng có thể có trường hợp bạn muốn chuyển quyền sở hữu vì một lý do nào đó.

Ví dụ: hãy xem xét đoạn mã sau

- (void)sayHi {
    CFStringRef str = CFStringCreateWithCString(NULL, "Hello World!", kCFStringEncodingMacRoman);

    NSString * aNSString = (__bridge NSString *)str;

    NSLog(@"%@", aNSString);

    CFRelease(str); //you have to release the string because you created it with a 'Create' CF function
}

trong trường hợp này, bạn có thể muốn lưu a CFReleasebằng cách chuyển quyền sở hữu khi truyền.

- (void)sayHi {
    CFStringRef str = CFStringCreateWithCString(NULL, "Hello World!", kCFStringEncodingMacRoman);

    NSString * aNSString = (__bridge_transfer NSString *)str;
// or alternatively
    NSString * aNSString = (NSString *)CFBridgingRelease(str);

    NSLog(@"%@", aNSString);
}

Quyền sở hữu của strđã được chuyển giao, vì vậy bây giờ ARC sẽ hoạt động và giải phóng bộ nhớ cho bạn.

Ngược lại, bạn có thể truyền một NSString *đối tượng CFStringbằng cách sử dụng __bridge_retainedép kiểu, vì vậy bạn sẽ sở hữu đối tượng và bạn sẽ phải giải phóng nó một cách rõ ràng bằng cách sử dụng CFRelease.


Để kết thúc nó, bạn có thể có

NSString → CFString

// Don't transfer ownership. You won't have to call `CFRelease`
CFStringRef str = (__bridge CFStringRef)string;

// Transfer ownership (i.e. get ARC out of the way). The object is now yours and you must call `CFRelease` when you're done with it
CFStringRef str = (__bridge_retained CFStringRef)string // you will have to call `CFRelease`

CFString → NSString

// Don't transfer ownership. ARC stays out of the way, and you must call `CFRelease` on `str` if appropriate (depending on how the `CFString` was created)
NSString *string = (__bridge NSString *)str;

// Transfer ownership to ARC. ARC kicks in and it's now in charge of releasing the string object. You won't have to explicitly call `CFRelease` on `str`
NSString *string = (__bridge_transfer NSString *)str;

Cảm ơn bạn rất nhiều, điều này không thực sự trực quan, nhưng nhờ bạn, bài học rút ra
Sulfkain

@: câu hỏi nhỏ. vì vậy nếu chúng ta sử dụng ARC. khi nào NSString->CFString, chúng ta nên sử dụng __bridge. nhưng khi nào CFString->NSString, chúng ta nên sử dụng __bride_transfer. ? Và bất kỳ tác dụng phụ nào, nếu chúng ta sử dụng CFReleasekhi không cần thiết. cảm ơn :)
hqt

@hqt, nếu bạn muốn cách 'dễ dàng', vâng những gì bạn nói là đúng. Ngoài ra, một phần bổ sung CFReleasesẽ làm hỏng chương trình của bạn một cách hợp lý, vì bạn sẽ kết thúc với hoạt động giữ lại / phát hành không khớp, cuối cùng giải phóng một NULLcon trỏ.
Gabriele Petronella
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.