iOS bridge vs bridge_transfer

2019-03-08 13:55发布

问题:

I'm confused with bridge and bridge_transfer, is this correct?

-(void)getData{
    ABAddressBookRef addressBook = ABAddressBookCreate();
    NSArray *allPeople = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeople(addressBook);

    NSString *name;
    for ( int i = 0; i < [allPeople count]; i++ )
    {
        name = (__bridge_transfer NSString *) ABRecordCopyValue((__bridge ABRecordRef)[allPeople objectAtIndex:i], kABPersonFirstNameProperty);
    }
    CFRelease(addressBook);
    allPeople = nil;
}

Is there anyone who can explain me how to use them?

回答1:

If you have automatic-reference-counting (ARC) turned on, the code is correct.

There are two __bridge_transfer in your statements. As a result, the ownership of created CFObjects will be transferred to NSObjects. If you have ARC turned on, they will be freed up automatically. If you used __bridge instead for these 2 statements, you will need to explicitly call CFRelease to release CFObjects created by the *Copy API.

The __bridge statement is also correct. Because you are referencing an NSObject in CF API. You are not transferring ownership, so that ARC will free it up.



回答2:

It is very very simple, When you use ARC (automatic reference counting) the compiler will take care of counting how many objects are being pointed by your variables. When the count goes to 0 the object is automatically dealocated. SO for things that come from a low level structure, like core foundation, the compiler doesnt know what to do. So you use BRIDGE if you just want to tell the compiler "ignore this one, i will release it when i need it". or Bridge transfer if you want to say "Treat this as an object and release it when the reference goes to 0).

When you do this, you create a copy that under normal circumstances should be released by a "CFRelease":

ABAddressBookCopyArrayOfAllPeople(addressBook)

However by adding this, you are transferring the ownership to an objective-c object:

NSArray *allPeople = (__bridge_transfer NSArray*)........

So the NSArray will be managed by ARC.


Note that as JRG mentions, doing this:

CFRelease(addressBook);

Does not affect the newly created object in anyway, but instead the original one which you still have to manually release: (It's easy to tell because those methods usually have the create or copy keywords in their names)


Something that does not happen in your code but you should be careful with is that releasing core foundation objects which are NULL with CFRelease will cause an error. As Paul mentions in his comment.



回答3:

Luis Oscar I'm still working out my understanding of ARC, but I believe addressBook does need CFRelease. ARC is not managing addressBook. NSArray *allPeople is being managed by ARC via the __bridge_transfer cast hint and it is being created as a copy of the original. Without the CFRelease, addressBook will leak.



回答4:

One edit: I believe calling CFRelease on a nil object does cause the app to crash