I have a question. In my .h:
NSString *string;
#property(nonatomic, retain)NSString *string;
In my .m:
string=[NSString stringWithFormat:#"%#", otherStringWithValue];
Ok, "stringWithFormat" is an autorelease method. Need I release "string" in dealloc??
only self.string = .... will retain your stringWithFormat.
so you dont need to release it. but beware that you string will be released and your app get crashed when your try later to access it. if you want to keep your string so make
self.string = .....
and release it on dealloc
If the string that you are declaring is a part of the property in the above code then yes, even though you have to initialize it. The ownership is still yours to take care off.
The attributes are applied to property only.
Properties can not be accessed directly. It can be accessed via "." only.
So, when you write,
string=[NSString stringWithFormat:#"%#", otherStringWithValue];
you are accessing variable. So, no retain will be called on it. Also, stringWithFormat will return autoreleased object. So, no need to release it in dealloc. However, you can not access this variable beyond the scope because you do not know, when will it get released.
If you write,
self.string=[NSString stringWithFormat:#"%#", otherStringWithValue];
you are accessing property and its value will be retained. So, you will have to release it in the dealloc method.
Just Use ARC.
Seriously. It means you no longer need to worry about retain/release (though you do have to worry about reference cycles, which you would have had to worry about anyway).
If you are not using ARC, then the code above crashes becaus you are not taking "ownership" of the string (by retaining it). Either retain it correctly:
[string release];
string=[[NSString stringWithFormat:#"%#", otherStringWithValue] retain];
Or use the setter, which (if it is automatically generated) will retain it correctly:
self.string=[NSString stringWithFormat:#"%#", otherStringWithValue];
In -dealloc, you then have to release the ivar, or you can just use the setter (which will release it automatically for you):
self.string = nil;
Before ARC, my rule of thumb was to almost always use the property syntax, since it just does the right thing.
instead of this:
string=[NSString stringWithFormat:#"%#", otherStringWithValue];
do this:
self.string=[NSString stringWithFormat:#"%#", otherStringWithValue];
Now, you need to release the string in your dealloc. Though, the +stringWithFormat returns autorelased object but you've declared a retained property so, you're responsible for releasing it.
This code will introduce memory leak because stringWithFormat returns autorelease object and you have retain string, so when you assign string the value of stringWithFormat it will provide new autorelease object.But whatever memory you have retained for string is still there because its retain count is still 1, so it will not get released.but if you tried to release string it will crash because after assignment it will contain autorelease object.
Related
I was having an issue with my UPDATE statement as I was telling here: Update issue with sqliteManager
I found out that initWithFormat WORKS
NSString *sqlStr = [[NSString alloc] initWithFormat:#"UPDATE User SET Name = :Name WHERE Id = :Id"];
BUT not stringWithFormat:
NSString* sqlStr = [NSString stringWithFormat:#"UPDATE User SET Name = :Name WHERE Id = :Id"];
Why is this as such? I would like to understand the logic/reasoning behind..
I am guessing that it has to do with the memory management of the string, it might not have been sufficiently retained so it is getting cleaned up before for it is getting used. The difference between the two methods are defined here
I have just found something interesting from this thread: How to refresh TableView Cell data during an NSTimer loop
This, I believe, is the reasoning behind..
I quote what "petergb" said:
[NSString stringWithFormat:...] returns an autoreleased object. Autoreleased objects get released after control returns from the program's code to the apple-supplied run-loop code. They are more or less a convenience so we don't have to release all the little objects that we use once or twice here and there. (For example, imagine how tedious it would be if you had to release every string you created with the #"" syntax...)
We can tell stringWithFormat: returns an autoreleased object because, by convention, methods who's names don't start with alloc or copy always return auto-released objects. Methods like this are said to "vend" an object. We can use these objects in the immediate future, but we don't "own" it (i.e. we can't count on it being there after we return control to the system.) If we want to take ownership of a vended object, we have to call [object retain] on it, and then it will be there until we explicitly call [object release] or [object autorelease], and if we don't call release or autorelease on it before we lose our reference to it by changing the variable to something else, we will leak it.
Contrast with [[NSString alloc] initWithFormat:. This method "creates" an object. We own it. Again, it will be there until we explicitly call [object release].
I have a property that has (nonatomic, assign) as attributes.
In a method, I then am retaining that variable then releasing it a line after.
Static analyzer is giving warning that incorrect decrement of the reference count of object....
Can I not do this
#property (nonatomic, assign) Class *iVar;
[self.iVar retain];
[self.iVar removeFromSuperview];
[self insertSubview:self.iVar atIndex:self.iVar.index];
[self.iVar release];
Since the retain and release both happen in the same method, you might want to copy the property to a local variable and then work with that:
UIView *someView = self.interestingView;
[someView retain];
//...do some stuff...
[someView release];
That at least provides some protection in case the "some stuff" part happens to modify self.interestingView. And it'll probably satisfy the static analyzer, too.
In general, I would avoid retaining/releasing variables that back properties outside the accessors for those properties, except for a few well defined situations such as -dealloc. Similarly, avoid directly retaining/releasing the result of a property access, as in [self.foo retain]. If that property is changed before you get to the release, you end up with both a leak and, later, an over-release.
The trouble is that you're not working with a variable; you're working with the result of a property accessor. Each time you access the property, the static analyzer applies the normal memory management rules for an object returned from a method — namely, you shouldn't be releasing it. If you change it to use an actual local or instance variable, the warning will go away.
I just tested a similar example,
You will appease the static analyzer by not using property notation
[iVar retain];
[self.iVar removeFromSuperview];
[self insertSubview:self.iVar atIndex:self.iVar.index];
[iVar release];
Or you could use a temporary variable.
In my app I have a NSError that I declare locally:
NSError *error;
Do I release it in dealloc method or do I need to release it in the method I declare it?
Please read the Cocoa Memory Management Guide, memory management is something you should understand perfectly. (And it’s not hard.) If you declare a variable in a method, you don’t have a pointer to it in dealloc, therefore you can’t release it there – you can only release it before it goes out of scope. Another question is if you should release it at all. That depends on whether it is a stack-based, autoreleased or retained variable:
float foo[] = {1, 2, 3}; // stack-based, no releasing necessary
NSString *foo = [NSString stringWithFormat:…]; // autoreleased, you must not release it
NSString *foo = [[NSString alloc] initWith…]; // retained, you must release it
You need to release it locally -- assuming you create it by alloc/new/copy or else retain it. (If you just get it from somewhere else without allocating or retaining, then it doesn't belong to you and you shouldn't release at all.)
Otherwise, once it goes out of local scope you have no access to the pointer and the object will leak.
You need to release it locally. Because in dealloc method we release class variables or class data members and those variables that are used through out the implementation file (like extern variables).
I have a question about a retain and a NSString, if I have a method who a return a NSString, and I put the return NSString in a nsstring variable, I must do a retain or not?
NSString *myString = #"";
myString = [self methodWhoReturnString]; // I must do this?
myString = [[self methodWhoReturnString]retain]; // Or I must do this?
The Apple Developer Documentation on Memory Management explains the scenarios where you retain/release objects.
Simply put, if you want the string to stick around, you need to retain it until you're finished with it. If that is just the scope of the current function, you can get away without retaining it as if the string is already autorelease'd (likely) it won't get released until your function finishes and the current AutoReleasePool is purged.
Bear in mind that an NSString * could actually be pointing to an NSMutableString *. If it matters to you if the string is changed by some other function without you realizing, be sure to copy it: NSString * myCopyOfString = [mystring copy];
If the string is set to autorelease, which it most likely is, then yes you will need to retain it somehow. I would suggest doing this though:
myString = [[self methodWhoReturnString] copy];
this ensures you have retained the data in the string not just a reference to a string that might still be controlled elsewhere. Be sure you release your copy later!
Usually, methodWhoReturnString would return an autoreleased string, which means you should retain it if you want to keep it around.
So, if methodWhoReturnString is your method, I believe that to keep with convention you should return [stringToReturn autorelease]; from that method, and then retain it if you want to keep it.
You use retain if you're going to be using myString at a later point in time (i.e. after the current method has returned) to prevent it being autoreleased.
You don't need to use retain if it's just a temporary variable used within the current method, since in that case you do want it to be autoreleased.
One special case is properties. If you call self.blah = foo, you don't need to retain foo, since the setBlah: method should do it for you.
(there's a whole load of other complexities and edge cases, but this is a good rule of thumb to get you started on understanding what to do)
Given the code you provided, you shouldn't call -retain. In your example, the return value of a method that returns an instance of NSString is assigned to myString, an automatic local variable. If the assignment had been made to an instance variable or a static variable, you would want to call either retain or copy to guarantee that the reference remains valid beyond the end of the local scope.
In this case though, the reference to the NSString instance is stored in a variable that will be destroyed automatically at the end of the local scope, so your code needn't concern itself with the object's lifetime.
Any method that has alloc, new or copy in it automatically retains and infers that you have ownership of the object. All others shouldn't. It would be helpful if you had more context though. If we are in a contained method where this string is used briefly, then you probably don't need to retain. If it is going to be used for a while, you might want to use the #synthesize syntax to make it a property of the class you are in. When you use #property and #synthesize and call something like self.myProperty = something it will automatically retain.
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.