Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

bridged cast: __bridge_transfer vs __bridge with synthesized setter

I am using ARC, and have confusion while using __bridge_transfer. I have a property userName as following:

@property (nonatomic, retain) NSString *userName;
...
@synthesize userName = _userName;
...

CASE 1:

NSString *name = (__bridge_transfer NSString *)ABRecordCopyCompositeName(person);
self.userName = name;

CASE 2:

self.userName = (__bridge_transfer NSString *)ABRecordCopyCompositeName(person);

where person is of type ABRecordRef.

In CASE 1, ARC would release local variable name (as per my understanding, correct me if I am wrong), however what would happen in CASE 2 ? Should I use __bridge in CASE 2 OR CASE 2 should not be used at all ? in CASE 2 with __bridge_transfer or __bridge, how to balance the reference count ?

in CASE 2, with __bridge_transfer, will ARC release the object (the object, which is being passed as an argument to the setter (void)setUserName:(NSString *)userName)?

like image 524
Vasu Avatar asked Jan 16 '13 06:01

Vasu


2 Answers

When you call ABRecordCopyCompositeName(), someone must release the returned object at some point. Using __bridge_transfer ensures that ARC will release the object for you. Without __bridge_transfer, you must release the returned object manually. Those are the only two options.

Therefore, you must use __bridge_transfer in both cases.

A nice exercise is to induce a leak by using __bridge instead of __bridge_transfer, then use Xcode and Instruments to try and find the leak. Does the compiler pick up the leak? Does static analysis (Project -> Analyze) pick up the leak? Does Instruments pick up the leak? If so, you'll then know how to check whether __bridge_transfer solves the problem.

like image 177
Darren Avatar answered Oct 27 '22 00:10

Darren


Case 1 and case 2 are equivalent. Think of it like this:

Case 1:

-(void)func {
  NSString *name = someObject;  // Retain, so +1 on the reference count
  self.userName = name;         // Retain, so +1 on the reference count
  // End of function, name is going out of scope,
  // so release name, so -1 on the reference count.
  // Total change to the reference count: +1 for self.userName.
}

Case 2:

-(void)func {
  self.userName = someObject;   // Retain, so +1 on the reference count
  // End of function.
  // Total change to the reference count: +1 for self.userName.
}

So they work out the same. Note that the compiler is allowed to cancel out a retain and release pair, if it is safe to do so. In a simple case like this it would certainly elide them. Thinking about it with all the +1 and -1 changes to the reference count is just to make it clearer.

To answer the bit about __bridge versus __bridge_transfer: you have called ABRecordCopyCompositeName, which returns a reference to an unmanaged object (a CFStringRef). The Copy in the function name tells you that this object is now owned by you, and you need to release it eventually.

You can either do this by calling CFRelease, or you can ask ARC to do it for you. __bridge tells ARC that it is not allowed to take ownership (in other words, you want to release the object manually, or it isn't owned by you). __bridge_transfer tells ARC that it should take ownership and release the object at the end of the full expression (in other words, you are asking ARC to do the release for you).

With __bridge_transfer:

self.userName = (__bridge_transfer NSString *)ABRecordCopyCompositeName(person);  // +1 inside ABRecordCopyCompositeName, +1 for self.userName, -1 at the end, because of the __bridge_transfer.
// self.userName now is the only strong reference.  Good.

With __bridge:

CFStringRef userName = ABRecordCopyCompositeName(person);  // +1 inside ABRecordCopyCompositeName.
self.userName = (__bridge NSString *)userName;             // +1 for self.userName, ARC does nothing because of the __bridge.
CFRelease(userName);                                       // -1.
// self.userName now is the only strong reference.  Good.

With __bridge and a memory leak:

self.userName = (__bridge NSString *)ABRecordCopyCompositeName(person);  // +1 inside ABRecordCopyCompositeName, +1 for self.userName, ARC does nothing because of the __bridge.
// self.userName now is one strong reference, but reference count is 2.
// Memory leak.
like image 38
Ewan Mellor Avatar answered Oct 27 '22 01:10

Ewan Mellor