سؤال

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.

هل كانت مفيدة؟

المحلول

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.

نصائح أخرى

Let's take this example:

@property NSString *fullName;

If in the implementation, we override the setters and getters, and in these setters and getters, we don't use an instance variable fullName, it is never created. For example:

- (NSString *)fullName
{
    return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName];
}

- (void)setFullName:(NSString *)fullName
{
    //logic to split fullName into two strings
    //self.firstName = etc
    //self.lastName = etc.
}

In this example, there is no instance variable for fullName created.

This is according to Apple's Official Documentation

If, however, you don't override both the setter and getter, an instance variable is created.

As a sidenote, you can declare a property readonly, and then simply overriding the getter (without using the variable) will prevent an ivar being created. Likewise, you can declare a property writeonly and just override the setter.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top