0

假设我在我的类中有一个名为myPropertyNamedefined的属性MyClassName。这篇文章中使用了手动内存管理。

我的类名.h

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

我的类名.m

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

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

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

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

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

    myPropertyName这会初始化属性的实例变量吗?如果我没有@synthesize myPropertyName = _myPropertyName;,那会不会是错误的,因为据说该属性的默认实例变量是_myPropertyName.

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

    即使我使用and仍被_myPropertyName声明为我的属性的实例变量?myPropertyName@synthesize myPropertyName;@private NSObject* myPropertyName;

在我的理解中,属性只是一个名字(比如myPropertyName),应该有一些实例变量被封装在代码中的实际操作中使用,比如赋值。

4

2 回答 2

2

首先,我强烈建议阅读Apple 的 properties 文档,也由 nhgrif 链接。但是,我知道文档可能是有点密集的阅读材料(尽管我发现 Apple 的阅读材料还不错),所以我将在这里简要概述属性。

我喜欢例子,所以我将以更现代的形式重写你的两个类。

我的类名.h

#import <UIKit/UIKit.h>
@interface MyClassName : NSObject

@property (nonatomic, strong) NSObject *myPropertyName;
// method prototypes here
@end

我的类名.m

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

该类MyClassName现在有一个名为myPropertyNametype的属性NSObject *。在这种情况下,编译器将为您“免费”做很多工作。具体来说,它将生成一个支持变量,并为myPropertyName. 如果我要重写这两个文件,并假装我是编译器,包括那些东西,它们看起来像这样:

我的类名.h

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

@property (nonatomic, strong) NSObject *myPropertyName;

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

@end

我的类名.m

#import "MyClassName.h"
@implementation MyClassName

- (void)setMyPropertyName:(NSObject *)obj
{
    _myPropertyName = obj;
}

- (NSObject *)myPropertyName
{
    return _myPropertyName;
}

@end

同样,所有这些都是“免费”发生的:我只是向您展示幕后发生的事情。现在为您编号的问题。

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

    首先,您可能应该使用自动引用计数或 ARC。如果你是,你将不被允许打电话autorelease。忽略那部分,这很好用。排除autorelease,这完全等同于:

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

    如果你看一下.m我上面写的第二个文件,它基本上会转化为:

    `_myPropertyName = [[NSObject alloc] init];

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

    myPropertyName如所写,此代码将给出编译器错误,因为在此类中没有调用变量。如果你真的想访问myPropertyName属性底层(或“支持”)的实例变量,你可以使用它的真实名称:

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

    但在大多数情况下,最好使用设置器,如第 1 点所示,因为这会产生副作用,以及键值编码和其他好东西。

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

    哦。好吧,你明白了。见第 2 点。

你提到过:

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

如果没有说清楚,属性是一个抽象概念;它的数据存储在一个普通的实例变量中,通常由编译器分配。它的访问权限通常应仅限于 setter 和 getter,但有重要例外。为了使这个答案简短,我不会再详细说明了。

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

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

于 2013-10-29T03:34:33.317 回答
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的官方文档

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

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

于 2013-10-29T01:49:59.530 回答