PDA

View Full Version : setter, @synthesize etc...




MACloop
Jul 7, 2010, 05:06 AM
Hi,
I have read and thought some about setters and getters lately and maybe someone can clear this out for me.

I am using the following syntax:

.h
NSMutableArray *list;
@property(nonatomic, retain)NSMutableArray *list;

.m

self.list = someList;


What about if I for instance would like to change the array later on in my code. I have noticed that both these following examples are actually working. Which one is correct and why? (I have been using the first one because I thought the self. makes the object retain +1...)
1) [list removeAllObjects];
2) [self.list removeAllObjects];

the same thing appears by getting values aswell, like:
1) someList = list;
2) somelist = self.list;

MACloop



NickFalk
Jul 7, 2010, 05:23 AM
You can't actually change an NSArray after you've initiated it. That's what the NSMutableArray class is for...

robbieduncan
Jul 7, 2010, 05:33 AM
You can't actually change an NSArray after you've initiated it. That's what the NSMutableArray class is for...

Given that he is using a NSMutableArray this comment is not particularly helpful!

Personally I would say you should use

[self.list removeAllObjects];
somelist = self.list;


Whilst it may not seem like there is any reason to if you don't do this then you may have weird behaviour if there is a subclass involved. The subclass could override the getter to do some work to generate/calculate the ivar value on demand instead of storing it in the property variable used by the superclass. All superclass methods should work correctly with the subclass but if you shortcut the access they would not.

In general good O-O programming discipline says to always use the setter/getter methods (and therefore dot syntax) when accessing ivars. This includes access within the class itself.

NickFalk
Jul 7, 2010, 05:46 AM
Given that he is using a NSMutableArray this comment is not particularly helpful!

@myself:

http://images.sodahead.com/profiles/0/0/1/8/3/6/6/3/5/double-face-palm-1268785205.jpeg

Sorry, I'll give reading-the-actual-post a try next time...

MACloop
Jul 7, 2010, 06:09 AM
Given that he is using a NSMutableArray this comment is not particularly helpful!

actually it is she ;-)

Whilst it may not seem like there is any reason to if you don't do this then you may have weird behaviour if there is a subclass involved. The subclass could override the getter to do some work to generate/calculate the ivar value on demand instead of storing it in the property variable used by the superclass. All superclass methods should work correctly with the subclass but if you shortcut the access they would not.
Ok that makes sense!

MACloop
Jul 7, 2010, 06:11 AM
@myself:

http://images.sodahead.com/profiles/0/0/1/8/3/6/6/3/5/double-face-palm-1268785205.jpeg

Sorry, I'll give reading-the-actual-post a try next time...

:D
By the way, this was just a "dummy" example to concrete explain my issue...

robbieduncan
Jul 7, 2010, 06:27 AM
actually it is she ;-)

Sorry! MACloop doesn't really give much away and typing he/she all the time is a bit long winded. I will remember for the future.

MACloop
Jul 7, 2010, 06:28 AM
Sorry! MACloop doesn't really give much away and typing he/she all the time is a bit long winded. I will remember for the future.

No problem :-)

seepel
Jul 7, 2010, 05:37 PM
I like to do things like this, just to be really clear about what is going on.


NSMutableArray *list_;
@property(nonatomic, retain)NSMutableArray *list;
@synthesize list = list_;

MACloop
Jul 8, 2010, 02:07 AM
I like to do things like this, just to be really clear about what is going on.


NSMutableArray *list_;
@property(nonatomic, retain)NSMutableArray *list;
@synthesize list = list_;


OK, that is interesting! I have seen it in tutorials and other code snippets on the web. So futher in your code, are you using list...or self.list when setting and getting values to this variable? And how do you do in viewDidUnload and dealloc?

MACloop

seepel
Jul 8, 2010, 03:46 AM
OK, that is interesting! I have seen it in tutorials and other code snippets on the web. So futher in your code, are you using list...or self.list when setting and getting values to this variable? And how do you do in viewDidUnload and dealloc?

MACloop

In general the only place you would see list_ in my code is in the header where I declare it

NSMutable *list_;
[code]

But occasionally I like to make a read only property when I know that other objects will never have to set the property but only retrieve it. So I would do this.

[code]
NSArray *list_;
@property (nonatomic, readonly) NSArray *list;

