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)?
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.
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.
Precisely because this is confusing, I recommend that you use CFBridgingRelease() and CFBridgingRetain() rather than casts with __bridge_transfer and __bridge_retained, respectively. Then, the only "unusual" cast you need to remember is __bridge, which does nothing with ownership.
I find it easier to remember because, with something like ABRecordCopyCompositeName() which leaves you with the responsibility to CFRelease() the returned object, you can use CFBridgingRelease() to discharge that responsibility and the analogy is obvious.
Similarly, you'd only use CFBridgingRetain() in a context where you would use CFRetain() if the object pointer were already a Core Foundation type.
So, your code could be:
NSString *name = CFBridgingRelease(ABRecordCopyCompositeName(person));
self.userName = name;
Or:
self.userName = CFBridgingRelease(ABRecordCopyCompositeName(person));
In both cases, the CFBridgingRelease() balances the Copy in the function name that implies that you have a responsibility to release the object. After that, it's all somebody else's responsibility. ARC manages the name variable. The implementer of the setter for the userName property manages that. (It happens to be ARC in this case, too, but that's irrelevant.)
Related
In c++ i would do the following,
Object* obj1;
Object* obj2;
Object** targetObj;
void SetTargetToObj1()
{
targetObj = &obj1;
}
void SetTargetToObj2()
{
targetObj = &obj2;
}
void ValueChanged()
{
//So if SetTargetToObj2() was called before ValueChanged() we
// would be changing some data on obj2
(*targetObj)->ChangeSomeData();
//or, we obj2 is null we could assign a new object to it via targetObj
(*targetObject) = new Object();
//now obj2 is pointing to our new object
}
Im wondering if there is a way in obj-c to do this same thing with NSObjects?
Pointers to pointers are not so simple under ARC.
When you declare, say, an instance variable:
NSObject *someObject;
you are implicitly declaring:
NSObject * __strong someObject;
i.e. a strong pointer. Strong is just one of the ownership qualifiers, you can also have weak and autoreleasing qualifiers.
Now taking the example in your comment:
NSDate **targetDate;
you get the error "pointer to non-const type 'NSDate *' with no explicit ownership". This is because ARC needs to know the ownership qualification of the pointer your pointer is referring to (read it slowly! ;-)). i.e ARC is asking you to type the variable instead as:
NSData * 'some ownership qualifer' * targetDate;
which, once you've decoded C's type priority rules, is a "pointer to a 'some ownership qualifier' pointer to an NSDate".
The error message includes "non-const" as this is all about writing via your pointer to pointer - ARC still needs to know how to handle the store, which depends on whether the pointed at reference is strong, weak, etc.
In your simple case the following should do:
NSObject *obj1;
NSObject *obj2;
NSObject * __strong * targetObj;
and then when doing (*targetObj) = ... etc. ARC knows what to do for memory management - which in this case is to release the old value in the variable referenced by targetObj as well as assigning the new reference into that variable.
Essential reading is Automatic Reference Counting and Transitioning to ARC Release Notes - in particular look up NSError in the latter as it explains how the common pattern of declaring error parameters as NSError ** is handled under ARC.
The code you have right there is already fine. If Object is in fact an obj-c object then this exact code is what you want. The only quirk is potential memory management issues (e.g. does targetObj need to retain the thing it's pointing to?)
I have an NSString that I've retained, and the only place I release it is in the dealloc method. For some reason, however, later in the program when I try to reference it (its length, specifically), I get a crash, saying [CFString length]:message sent to deallocated instance 0xff32c50.
I explicitly retain the string earlier in the program. Is there any reason why this would be happening? Any help is appreciated.
The string, entityParameter, is declared in the header, and defined later.
Here is some of the code:
entityParameter = [[EntitySearchWindow stringByEvaluatingJavaScriptFromString:#"f();"] retain];
The place where I'm getting the crash looks like this:
if([entityParameter length] != 0 && entityParameter != nil)
{
return;
}
I have an NSString that I've retained,
and the only place I release it is in
the dealloc method. For some reason,
however, later in the program when I
try to reference it (its length,
specifically), I get a crash, saying
[CFString length]:message sent to
deallocated instance 0xff32c50.
Obviously, it isn't retained, then.
If by "retained" you mean "assigned to a property", are you doing:
self.prop = [NSString ...];
Or:
prop = [NSString ...];
Because the former will retain (if the property is declared as retain) whereas the latter will not. Note that NSString properties should generally be declared copy, but that is orthogonal to the question).
If your code is as written:
entityParameter = [[EntitySearchWindow stringByEvaluatingJavaScriptFromString:#"f();"] retain];
And you really do only release it in dealloc, then make sure your containing object hasn't already been deallocated. That may be happening. Or it might be that you've leaked the string reference somewhere and spuriously deleted it without a retain.
Using Zombie detection in instruments with "track retain/release events" (or whatever it is called) should show you every last retain/release event on the object, including the one the blew up.
I know this has been discussed ad-nauseum but I just don't get some of the memory management. I understand that retain keeps the object alive and copy gives one a separate copy of an object.
What I don't get is when it comes to ivars & properties, retain as a property means that the setter releases the old value & retains the new:
property = newValue;
// retain
if (property != newValue)
{
[property release];
property = [newValue retain];
}
but I've seen examples where they assign static strings to the retain property ivars e.g.
self.stringProperty = #"something";
(some other code)
self.stringProperty = #"somethingElse";
The second call to set string should call release on the static string which is not allowed, why doesn't the program crash?
Also, if an object is declared with the retain property & then is assigned something with init, e.g.
#property(retain)someArray;
someArray = [[NSArray alloc] initWithArray:arbArray];
does that mean someArray now has a retain count of 2 but if it was created with
someArray = [NSArray arrayWithArray:arbArray];
the retain count is only 1 because the 2nd is a factory method?
The second call to set string should call release on the static string which is not allowed, why doesn't the program crash?
You can pass release to a constant string, it just won't do anything meaningful, so those lines of code are valid.
does that mean someArray now has a retain count of 2 but if it was created with...the retain count is only 1 because the 2nd is a factory method?
Well, first of all,
someArray = [[NSArray alloc] initWithArray:arbArray];
doesn't use the methods created by #property, it just accesses the ivar directly. To use the property methods, you'd have to use self.someArray = ...;.
But yes,
[[NSArray alloc] initWithArray:arbArray]
returns an object with an effective retain count of 1, and
[NSArray arrayWithArray:arbArray]
returns an object with an effective retain count of 0, so if you did pass them through the "retain" setter created by #property, the ivar would have an effective retain count of 2 and 1, respectively.
This is more that one question, but anyway...
Static strings are special cases in a number of ways, one of which is that you can retain and release them to your heart's content without it having any effect.
As an aside, NString properties often have copy rather than retain semantics, which would anyway obviate that question if it mattered. But it doesn't.
In your second case, assigning to a retain property directly from an alloc (or copy or other ownership-granting call) is bad practice and will leak unless you actively add a corresponding release afterwards, or autorelease during, eg:
self.someArray = [[[NSArray alloc] initWithArray:arbArray] autorelease];
But there's really no reason not to use the class method in this particular case.
The second call to set string should call release on the static string which is not allowed, why doesn't the program crash?
It's not a static string, it's a constant string. However, that is irrelevant to the question, but actually you are allowed to send -retain to any Objective-C object derived from NSObject except NSAutoreleasePool. If you look at the retainCount (a bit naughty, but since we are discussing implementation, OK) of a constant NSString e.g.
NSLog(#"retain count = %u", [#"foo" retainCount]);
you'll most likely find it's set to a really big number (UINT_MAX in fact). This is a signal to the run time to ignore calls to release and retain.
By the way, forgetting to release objects won't crash the program straight away. In fact, if you have lots of RAM, you might not notice until the OS starts swapping.
does that mean someArray now has a retain count of 2 but if it was created with
No, because you didn't use the property to assign the new array, you went straight to the ivar:
self.someArray = [[NSArray alloc] initWithArray:arbArray];
would be a leak.
self.someArray = [NSArray arrayWithArray:arbArray];
would be OK.
I am just curious, do I need to add a further [name release] elsewhere to match up with the retain here in the getter?
- (NSString *)name {
return [[name retain] autorelease];
}
gary
No, but you shouldn't need to do this at all since you are not allocating anything. You could simply return name and that should be fine. Was there a reason you needed to add this retain/autorelease?
A little more explanation, what is happening here is that your retain count goes up by one when you do a retain, and then down by 1 when the scope exists because of the autorelease.
I don't know how your variable definition is in your class but the rule is that in your getter you should return the object unchanged for the reference count. It's the responsability of the caller to call retain if it want to keep a reference on it.
- (NSString*) name {
return name;
}
// caller
NSString* name = object.name;
[name retain]; // if necessary. If the string is used only in the context of a method you do not have to retain it.
If you are using the returned value as a field in another class you should define your field like this:
#property(retain, nonatomic) NSString* name;
With this a retain will be called when you assign to the variable.
No, this is fine. autorelease will cause the value to be released when the current autorelease pool is drained.
Every retain must be matched with exactly 1 of either release or autorelease.
However, I believe both the retain and autorelease are unneeded here. Generally you want to use that autorelease idiom because you've alloc'ed something in the method.
No. The autorelease will balance it out. I don't think, however, that the retain and autorelease would be necessary. You can simply use return name.
As others have said, you do not need to retain or autorelease the property. Since callers of the 'getter' method did not create the object, they do not own it, and you are safe to assume that they won't tinker around with its retain count.
But, callers could potentially change the value of the variable returned by the getter, which would affect the object. Therefore, it would probably be a better idea to return a copy of your variable, especially since it is an NSString. (Getters for NSString objects often return a copy.)
- (NSString *)name {
return [[name copy] autorelease];
}
In this scenario, you are creating a copy of the variable, so you 'own' it. By autoreleasing it before it is returned, you ensure that it will survive long enough to be used in the caller's scope, and that any changes they make to the 'name' variable will not affect the underlying object.
I am just curious, do I need to add a further [name release] elsewhere to match up with the retain here in the getter?
- (NSString *)name {
return [[name retain] autorelease];
}
No, because you are already releasing it. autorelease just means “send yourself release later”.
I think you should review the memory-management rules.
I think I might have figured it out:
if [myString] is created outside the method then your safe to use ...
return myString;
if on the other hand [myString] is created inside the method and therefore needs to be released and returned, then you use.
myString = [[NSString alloc] initWithFormat: #"Send me home"];
return [myString autorelease];
This way the method sets [myString] to autorelease, Basically the object is created, set to autorelease and returned. The object will ultimately be released when the pool is destroyed.
I understand that any init... method initializes a new object and that NSString stringWithString makes a copy of the parameter string as a new object. I also understand that being the objects' owner, I can control the release/deallocation of any objects that I allocate. What I don't understand is when would I use the stringWithString method since any local variable assigned that way would have it's memory "owned" by NSString instead of the local class.
The "Programming in Objective C" book by Kochan (1st ed) uses the following code (see pages 342-344) to explain that the initWithString is preferable to stringWithString because the AddressCard class would own the name variable contents. Also, I don't get any errors making repeated calls to the setName version with the stringWithString method. TIA!!
//header file has appropriate declarations but not included here:
#import "AddressCard.h"
#implementation AddressCard;
-(NSString *) name
{
return name;
}
//Recommended code:
-(void) setName: (NSString *) theName
{
[name release]
name = [[NSString alloc] initWthString: theName];
}
//Incorrect code according to Kochan:
-(void) setName: (NSString *) theName
{
[name release]
name = [NSString stringWthString: theName];
}
//rest of class implementation code snipped
#end
What I don't understand is when would I use the stringWithString method since any local variable assigned that way would have it's memory "owned" by NSString instead of the local class.
What? No.
The rules are simple:
Any object returned by alloc, copy, copyWithZone, or new has a retain count of 1.
retain increases the receiving object's retain count.
release decreases the receiving object's retain count.
autorelease tells the current autorelease pool to send the receiving object the release message “later”.
Any factory method that doesn't have “new” or “copy” in the name (e.g., stringWithString:) returns an object that it has autoreleased on your behalf.
Or, digested a bit:
Any method whose name contains copy, alloc, retain, or new returns an object that you own.
Any method that doesn't, returns an object that you don't own.
To own an object, retain it.
The incorrect implementation of setName: that you show is incorrect because it stores an autoreleased object in an instance variable, when you mean to own the object. You should retain it or, in this case, copy it. One way is to simply use alloc and initWithString:, as in the correct example you show; the other way would be copy.
The Memory Management Programming Guide for Cocoa explains everything. Every Cocoa or Cocoa Touch programmer should read or re-read it from time to time.
Actually, both setters are wrong. The 'incorrect' one is wrong for general memory management reasons (which are well-expounded elsewhere). The 'recommended' one is wrong for 2 reasons:
if (theName == name), then you're
likely to deallocate your object in
the first line, and then attempt to
use the deallocated object as a
parameter to -initWithString: on the
second line, resulting in undefined
behavior.
-initWithString: does not handle being passed nil gracefully.
The 'correct' (IMHO) method is:
-(void) setName: (NSString *) theName
{
if (theName == name) return; // if they're equal, no need to do anything further
[name release];
name = [theName copy]; // sets name to nil if theName is nil
}
For most objects you'll actually want to -retain instead of -copy on that third line, but for strings it's almost always better to copy.
The difference between initWithString and stringWithString is that stringWithString returns an auto-released pointer. This means that you don't need to release it specifically, since that will be taken care of next time that the auto-release pool cleans up any auto-released pointers.
initWithString, on the other hand, returns a pointer with a retain count of 1 - you do need to call release on that pointer, or else it would result in a memory leak.
See https://stackoverflow.com/questions/193288/what-is-the-cost-of-using-autorelease-in-cocoa for some reasons as why you should use auto-release vs release.
In the Incorrect code above, the next time name is referenced after setName is called, you'll get an exception error, since the object will have been released. You can use either the "Correct" code, or wrap your stringWithString call in an explicit retain call:
name = [[NSString stringWithString: theName] retain];
What I don't understand is when would I use the stringWithString method since any local variable assigned that way would have it's memory "owned" by NSString instead of the local class.
A string created with stringWithString: isn't owned by the NSString, it is owned by the NSAutoreleasePool (although multiple places can retain an object, making ownership shared).
With stringWithString:, the string will become invalid when the autorelease pool is next processed (normally during the application's next event loop) because the NSAutoreleasePool will release its pointer. If you have not retained the string before then, any pointer you have to it (name in the case of your class) will be invalid (the variable name will still exist but it will point to garbage).
Autorelease is good, if you don't intend to keep any pointers to the NSString but since you do intend to keep a pointer, you'll need to retain the NSString. initWithString: gives you a retain count of 1 automatically.