Releasing a (nonatomic, retain) synthetized property - iphone

My question looks like a dozen ones about releasing properties, but I can't find the exact answer i'm searching for.
When a property is declared with retain :
#property (nonatomic, retain) NSString * myString;
then
#synthesize myString;
It generates getters and setters with retaining and releasing operations. Okay.
Of course, property must be released in dealloc.
-(void)dealloc {
[myString release];
myString = nil;
[super dealloc];
}
So that's clean.
But what if i never use myString ? Is it pre-initialised ? My opinion is the myString retain-count would be 0. But releasing myString in dealloc would decrease it and make the application crash ? But it does not crash !
Is a cleaner way to release it like ?
if(myString != nil) {
[myString release];
myString = nil;
}

The key thing you are missing is that you can send messages to nil. So no, your latter approach is not cleaner, just unnecessary.
If you never use myString, it's not initialized to anything. It remains nil. When you release it, you are effectively doing [nil release] - which doesn't actually do anything. Hence no crash.

There is no need to check wether it is nil.
If you send the release to a nil object nothing happens, so why check.
When an instance of object is created the property will be set to nil unless you initialize it in any of the init methods.
It not the same with variables you create in a method, they could point to invalid memory. Thus setting these to nil is the safe way. This is not needed for properties.

You can send release messages to nil objects in objective-c this way nothing happens. I mean the application wont crash. The idea behind setting objects to nil comes handy when an object is used in multithreaded environment since with multiple threads you can't always guarantee that an instance variable will only be read before it's released.

if you are using #property(retain/copy) & #synthesize there is no need to check for nil. It won't crash or throw EXC_BAD_ACCESS.
Otherwise, if you are not using that, you have to check whether the variable is nil or not, or it will crash if the variable is nil.

Related

Impact of releasing a variable more then the retain count

I have a instance variable declared as a retain property & then I released it 2 times. After releasing it I am not using it. This is not resulting into any crash. Is there any other impact of releasing a variable more than required (given that the variable is not going to be used after the release):
#property (nonatomic, retain) NSString *myVariable;
self.myVariable = nil;
self.myVariable = nil;
You are not, in fact, releasing it twice. This is because you're using properties. The first time you call self.myVariable = nil, you're releasing it (assuming it had a value). But the second time, it's already nil, so there's nothing to release.
In general, actually releasing an object multiple times (or more accurately, having more releases than retains) is really bad and will almost certainly crash your app.
You're not actually releasing it twice. Given that the setter looks something like this:
- (void)setMyVariable:(NSString)value
{
[myVariable release];
myVariable = [value retain];
}
The first self.myVariable = nil will release the myVariable iVar, and will also set it to nil. The next self.myVariable = nil will do nothing, because [nil release] does nothing.
Actually overreleasing an object will (usually) cause a crash.
You might be confused about the difference between a variable and an object. A single variable can be used with a release an infinite number of times (say, if is nil, or it holds a completely different retained object before each release, etc. This is because a variable can hold no object, or different objects at different times.). In your example, the variable holds no object (nil) during your second release.
But releasing any one non-nil object just one time too many can be the cause of a crash.
With the new ARC (Automatic Reference Counting) in iOS 5 you shouldn't worry about this issue, since the compiler takes care of this.
Learn more about it here:
http://clang.llvm.org/docs/AutomaticReferenceCounting.html
However, if you can't / don't want to use ARC, here is my alternative answer:
By accessing your vars the way you are doing ( self.var = nil ), my guess is that these synthesized functions take care of not releasing a non-retained var, so you are safe to do so as many times you like (not very elegant though).
If, on the other hand, you would explicitly call release like this [var release] twice or more, you might run into pretty nasty problems.
Nothing will happen in your code. I assume you are using ARC (Automatic Reference Counting) so you are "releasing" it by setting its pointer to nil.
How it really works is, suppose you have a NSString object allocated in memory, you create it and you assign a pointer to it.
So now your pointer is pointing to that object, what arc does is: If an object no longer has a pointer pointing to it then it is automatically released. Assuming you had ONLY that "myvariable" pointer on that NSString then it will be released the moment you set it to nil.
If you set the myvariable to nil again then you are absolutely not doing anything to it since the object was already released before.
Note that this means that if you have ANOTHER variable also pointing to that NSString then the object WONT be released but myvariable wont be pointing to it anymore.
I forgot to mention, you can find an excellent explanation about how arc works in "iOS 5 by tutorials" by Ray Wenderlich.
PD: If you are using ARC u should change your
#property (nonatomic, retain) NSString *myVariable;
to
#property (nonatomic, strong) NSString *myVariable;

