Tôi đang cố gắng hiểu cách chính xác để nhận NSString
từ a CFStringRef
trong ARC? Tương tự cho đi theo hướng ngược lại, CFStringRef
để NSString
trong ARC?
Cách chính xác để làm điều này mà không tạo rò rỉ bộ nhớ là gì?
Tôi đang cố gắng hiểu cách chính xác để nhận NSString
từ a CFStringRef
trong ARC? Tương tự cho đi theo hướng ngược lại, CFStringRef
để NSString
trong ARC?
Cách chính xác để làm điều này mà không tạo rò rỉ bộ nhớ là gì?
retain
ing và release
-ing, bây giờ chúng ta phải sử dụng các phôi "đẹp" như __bridge_transfer
, __unsafe_unretained
và __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ả..)
Câu trả lời:
Thông thường
NSString *yourFriendlyNSString = (__bridge NSString *)yourFriendlyCFString;
và
CFStringRef yourFriendlyCFString = (__bridge CFStringRef)yourFriendlyNSString;
Bây giờ, nếu bạn muốn biết tại sao lại có __bridge
từ 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_retained
hoặc chuyểnCFBridgingRetain
con 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_transfer
hoặcCFBridgingRelease
di 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 CFRelease
bằ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 CFString
bằ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ó
// 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`
// 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;
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 CFRelease
khi không cần thiết. cảm ơn :)
CFRelease
sẽ 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 NULL
con trỏ.
CFStringRef foo (__bridge CFStringRef)theNSString;
vàNSString *bar = (__bridge NSString *)theCFString;