I'm trying to learn Objective C. I came across the following code which the compiler generates behind the scenes for #property(nonatomic, retain) NSString* myField
-(NSString*) myField
{
return myField_; //assuming myField_ is the name of the field.
}
-(void) setMyField:(NSString*) newValue
{
if(newValue != myField_)
{
[myField_ release];
myField_ = [newValue retain];
}
}
Now my question is; Why to call retain on newValue? Instead the following syntax should be used:
myField_ = newValue;
[myField_ retain];
Please advise why the above syntax is not used because as per my understanding, we want to retain the object pointed to by myField_ ?
They're the same (both are correct). You don't copy the object - retain returns the same pointer that was retained, so it's shorter and cleaner to write
ivar = [newObj retain];
than separately assigning and retaining the object.
Both syntaxes are correct. In the first case we also retain the object pointed by myField since we assign [newValue retain] to it.
Related
My purpose: making an API call to a server, and getting back from them is an array of data named dataArr and I want to store these data to another array for later need.
What I am doing so far is
myClass.h:
#propery ( nonatomic, retain ) NSArray *dataList;
myClass.m:
#implementation myClass
-(void)receivedData:(NSArray*) dataArr {
// ???
}
To fill in at line 3, I have two options, option A:
dataList = dataArr;
or option B:
[dataList release];
[dataArr retain];
dataList = dataArr;
I think option A is the right way to do it because dataList is declared as retain in the header file. Therefore, the setter will make sure to release a current array (dataList) and reain a received array (dataArr) as well
I just want to double check that I am on the right path.
Please correct me if I have just made a mistake in the middle. Thanks
Any comments are welcomed.
dataList = [dataArr];
this is not valid Objecitve-C. If you wanted to write
dataList = dataArr;
that's still a no-go, as you're acessing the instance variable directly, not through the property setter, that is, your array won't be retained and it will badly crash.
[dataList release];
[dataArr retain];
dataList = dataArr;
is wrong again. If dataList was the same as dataArr, and the reference of the object (self) was the last reference to it, then it would get deallocated, breaking the following retain message, and most likely crashing again.
If you have a property setter (which you have), simply write
self.dataList = dataArr;
this will retain the array correctly. By the way, the implementation of the setter is something like your last method, but it checks either for inequality:
- (void)setDataList:(NSArray *)dl
{
if (dataList != dl)
{
[dataList release];
dataList = [dl retain];
}
}
or pre-retains the object to be set:
- (void)setDataList:(NSArray *)dl
{
[dl retain];
[dataList release];
dataList = dl;
}
add #synthesize dataList; so the compiler can generate the default setter
then in line 4 add:
self.dataList = dataArr;
The default setter will take charge of releasing and retaining in a correct manner
I have a setter like this:
- (UIImagePickerController *) foto {
if (_foto == nil) {
_foto = [[UIImagePickerController alloc] init];
_foto.delegate = self;
}
return _foto;
}
it is declared like
#property (nonatomic, retain) UIImagePickerController *foto;
with
#synthesize foto = _foto;
on my dealloc I have
[_foto release];
At some point in my code I want to do this
self.foto = nil;
but something in my soul says the object assigned to self.foto previously will leak, because it was alloc on the setter... how do I make it right?
thanks.
Edit: No, that should be fine. As long as you don't assign something else to _foto before you release, it should work.
Yup. You create an object, then loose the pointer to it. If you throw an autorelease on the init line, that will fix it. You could also use ARC.
The init line doesn't actually do anything... You assign the pointer to an object you create, then assign it to something else.
I don't think there is a leak there. When you assign to self.foto like this:self.foto = nil;, it will release the former one automatically. If you assign it by this way: _foto = nil;, you need to release it manually before the assignment.
Yes that works, and will not leak. When you set the value of _foto, its retain count is 1 (because you called alloc). As long as you release it (which you've said you do) in dealloc, you should be fine, as the retain count will go back to 0. UNLESS your setter is ALSO written by you, and written improperly. It needs to explicitly release the old value, if it's not nil. Something like this:
- (void)setFoto:(UIImagePickerController*)foto {
if (_foto) {
[_foto release];
_foto = nil;
}
if (foto)
_foto = [foto retain];
}
Question #1
Will NSStringFromCGPoint() return an autorelease object or does the object needs to be released?
Question #2
When you have a property : #property (nonatomic, retain) NSString *someString;
And you set it like so: self.someString = [[[NSString alloc] initWithString:#"Something"] autorelease];
Is this:
[someString release];
someString = nil;
equal to
self.someString = nil;
I haven't checked that one specifically, but by convention those sorts of functions return autoreleased objects. You might be able to test this yourself by setting up a minimal, non-ARC project and calling -retainCount on what you get out of the function, but I'm not sure. (And in general, retainCount isn't something you want to use.)
Yes. The synthesized setter looks something like:
- (void)setSomeString:(NSString *)string
{
if (string != someString) {
[someString release];
}
someString = [string retain];
}
So, whether you call it explicitly or using the dot notation, the old value gets released (and the underlying ivar gets set to nil or whatever you pass in).
Also, I'm not sure if you were just doing it for a random example, but you don't have to wrap a string literal in memory management code to pass it to the property accessor. (That is, self.someString = #"Something" is fine.)
Does the call include the term "new", "alloc", "copy", or "create"? If not, you're getting back an object that you do not own (you may assume it is either autoreleased or that the reference is owned elsewhere).
- (void)setSomeInstance:(SomeClass *)aSomeInstanceValue
{
if (someInstance == aSomeInstanceValue)
{
return;
}
SomeClass *oldValue = someInstance;
someInstance = [aSomeInstanceValue retain];
[oldValue release];
}
ok, so setter should look like. I understand first 3 lines - prevent before situation when new object is the same as the old one.
But what about this line:
SomeClass *oldValue = someInstance;
Why system have to keep address of old object. Why can't it be simply
[someinstance release];
someinstance = [aSomeInstanceValue retain];
Actually - no reason.
It's usually just a choice.
There are three idioms for writing accessors.
Autorelease:
- (void)setFoo:(id)newFoo {
[foo autorelease];
foo = [newFoo retain];
}
Less code to write, but I think autorelease in this case is being lazy.
Retain then release
- (void)setFoo:(id)newFoo {
[newFoo retain];
[foo release];
foo = newFoo;
}
Check first
- (void)setFoo:(id)newFoo {
if ([foo isEqual:newFoo]) {
return;
}
[foo release];
foo = [newFoo retain];
}
The only difference between the last two is that the second checks to see if the new value is different to the current value before trying to set the property. At the cost of an extra if statement. So - if the new value is likely to be the same as the old value, using this construction gives better performance.
Generally, and if you're not using properties for some strange reason, use retain then release, and then if profiling shows that there's a bottleneck - use the check first method.
I would suggest the default retain setter works something like this:
- (void) setFoo:(id) foo {
if ( foo == _foo) return;
[_foo release];
_foo = [foo retain];
}
if you don't check if the old and the new foo are the same, you might end up with a reference to a deallocated object if you for some reason write something like this:
myObject.foo = myObject.foo;
Because the same object would first be released, and then retained. If the myObject is the sole owner, the object would be deallocated after the first release, leaving you with a dangling pointer.
The default retain setter works like that :
- (void)setFoo:(Foo *)aFood
{
if (_foo != nil)
[_foo release];
if (aFood != nil)
_foo = [aFood retain];
}
I'm going through all of my documentation regarding memory management and I'm a bit confused about something.
When you use #property, it creates getters/setters for the object:
.h:
#property (retain, nonatomic) NSString *myString
.m:
#synthesize myString
I understand that, but where I get confused is the use of self. I see different syntax in different blogs and books. I've seen:
myString = [NSString alloc] initWithString:#"Hi there"];
or
self.myString = [NSString alloc] initWithString:#"Hi there"];
Then in dealloc I see:
self.myString = nil;
or
[myString release];
or
self.myString = nil;
[myString release];
On this site, someone stated that using self adds another increment to the retain count? Is that true, I haven't seen that anywhere.
Do the automatic getters/setters that are provided autorelease?
Which is the correct way of doing all of this?
Thanks!
If you are not using the dot syntax you are not using any setter or getter.
The next thing is, it depends on how the property has been declared.
Let's assume something like this:
#property (nonatomic, retain) Article *article;
...
#synthesize article;
Assigning something to article with
self.article = [[Article alloc] init];
will overretain the instance given back by alloc/init and cause a leak. This is because the setter of article will retain it and will release any previous instance for you.
So you could rewrite it as:
self.article = [[[Article alloc] init] autorelease];
Doing this
article = [[Article alloc] init];
is also ok, but could involve a leak as article may hold a reference to an instance already. So freeing the value beforehand would be needed:
[article release];
article = [[Article alloc] init];
Freeing memory could be done with
[article release];
or with
self.article = nil;
The first one does access the field directly, no setters/getters involved. The second one sets nil to the field by using a setter. Which will release the current instance, if there is one before setting it to nil.
This construct
self.myString = nil;
[myString release];
is just too much, it actually sends release to nil, which is harmless but also needless.
You just have to mentally map hat using the dot syntax is using accessor methods:
self.article = newArticle
// is
[self setArticle:newArticle];
and
myArticle = self.article;
// is
myArticle = [self article];
Some suggestions on reading, all official documents by Apple:
The Objective-C Programming Language
Dot Syntax
Declared Properties
Memory Management Programming Guide
Object Ownership and Disposal
Using Accessor Methods
When you create a retain setter, you're creating something like this:
- (void)setString:(NSString *)someString {
if (someString != string) {
[string release];
[someString retain];
string = someString;
}
}
If you don't use the setter, the new value is not getting that retain—you don't "own" that string, and because it's all references, if the original string is released, you might be facing a null reference, which will lead to an EXC_BAD_ACCESS. Using the setter ensures that your class now has a copy of that value—so yes, it does increment the retain count of the new value. (Note that using the getter is a convention of OOP—that outsiders should not be able to directly touch the ivar. Also in your getter you can modify the value, maybe returning an NSArray when your ivar is an NSMutableArray, for example).
You shouldn't autorelease in a setter—Apple has used it in their sample code, but a thing to keep in mind is that setters are called a lot—millions of times, potentially. All of those objects are going into the same autorelease pool, so unless you create your own and/or regularly flush it, you'll have a ton of elements in your pool, all unneeded but still taking up RAM. Much better to simply release.
As for dealloc, trace back through that setter. If you send a release directly, it's obvious—you release that object. But if you write self.string = nil;, what you're doing is this:
The nil value is not the same, so you enter the if block
You release the old value—what you want to do
You retain nil: messages to nil do nothing, and you don't crash
You set nil, which doesn't take up any memory, to the string, which is now effectively empty
As a matter of convention, I use release in my dealloc method, because release seems more final, and dealloc is the final method call your object will receive. I use self.string = nil; in viewDidUnload and the memory warning methods.
Hope this helps!
In addition to Nick's answer - synthesized getters/setters don't provide autorelease (btw, what's the big idea of doing this? Well, you can use getter as a factory, but it's not a common way in Objective C).
Then in dealloc I see:
self.myString = nil;
or
[myString release];
or
self.myString = nil; [myString
release];
In dealloc it doesn't really matter which form of release you're using. But the good way is to nil your fields when releasing them :) I prefer to use self.myString = nil; in dealloc