iphone - properties and instance variables

Suppose I have this code...
foo.h
#interface Foo : NSObject {
NSString *aString; // 1
}
#property (nonatomic, retain) NSString *aString;
foo.m
#synthesize aString = _aString;
....
- (void)dealloc {
[aString release];
[super dealloc];
}
My questions are:
do I really need to declare aString in "1"? (see code)
if I am synthesizing aString = _aString, I am already creating an instance
variable, right?
if I am retaining the property on foo.h (#property), why Xcode complains if I release aString in dealloc?
thanks.
You are mixing up the property and the backing variable. "aString" is the property, which you access via method call (e.g. [self aString]). "_aString" is the backing variable, which you access directly (e.g. _aString).
Taking your questions in order:
No. This is an unused variable because you told the compiler to use _aString as the variable. (You don't actually need to declare either one in the modern run-time.)
Yes, as indicated in my answer to the first question.
Because the compiler expects you to send a message to an object, and "aString" is undefined as written. Normally you would use [self aString] to access the object, but this is a special case: in -dealloc and in -initXYZ you don't use accessor methods because of potential side effects. Switch to [_aString release] and everything will work (unless you have ARC, in which case you don't release at all.
With your #synthesize, the instance variable (your "1") should be NSString* _aString.
The reason you use synthesize with a differently named variable is so that you always use self.aString to properly release the old object instead of accidentally overwriting the pointer by directly modifying aString.
Do you have ARC enabled? If so, that's why Xcode complains about releasing it.
To answer your questions in order:
No. There might some sort of "best-practice" reason that I'm missing, but #property will synthesize the instance variable as well.
When you declare aString = _aString, what that allows you to do is directly manipulate _aString without accessing the synthesized getter/setter (by calling _aString) or use the synthesized getter/setters (by calling self.aString).
You are likely releasing it somewhere else, someone else is over-releasing it, or you're using ARC. With NSStrings (and other simple objects that have deep copy method readily available), I find it best to use #property (copy), and _aString = [stringPassedToInit copy], so that you are the only one handling your string's retain count. If you're using ARC, you don't need to worry about retain/release in most instances.
No, you don't need to declare ivars any more (since iOS 3 I think). You can delete the entire { ... } part of your interface declaration and it won't make any difference.
It's complaining because your ivar is named _aString, not aString. You need to say
[_aString release]
instead.
Answers : -
do I really need to declare aString in "1"? (see code) - Now with iOS 4 onwards you won't need to declare.
if I am synthesizing aString = _aString, I am already creating an instance variable, right? - Yes
if I am retaining the property on foo.h (#property), why Xcode complains if I release aString in dealloc? - now you need to use this - self.aString = nil, this will take care.
My answers are:
NO
YES
Try [_string release] instead.

Require some understanding for Singleton Pattern

I am going to paste a code here and had a question regarding that which I wanted to understand merely, based on the logical way.
#interface MySingleton : NSObject {
NSString *enteredCode;
}
#property (nonatomic, retain) NSString *enteredCode;
#end
#synthesize enteredCode;
-(void) addInput:(NSString *) input
{
self.enteredCode = [self.enteredCode stringByAppendingString:input];
}
- (void)dealloc {
[enteredCode release];
}
#end
In my code, if I utilize "self.enteredCode = [self.enteredCode stringByAppendingString:input];"
everything works fine but "enteredCode = [self.enteredCode stringByAppendingString:input];" it gets exc_bad_access, and I am just wondering why this case be?
I am just trying to understand what difference really does it makes without having self there?
Thanks.
This is not to do with singletons. When you do self.enteredCode you are going through the property which is set to 'retain'. The stringByAppendingString method is a convenience method with returns an autoreleased object to you, meaning that it will be released at some point on the next run loop. You need to retain this value to stop it being released, which is fine when you assign it through the property as it is properly retained by you and you can use it as you like.
When you reference the variable directory (without the self.) you bypass this and as such you don't ever retain the value, the value is subsequently released and you reference bad memory and BOOOOOOOOM, bad access.
when you call self.enteredCode = XXX it will call [self setEnteredCode:XXX]. Since you are using a retain property this will release the old value of enteredCode, and retain the new value.
if you directly manipulate the enteredCode variable you will have memleaks and crashes because it will try to release something that is not retained later.
If I understand correctly, self.enteredCode works but enteredCode fails.
If that's the case then I believe it's because you're bypassing the property and setting the iVar directly. That means you're assigned an auto released object and bypassing the retain mechanism.
Consider using something like _enteredCode for your iVars do it's clearer in your code when you're bypassing properties.

Property does not seem to be used?

This is something that I came across in the Apple reference material - Sample Code when researching how to use NSTimer, I am not asking about NSTimer as thats a seperate question but I am curious about the use of the #property, the direct assignment to the iVar (i.e. not using the property setter) and the subsequent release.
#property (nonatomic, retain) NSTimer *updateTimer;
...
#synthesize updateTimer;
...
updateTimer = [NSTimer scheduledTimerWithTimeInterval:.01 target:self selector:#selector(updateCurrentTime) userInfo:p repeats:YES];
...
...
updateTimer = nil;
...
...
// Dealloc method
[updateTimer release];
My question is, does the property get used at all, it seems not? Also the release, does that work, where is the retain if the #property setter is not being used?
The retain is in the definition of the property. (i.e. where it says "(nonatomic, retain)" in brackets.)
If the property had been allocated, it would be retained "automatically" by the setter it at that time.
But just as you say the property itself is never used, so it is never allocated or retained.
The release you can see in the code appears to be simply wrong, just as you say. The ivar was never retained so a release would crash just as Bjorn pointed out.
(Note that they apparently set it to nil -- of course you can send any message at all to nil, but just as you say it's a really silly example. You can't release something you never retained.)
Exactly as you say, the example is a little weird. There was "no reason" to make a property: just as you say it was never used. Conversely, why did they release the ivar - which was never retained.
So in short your suspicions seem to be correct!
There are at least three horrible errors in that code!
You are right, the property is never used as there is no call like self.updateTimer = something or [self setUpdateTimer:something]. Sending the release message in -dealloc "works" because you reset updateTimer to nil. It is perfectly fine to send messages to nil, but nothing is going to happen. If you did not reset the variable to nil, the message would have been sent to a deallocated instance and cause an EXC_BAD_ACCESS exception.
If you use a dot, the property method gets called. Otherwise it is simple assignment. For instance, foo = bar would be assignment, whereas self.foo = bar would result in the property method getting called.
Try using self.updateTimer = ....

Releasing an ivar with the Copy property

If I have a class
#interface Foo {
NSString *temp;
}
#property(nonatomic, copy) NSString *temp;
#end
I understand that upon assignment, the old temp will get released and the new one will be assigned using temp = [newTemp copy]. And going by memory management rules, you are supposed to do [temp release] in the dealloc method of Foo, right?
What I don't understand is what happens if the setter was never used - you still have the [temp release] in the dealloc, so it's releasing something with a retain count of 0. Can someone clarify this for me?
There are two possibilities.
Since you never set it, it's nil. Sending release to nil is just fine. So no problem there.
Your init routine makes a default value for temp. Then it is a real object, and sending it release is also ok.
No problem all around! In neither case are you sending a message to an object with a retain count of 0.