Search code examples
objective-cpropertiesivar

Which one is initialized, property or its instance variable


Suppose I have a property called myPropertyName defined in my class MyClassName. Manual memory management is used throughout this post.

MyClassName.h

#import <UIKit/UIKit.h>
@interface MyClassName : NSObject {
    @private
        NSObject* myPropertyName;
    @public
}
@property (nonatomic, retain) NSObject* myPropertyName;
// Some methods prototypes are here
@end

MyClassName.m

#import "MyClassName.h"
@implementation MyClassName
@synthesize myPropertyName;
// Some methods are here
@end

I'm confused with usages such as the place of myPropertyName declaration, its difference between instance variable. For example, what is the difference among these three statement of initialization code, for example, in the customized -(void)init method for my class myClassName.

  1. self.myPropertyName = [[[NSObject alloc] init] autorelease];

    This one is calling myPropertyName setter, but I'm not sure what is the name of the instance variable being used in the setter, myPropertyName (since I've declared a @private field named myPropertyName) or _myPropertyName (people say that this one with underbar is the default)?

  2. myPropertyName = [[NSObject alloc] init];

    Does this initialize the instance variable of the myPropertyName property? If I don't have @synthesize myPropertyName = _myPropertyName;, would it be wrong since the default instance variable for the property is said to be _myPropertyName.

  3. _myPropertyName = [[NSObject alloc] init];

    Is _myPropertyName still declared as the instance variable for my property myPropertyName even if I use @synthesize myPropertyName; and @private NSObject* myPropertyName;?

In my understanding, a property is just a name (such as myPropertyName), there should be some instance variable encapsulated to be used in actual operations in the code, such as assigning values.


Solution

  • First off, I highly recommend reading Apple's documentation on properties, also linked by nhgrif. However, I understand docs can be a bit dense reading material (though Apple's, I find, are not so bad), so I'll give a brief overview of properties here.

    I like examples, so I'm going to rewrite your two classes in a bit more current form.

    MyClassName.h

    #import <UIKit/UIKit.h>
    @interface MyClassName : NSObject
    
    @property (nonatomic, strong) NSObject *myPropertyName;
    // method prototypes here
    @end
    

    MyClassName.m

    #import "MyClassName.h"
    @implementation MyClassName
    // some methods here
    @end
    

    The class MyClassName now has a property called myPropertyName of type NSObject *. The compiler will do a lot of work for you for "free" in this instance. Specifically, it will generate a backing variable, and also generate a setter and getter for myPropertyName. If I were to rewrite the two files, and pretend I'm the compiler, including that stuff, they would look like this:

    MyClassName.h

    #import <UIKit/UIKit.h>
    @interface MyClassName : NSObject {
        NSObject *_myPropertyName;
    }
    
    @property (nonatomic, strong) NSObject *myPropertyName;
    
    - (void)setMyPropertyName:(NSObject *)obj;
    - (NSObject *)myPropertyName;
    
    @end
    

    MyClassName.m

    #import "MyClassName.h"
    @implementation MyClassName
    
    - (void)setMyPropertyName:(NSObject *)obj
    {
        _myPropertyName = obj;
    }
    
    - (NSObject *)myPropertyName
    {
        return _myPropertyName;
    }
    
    @end
    

    Again, all of this is happening for "free": I'm just showing you what's happening under the hood. Now for your numbered questions.

    1. self.myPropertyName = [[[NSObject alloc] init] autorelease];

      First of all, you should probably be using Automatic Reference Counting, or ARC. If you are, you won't be allowed to call autorelease. Ignoring that part, this works fine. Excluding the autorelease, this is exactly equivalent to:

      [self setMyPropertyName:[[NSObject alloc] init]];

      Which, if you look at the second .m file I wrote out, above, will basically translate to:

      `_myPropertyName = [[NSObject alloc] init];

    2. myPropertyName = [[NSObject alloc] init];

      As written, this code will give a compiler error, since there is no variable called myPropertyName in this class. If you really want to access the instance variable underlying (or, "backing") the myPropertyName property, you can, by using its real name:

      _myPropertyName = [[NSObject alloc] init]; // note the underscore

      But most of the time, it's better to use the setter, as in point 1., since that allows for side effects, and for Key-Value Coding, and other good stuff.

    3. _myPropertyName = [[NSObject alloc] init];

      Oh. Well you got it. See point 2.

    You mentioned that:

    I'm confused with usages such as the place of myPropertyName declaration, its difference between instance variable. For example, what is the difference among these three statement of initialization code, for example, in the customized -(void)init method for my class myClassName.

    In case it hasn't been made clear, a property is something of an abstract concept; its data is stored in a normal instance variable, typically assigned by the compiler. Its access should usually be restricted to the setter and getter, with important exceptions. To keep this answer short, I won't go into more detail than that.

    One more thing: as nhgrif mentioned, you don't need to use the @synthesize keyword anymore. That is implicitly understood by the compiler now.

    If you're not sure about any of this, post a comment or, better yet, read the docs.