views:

101

answers:

3

I have a few basic questions regarding the syntax and usage of properties in Objective C and would appreciate it if someone could answer them please.

Assume the following declaration in the header:

@interface TestObject : NSObject {

    NSArray *myArray;
}

@property (nonatomic, retain) NSArray *myArray;

In the implementation, can I?:

  1. Use myArray and self.myArray interchangeably for setting and getting purposes?
  2. Is self.myArray = nil equivalent to [myArray release]? If so, Is there ever a reason to use self.myArray = nil rather than [myArray release]?

Thanks!

A: 

To setup setters/getters you'd have to implement those in main as:

+ (NSArray*) myArray {
return myArray;
}

+ (void) setMyArray:(NSArray*)input{
myArray = input;
}
Scott
-1 setter/getter methods are instance methods, not class methods.
swegi
This is also not correct. Your methods (besides being class methods and not instance methods) are doing simple pointer assignation, as if the property were declared as `assign`. It isn't. It's declared as `retain`.
Dave DeLong
+4  A: 

Both existing answers are wrong.

@synthesize generates setters and getters that look like this:

- (void)setMyArray:(NSArray*)array {
    if( myArray != array ) {
        [myArray release];
        myArray = [array retain];
    }
}

- (NSArray*)myArray {
    return myArray;
}

(Note, they aren't exactly like this, and differ if you specify copy, or other attributes, but that's the basic formula). Now we can see that self.myArray = nil; WILL release the old array. self.myArray and myArray aren't interchangeable for setting purposes. Moreover, self.myArray = nil; will continue to work in a garbage collected world.

As Dave Delong points out, self.myArray = nil will notify anyone observing myArray of the changed value, which could be a problem if you do this in your dealloc method. To avoid this case your dealloc would look something like:

- (void)dealloc {
    [myArray release]; myArray = nil;
    [super dealloc];
}

(note myArray = nil; is a stylistic choice here.)

Steven Canfield
as I've said in other comments, `self.myArray = nil;` can have bad side effects if others are observing the `myArray` property. You don't want to fire off observation notifications while your object is deallocating, because then the observers might try to access a partially deallocated object. That isn't a Good Idea.
Dave DeLong
+1 for being absolutely correct otherwise. :)
Dave DeLong
Dave DeLong: An object that is deallocating shouldn't have any observers. If it does, that itself is a bug in your program.
Peter Hosey
+5  A: 
  1. myArray and self.myArray are actually different. myArray is accessing the variable directly, whereas self.myArray (which is equivalent to [self myArray]) is calling an accessor method. Most people agree that you should use self.myArray (or [self myArray]) all the time, and never use myArray directly. This is because the accessor might have side effects; for example, KVO won't work if you set your variable directly, and memory management won't be handled for you.

  2. Your property is declared with retain, so self.myArray = anArray (which is the same as [self setMyArray:anArray]) does the following:

    1. Retain anArray, which will soon be the new myArray.
    2. Release the old myArray, which will soon no longer be myArray.
    3. Change the pointer myArray so it now points to anArray.

Therefore, when you do self.myArray = nil, one of the steps (#2) is indeed release the old array. (And since the new one is nil, we don't have to worry about its memory management, even though we retained it.) So yes, self.myArray = nil is a valid way of releasing myArray.

HOWEVER, if you're talking about releasing myArray in dealloc, it's generally a good idea to use [myArray release], because calling self.myArray = nil will have side effects if any other objects are observing myArray through KVO. So while it does follow memory management standards, it's not a good idea to write your dealloc method using self.myArray = nil.

andyvn22
Thanks, but in response to your answers above:1. What is the difference between the 2? Does it relate to KVC and KVO?2. Thanks, but is there ever an occasion to use self.myArray = nil rather than [myArray release];
Run Loop
It's because using the accessor may have desirable side effects, including (but not limited to) KVO and memory management. Say you've got a `retain`-ed array already set in `myArray`. Then setting `myArray = newArray` leaks the old one, whereas calling the accessor (`self.myArray = newArray`) releases the old one and retains the new one for you.
andyvn22
@JK feel free to use `self.myArray = nil;` anywhere except your `dealloc` method.
Dave DeLong
To be totally pedantic ;), step 2.2 only releases the old myArray if it's not the same as the new myArray.
Frank Schmitt
@Dave Thanks. My preference is actually to use [myArray dealloc]. I had just wondered if I ever needed to use the self.myArray = nil syntax, which I now understand is useful for KVO, but should be avoided in dealloc.
Run Loop
@JK ***NEVER INVOKE DEALLOC YOURSELF*** (unless it's `[super dealloc]` inside your `dealloc` method). That's what `retain` and `release` are for.
Dave DeLong
(sorry if that comes across as harsh, but you're asking for a world of hurt if you ever invoke `dealloc` yourself)
Dave DeLong
Sorry, I meant to type release. It's late :) Thanks anyhow.
Run Loop
andyvn22: I agree that you shouldn't send yourself accessor messages from `dealloc` because the accessor methods themselves may have side effects, but if you have anything still observing properties of an object when it hits `dealloc`, that is a bug.
Peter Hosey