【问题标题】:NSArray and NSMutable Array. Type of property and type of ivar are not the sameNSArray 和 NSMutableArray。属性类型和 ivar 类型不一样
【发布时间】:2014-08-07 17:32:30
【问题描述】:

我正在阅读关于 Objective-C 编程的 big nerd 牧场指南。

第 21 章中有一个例子和挑战让我很困惑。 (我实际上完成了挑战,但我使用了示例中的先前代码)我想真正了解我做了什么。

它与声明一个 NSArray 类型的属性,然后将 setter 方法声明为 NSMutableArray 类型有关。谁能告诉我这里发生了什么?此声明的“幕后”发生了什么。

@property (nonatomic copy) NSArray *assets 

这两个文件中发生了什么?请尽可能在最低级别进行解释。谢谢!

BNREmployee.h

@interface BNREmployee: BNRPerson
{
    NSMutableArray *_assets
}
@property (nonatomic copy) NSArray *assets 

@end 

BNREmployee.m

@implementation BNREmployee 

- (void)setAssets:(NSArray *)a
{
    _assets = [a mutableCopy]; //What did this actually do? 
}

- (NSArray *)assets
{
    return [_assets copy];
}

【问题讨论】:

  • assets 的“外部面”(即属性视图)是一个不可变数组,但内部维护了一个可变版本。
  • (请记住,没有规则规定属性必须有任何特定变量支持它。它可以从数据库查询或网络请求中获取其值。)

标签: objective-c class


【解决方案1】:

一个NSMutableArray 是一个NSArray(它是一个子类),所以它只是被正常分配。幕后没有什么特别的事情发生。

我可以举一个例子来查看您的模型,例如将 BNREmployee 对象分配给 BNRPerson 指针,这将正常工作。

BNREmployee *employee = [BNREmployee new]; // or whatever initializer

BNRPerson *person = employee; // works fine, an employee IS a person

您始终可以将NSMutableArray 分配给NSArray 指针,但反之则不行。

编辑

"该属性有NSArray类型,告诉其他类,如果你问 对于我的资产,你会得到一些不可变的东西。 然而,在幕后,assets 数组实际上是一个实例 的 NSMutableArray 以便您可以在 BNREmployee 中添加和删除项目"

通过将公共属性公开为不可变类型,您可以让任何潜在的调用者知道,如果不显式调用对象上的 mutator,他们就无法修改该属性。 它还让调用者知道,一旦他们得到集合,它的内容就永远不会从他们下面被改变。这是公开不可变属性时的标准约定。 正如下面其中一个 cmets 所指出的,在某些情况下,返回类型是不可变的,但底层对象实际上在内部是可变的并且可以更改,因此,如果您尚未收到实际的不可变副本(例如[NSView subviews]),那么好的做法是在接收对象时制作副本。

将实际的底层变量设为可变类型是为了方便所属类在内部轻松修改它。从功能上讲,您可以通过将其设为常规 NSArray 并在您想要更改其内容时不断地重新创建它(例如 array = [array arrayByAddingObject:object])来完成同样的事情。这当然比仅仅修改一个可变实例要慢。

【讨论】:

  • 赋值给NSMutableArray类型的实例变量,而不是NSArray,所以在setter方法中调用copy是错误的做法。
  • 我错过了那部分,正在修改答案。
  • 我认为这个例子的重点是数组的可变性是一个私有的实现细节,而它的公共接口提供了不可变的访问。通过访问器方法公开可变数组在概念上会违反封装。
  • Jiehr 是正确的。在书中它指出“该属性的类型为 NSArray,它告诉其他类,如果您要我的资产,您将得到一些不可变的东西。”但是,在幕后,assets 数组实际上是 NSMutableArray 的一个实例,因此您可以在 BNREmployee 中添加和删除项目”我只是很难理解该语句......
  • "它还让调用者知道,一旦他们获得集合,它的内容将永远不会从它们下面被更改。这是暴露不可变属性时的标准合约。"这是不正确的。作为调用者,不能假设从另一个对象从不可变类型的属性接收到的数组实际上不会发生变异。 不能改变它,但是没有标准的设计合同它不会在你的控制下改变。反例见-[NSView subviews]
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-24
相关资源
最近更新 更多