- (NSArray*)list {
if(list_ == nil) {
list_ = [NSArray arrayWithObjects:@"one",@"two",nil];
}
return list_
}


The advantage of this is that if I receive a memory warning I can get rid of the property easily enough by setting it to nil, and I know that it will be there when I need it again, because as soon as I use it it will be re-instantiated. I don't know if it is the right and standard way to do lazy loading, but it seems to work well enough for me so far.

So basically the only time I would ever refer to the ivar (list_) directly would be in the property's setter or getter. If you refer to the property (self.list) inside the setter or getter, there is a good chance you will hit an infinite loop, right?

PhoneyDeveloper
Jul 8, 2010, 07:54 AM
You're missing a retain in your list method.

How do you set the property to nil?

dejo
Jul 8, 2010, 09:12 AM
In general the only place you would see list_ in my code is in the header where I declare it
[code]
NSMutable *list_;
[code]

It's pretty normal to also see it (list_, in this case) in the dealloc method, as in:
[_list release]

seepel
Jul 8, 2010, 12:34 PM
You're missing a retain in your list method.

How do you set the property to nil?

Your absolutely right about the retain, and I guess by property I ment ivar. So I would release and nil it? Does that make sense?

It's pretty normal to also see it (list_, in this case) in the dealloc method, as in:
[_list release]

Also true!

iSee
Jul 8, 2010, 05:21 PM
One point on this:

...(I have been using the first one because I thought the self. makes the object retain +1...)...

When you @synthesize a retained property (like in the example you listed):
- the setter will retain +1 the object you pass in (and release the previous value.
- the getter will NOT retain +1 the value it returns. The caller can retain it for itself if it wants to keep it around. (Well, actually it *could* return an autoreleased object, but the calling code should not count on that or care either way.)

so:
self.list = someList; // setter called; value is stored in list and retained +1
[self.list removeAllObjects]; // getter called; object is not retained +1


Also, I agree with others who say to always use the setters/getters. (e.g., use self.list, not list) -- the only exception to this is when you implement your own setters or getter rather than @synthesize (obviously if the setter calls the setter, you've got an infinite loop on your hands).

You don't always have to, of course. But you'll save yourself occasional mistakes if you do.

I even use setters in [dealloc] to release retained properties. e.g.,
-(void)dealloc
{
self.list = nil;
[super dealloc];
}

MACloop
Jul 9, 2010, 01:59 AM
One point on this:



When you @synthesize a retained property (like in the example you listed):
- the setter will retain +1 the object you pass in (and release the previous value.
- the getter will NOT retain +1 the value it returns. The caller can retain it for itself if it wants to keep it around. (Well, actually it *could* return an autoreleased object, but the calling code should not count on that or care either way.)

so:
self.list = someList; // setter called; value is stored in list and retained +1
[self.list removeAllObjects]; // getter called; object is not retained +1


Also, I agree with others who say to always use the setters/getters. (e.g., use self.list, not list) -- the only exception to this is when you implement your own setters or getter rather than @synthesize (obviously if the setter calls the setter, you've got an infinite loop on your hands).

You don't always have to, of course. But you'll save yourself occasional mistakes if you do.

I even use setters in [dealloc] to release retained properties. e.g.,
-(void)dealloc
{
self.list = nil;
[super dealloc];
}

Thanks for the answer! I have read though that it might be against Apple's recommendations to use setters in dealloc. The problem might be that you (with calling the setter) could use a setter in an already partially deallocated object. Therefor I have been using [list release]; in the dealloc but this is perhaps not neccesary?

PhoneyDeveloper
Jul 9, 2010, 09:12 AM
in the dealloc but this is perhaps not necessary?

It is recommended that you not use the setter in dealloc. It's more of an issue if you are writing library code or classes that are intended to be subclassed.

There was a bug of this kind in 2.x where UIViewController set its view property in its dealloc method using the setter. This would call any overridden setView methods in UIViewController subclasses after the subclass had called super dealloc. Overriding setView was part of the recommended way to clean up outlets at that time, before viewDidUnload was available.

There is no advantage at all to using the setter in dealloc.

iSee
Jul 9, 2010, 11:19 AM
Yeah, that's a good point about using setters in dealloc and subclasses.

Sorry for the bad advice. I take back what I said about using setters in dealloc. :)