初始化哪一个,属性或其实例变量

时间:2013-10-29 01:41:32

标签: objective-c properties ivar

假设我的班级myPropertyName中定义了一个名为MyClassName的媒体资源。本文中使用了手动内存管理。

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

我对诸如myPropertyName声明的位置,它与实例变量之间的区别等用法感到困惑。例如,这三个初始化代码语句之间的区别是什么,例如,在我的类-(void)init的自定义myClassName方法中。

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

    这个是调用myPropertyName setter,但是我不确定setter中使用的实例变量的名称是什么,myPropertyName(因为我已经声明了一个名为@private的字段myPropertyName)或_myPropertyName(有人说这个带有下划线的是默认设置)?

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

    这会初始化myPropertyName属性的实例变量吗?如果我没有@synthesize myPropertyName = _myPropertyName;,那么它是错的,因为该属性的默认实例变量被称为_myPropertyName

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

    即使我使用_myPropertyNamemyPropertyName@synthesize myPropertyName;仍被声明为我的媒体资源@private NSObject* myPropertyName;的实例变量吗?

  4. 根据我的理解,属性只是一个名称(例如myPropertyName),应该有一些封装的实例变量用于代码中的实际操作,例如赋值。

2 个答案:

答案 0 :(得分:2)

首先,我强烈推荐阅读由{nhgrif链接的Apple's documentation on properties。但是,我理解文档可能是一个有点密集的阅读材料(虽然Apple发现,并不是那么糟糕),所以我将在这里简要介绍一下属性。

我喜欢这样的例子,所以我要用更新的形式重写你的两个类。

<强> 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

班级MyClassName现在有一个名为myPropertyName的{​​{1}}类型的属性。编译器将为你做很多工作&#34; free&#34;在这种情况下。具体来说,它将生成一个支持变量,并为NSObject *生成一个setter和getter。如果我要重写这两个文件,假装我编译器,包括那些东西,它们看起来像这样:

<强> MyClassName.h

myPropertyName

<强> MyClassName.m

#import <UIKit/UIKit.h>
@interface MyClassName : NSObject {
    NSObject *_myPropertyName;
}

@property (nonatomic, strong) NSObject *myPropertyName;

- (void)setMyPropertyName:(NSObject *)obj;
- (NSObject *)myPropertyName;

@end

同样,所有这一切都发生在&#34;免费&#34;:我只是告诉你幕后发生了什么。现在为你编号的问题。

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

    首先,您可能应该使用自动引用计数或ARC。如果是,您将无法致电self.myPropertyName = [[[NSObject alloc] init] autorelease];。忽略那部分,这很好。排除autorelease,这完全等同于:

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

    如果你看一下我上面写的第二个autorelease文件,基本上会转换为:

    `_myPropertyName = [[NSObject alloc] init];

  2. .m

    如上所述,此代码将给出编译器错误,因为此类中没有名为myPropertyName = [[NSObject alloc] init];的变量。如果您真的想要访问基础(或者&#34;支持&#34;)myPropertyName属性的实例变量,您可以使用其真实姓名:

    myPropertyName

    但大多数情况下,使用setter会更好,如第1点所示,因为它允许副作用,键值编码和其他好东西。

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

    喔。嗯,你明白了。见第2点。

  4. 你提到过:

      

    我对诸如_myPropertyName = [[NSObject alloc] init];声明的位置,它在实例变量之间的区别等用法感到困惑。例如,这三个初始化代码语句之间的区别是什么,例如,在我的类myPropertyName的自定义-(void)init方法中。

    如果没有明确表示,财产是一种抽象的概念;其数据存储在通常由编译器分配的普通实例变量中。它的访问通常应限于setter和getter,但有一些重要的例外。为了简短地回答这个问题,我不会详细介绍。

    还有一件事:正如nhgrif所提到的,您不再需要使用myClassName关键字了。现在编译器已经隐含地理解了这一点。

    如果您对此不确定,请发表评论,或者更好的是阅读docs

答案 1 :(得分:1)

我们来看这个例子:

@property NSString *fullName;

如果在实现中,我们覆盖了setter和getter,并且在这些setter和getter中,我们不使用实例变量fullName,它永远不会被创建。例如:

- (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.
}

在此示例中,没有创建fullName的实例变量。

根据Apple's Official Documentation

但是,如果不覆盖setter和getter,则会创建一个实例变量。

作为旁注,您可以声明属性readonly,然后简单地覆盖getter(不使用变量)将阻止创建ivar。同样,您可以声明属性writeonly,然后覆盖setter