Я намагаюся зрозуміти правильний спосіб отримання повідомлення NSString
з CFStringRef
ARC? Те саме для руху в зворотному напрямку, CFStringRef
до NSString
ARC?
Який правильний спосіб це зробити, не створюючи витоків пам'яті?
Я намагаюся зрозуміти правильний спосіб отримання повідомлення NSString
з CFStringRef
ARC? Те саме для руху в зворотному напрямку, CFStringRef
до NSString
ARC?
Який правильний спосіб це зробити, не створюючи витоків пам'яті?
retain
та release
додавання об’єктів, ми тепер повинні використовувати "красиві" відливки типу __bridge_transfer
, __unsafe_unretained
та __autoreleasing
. Ніхто не має часу на це. (А якщо серйозно, це важче для читання. На мій погляд, це зовсім не полегшило управління пам’яттю.)
Відповіді:
Зазвичай
NSString *yourFriendlyNSString = (__bridge NSString *)yourFriendlyCFString;
і
CFStringRef yourFriendlyCFString = (__bridge CFStringRef)yourFriendlyNSString;
Тепер, якщо ви хочете дізнатися, чому саме __bridge
ключове слово, ви можете звернутися до документації Apple . Там ви знайдете:
__bridge
передає покажчик між Objective-C та Core Foundation без передачі права власності.
__bridge_retained
абоCFBridgingRetain
передає покажчик Objective-C на покажчик Core Foundation, а також передає вам право власності. Ви несете відповідальність за виклик CFRelease або пов’язаної функції для відмови від права власності на об’єкт.
__bridge_transfer
абоCFBridgingRelease
переміщує вказівник, що не є Objective-C, на Objective-C, а також передає право власності ARC. ARC відповідає за відмову від права власності на об'єкт.
Це означає, що у вищезазначених випадках ви кидаєте об’єкт без зміни власника. Це означає, що в жодному випадку ви не будете відповідальні за обробку пам'яті рядків.
Також може бути випадок, коли з якихось причин ви хочете передати право власності.
Наприклад, розглянемо такий фрагмент
- (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
}
у такому випадку ви можете захотіти зберегти a CFRelease
, передавши право власності під час кастингу.
- (void)sayHi {
CFStringRef str = CFStringCreateWithCString(NULL, "Hello World!", kCFStringEncodingMacRoman);
NSString * aNSString = (__bridge_transfer NSString *)str;
// or alternatively
NSString * aNSString = (NSString *)CFBridgingRelease(str);
NSLog(@"%@", aNSString);
}
Право власності на str
передано, тож тепер ARC розпочне і звільнить пам’ять для вас.
Навпаки, ви можете NSString *
передати a на CFString
за допомогою __bridge_retained
гіста, так що ви будете власником об'єкта, і вам доведеться явно звільнити його за допомогою CFRelease
.
Завершити це можна
// 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
, ми повинні використовувати __bridge
. але коли CFString->NSString
, ми повинні використовувати __bride_transfer
. ? І будь-який побічний ефект, якщо ми використовуємо, CFRelease
коли нам теж не потрібно. спасибі :)
CFRelease
повинна розумно розбити вашу програму, оскільки у вас закінчиться невідповідна операція збереження / вивільнення, в кінцевому підсумку випустивши NULL
покажчик.
CFStringRef foo (__bridge CFStringRef)theNSString;
andNSString *bar = (__bridge NSString *)theCFString;