NSString เป็น CFStringRef และ CFStringRef เป็น NSString ใน ARC?


89

ฉันกำลังพยายามทำความเข้าใจวิธีที่ถูกต้องในการรับNSStringจากCFStringRefARC หรือไม่? เช่นเดียวกันกับการไปในทิศทางตรงกันข้ามCFStringRefกับNSStringใน ARC?

อะไรคือวิธีที่ถูกต้องในการทำเช่นนี้โดยไม่ทำให้หน่วยความจำรั่วไหล?


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

คุณช่วยอธิบายได้ไหมว่าเกิดอะไรขึ้นโดยละเอียดเมื่อใช้ตัวเลือกทั้งสองนี้
zumzum

ไม่มาก ฉันไม่ได้ใช้ ARC ดังนั้นทั้งหมดที่ฉันรู้ก็คือคุณต้องทำสิ่งนี้ แต่ไม่ใช่เหตุผล

1
@GabrielePetronella ARC ควรจะทำให้การเข้ารหัสง่ายขึ้นโค้ดสั้นลงและอ่านง่ายขึ้นและลดความเป็นไปได้ที่จะเกิดข้อผิดพลาดจากมนุษย์ ดังนั้นตอนนี้แทนที่จะต้องดูแลการนับจำนวนการอ้างอิงโดยretainไอเอ็นจีและreleaseไอเอ็นจีวัตถุที่เราจะต้องตอนนี้ใช้ปลดเปลื้อง "สวย" เหมือน__bridge_transfer, และ__unsafe_unretained __autoreleasingไม่มีใครไม่มีเวลาสำหรับสิ่งนั้น (และอย่างจริงจังมันอ่านยากกว่าในความคิดของฉันมันไม่ได้อำนวยความสะดวกในการจัดการหน่วยความ

1
@ H2CO3 ขอบคุณสำหรับคำตอบ ฉันไม่เห็นด้วยอย่างยิ่งโดยเฉพาะกับประโยคสุดท้าย แต่ฉันเคารพในมุมมองของคุณ :)
Gabriele Petronella

คำตอบ:


180

โดยปกติ

NSString *yourFriendlyNSString = (__bridge NSString *)yourFriendlyCFString;

และ

CFStringRef yourFriendlyCFString = (__bridge CFStringRef)yourFriendlyNSString;

ตอนนี้ถ้าคุณต้องการที่จะรู้ว่าทำไม__bridgeคำหลักคือมีคุณสามารถอ้างถึงเอกสารที่แอปเปิ้ล คุณจะพบ:

__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
}

ในกรณีนี้คุณอาจต้องการบันทึก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 *ไปCFStringใช้หล่อเพื่อที่คุณจะเป็นเจ้าของวัตถุและคุณจะต้องชัดเจนปล่อยมันโดยใช้__bridge_retainedCFRelease


ในการสรุปคุณสามารถมีได้

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;

ขอบคุณมากนี่ไม่ใช่เรื่องง่าย แต่ขอบคุณสำหรับคุณบทเรียนที่ได้เรียนรู้
Sulfkain

@: คำถามเล็กน้อย ดังนั้นถ้าเราใช้ ARC เมื่อเราควรจะใช้NSString->CFString __bridgeแต่เมื่อเราควรจะใช้CFString->NSString __bride_transferเหรอ? และผลข้างเคียงใด ๆ หากเราใช้CFReleaseเมื่อเราไม่ต้องการด้วย ขอบคุณ :)
hqt

@hqt ถ้าคุณต้องการวิธีที่ 'ง่าย' ใช่สิ่งที่คุณพูดนั้นถูกต้อง นอกจากนี้สิ่งพิเศษCFReleaseควรทำให้โปรแกรมของคุณขัดข้องพอสมควรเนื่องจากคุณจะจบลงด้วยการดำเนินการเก็บ / รีลีสที่ไม่ตรงกันในที่สุดก็ปล่อยตัวNULLชี้
Gabriele Petronella
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.