声明实例变量和属性之间的冲突

时间:2015-04-29 02:53:54

标签: objective-c

我正在研究Objective-C。我之前问了一个关于这段代码的问题,但我提出了进一步的问题。以下代码尝试在外部NSArray,但内部确实NSMutableArray,因此我可以添加指针或删除NSMutableArray

我面临两个问题。 1)这样做的目的是什么?您是否有外部NSArray的具体原因?为什么我不能声明NSMutableArray的属性?

2)我知道当我声明_assets的属性时,实例变量(NSArray *assets)。我还在界面下声明了NSMutableArray *_assets。我认为这两个_assets相互冲突,即使它们有不同的类型。我是以错误的方式思考这个问题的吗?

@interface BNREmployee : BNRPerson
    {
        NSMutableArray *_assets;
    }

@property (nonatomic) unsigned int employeeID;
@property (nonatomic) unsigned int officeAlarmCode;
@property (nonatomic) NSDate *hireDate;
@property (nonatomic, copy) NSArray *assets;

5 个答案:

答案 0 :(得分:1)

穿戴     {         NSMutableArray * _assets;     } 在@implementation块中

@implementation {
   NSMutableArray *_assets;
}

将NSMutableArray放在实现块中隐藏了这样一个事实:它可以从消费者那里变化(它不再在头文件中)。

跟着它:

@synthesize assets = _assets;

实际上这可能不是必需的,但可以让事情变得更加清晰。当您声明属性时,将自动创建ivar(除非您@dynamic属性)。但是,显式声明的同名ivar将覆盖自动创建的ivar - 只要类型相同或是子类。

使其成为NSArray公开可见的原因是没有其他人可以改变您的数据结构。你将控制它。如果它是内部的NSMutableArray,那么您可以添加和删除项目,而不会将该功能暴露给消费者。

您可以将您的属性声明为readonly或readwrite - 读写NSArray意味着您可以使用属性集替换整个数组,但您无法添加或删除项目。如果你在内部添加和删除项目,这可能会使事情变得混乱。当有一个可变的内部版本时,尽量坚持readonly。

答案 1 :(得分:1)

我会按照你问他们的方式尝试你的答案。让希望他们清除你的疑虑。到目前为止,我猜你会知道NSArray一旦初始化了数据,你将无法添加或删除其中与NSMutableArray不同的数据。

此处的好处是没有其他人可以更改您的外部可见数据。此外,当您尝试对数组进行排序或迭代时,您确信不会删除或添加其他数据。此外,如果您对此类情况使用NSMutableArray,则在迭代数组时添加数据时应用程序会崩溃。

喜欢@KirkSpaziani解释

@synthesize assets = _assets;

将为您的属性创建一个实例变量。但实际上你应该只在getter和setter中使用这个_assets。您应该使用其他地方self.assets

您还可以按如下方式合成您的其他数组NSMutableArray *_assets

@synthesize _assets = __assets; 哪个会有双下划线,但坦率地说我们不应该使用下划线作为起始变量名。如果你有完全不同的名字,那就太好了。

同样,随着Objective C的进步,您根本不需要合成这些变量。只需使用self.variableName即可访问它。

希望它能清除你的一些疑问。

答案 2 :(得分:1)

如果您希望_assets成为可变数组,但是您不希望其他类修改它,那么您可以执行以下操作:实现assets属性的setter和getter,使它们看起来像这样(实现getter和setter将导致属性不被合成,这意味着NSArray *_assets将不会自动创建):

-(NSArray *)assets{
  return [_assets copy]; // Copy creates an immutable copy
}
-(void)setAssets:(NSArray *)assets{
  _assets = [NSMutableArray arrayWithArray:assets];
}

请记住,如果您访问资产数组很多,它可能会很慢,因为您每次都创建一个不可变副本,因此您可以在修改_assets数组时创建NSArray并返回在-(NSArray *)assets方法

答案 3 :(得分:0)

您在内部保留NSMutableArray但在外部公开NSArray的原因是,您的API用户不会滥用它并改变其数据。将其视为不可变的使人们不太容易弄乱它。

您可以采取的另一种方法是根本不使用属性,而只是在类扩展中使用getter和mutable属性。例如,在你的.h:

@interface BNREmployee : BNRPerson

- (NSArray *)assets;

@end

在你的.m

@interface BNREmployee ()

// Inside of the class manipulate this property
@property (nonatomic, strong) NSMutableArray *mutableAssets;

@end

@implementation BNREmployee

// Clients of your class rely on this
- (NSArray *)assets
{
    // copy makes the result immutable
    return [self.mutableAssets copy];
}

@end

答案 4 :(得分:0)

另一种方法可能是使该属性只能写入您的类的实现。

为此,请在标题中将您的媒体资源声明为readonly

//BNREmployee.h
@property (nonatomic, readonly) NSMutableArray *assets;

在实现的内部接口中将其声明为readwrite

//BNREmployee.m
@interface BNREmployee()
@property (nonatomic, readwrite) NSMutableArray *assets;
@end

@implementation
...