【问题标题】:Why does a (copy, nonatomic) NSMutableArray property create NSArrays?为什么(复制,非原子)NSMutableArray 属性会创建 NSArrays?
【发布时间】:2013-02-13 15:14:17
【问题描述】:

我在创建 TableView class 时犯了一个错误,并且在我定义它时不小心将我的 @property 保留为 copy

@property (copy, nonatomic) NSMutableArray *words; 

我“正确”初始化了数组:(注意这是第三次尝试,所以请忽略我没有使用 mutableCopy 和其他更好的方法)

NSArray *fixedWords = @[@"Eeny", @"Meeny", @"Miny", @"Moe", @"Catch", @"A", @"Tiger", @"By", @"His", @"Toe"];
NSMutableArray *mutWords = [[NSMutableArray alloc] initWithArray:fixedWords];
self.words = mutWords;

但是当我后来重新排序数组时,它在 removeObjectAtIndex 行上崩溃了:

id object = [self.words objectAtIndex:fromIndexPath.row];
NSUInteger from = fromIndexPath.row;
NSUInteger to = toIndexPath.row;
[self.words removeObjectAtIndex:from];

带有错误信息

unrecognized selector sent to instance

花了很多时间才发现这是因为副本意味着分配 NSMutableArray 会导致创建标准(非可变)NSArray。谁能解释为什么这是正确的行为?

【问题讨论】:

  • @property (copy, nonatomic) NSMutableArray *words; 不使用复制,你应该使用保留。
  • 或强而不是保留
  • 哈,我来到这里是因为我希望今天有一种方法可以做到@property (nonatomic, mutableCopy)。哦,好吧,随着 swift 即将逐步淘汰 Objective-C,我猜它永远不会发生了。

标签: ios objective-c nsmutablearray nsarray


【解决方案1】:

-copy,由可变 Cocoa 类实现,总是returns their immutable counterparts。因此,当一个 NSMutableArray 被发送 -copy 时,它返回一个包含相同对象的 NSArray。

因为words 有内存限定符copy,所以这一行:

NSMutableArray *mutWords = [[NSMutableArray alloc] initWithArray:fixedWords];
self.words = mutWords;

扩展到:

NSMutableArray *mutWords = [[NSMutableArray alloc] initWithArray:fixedWords];
self.words = [mutWords copy];

鉴于 NSMutableArray 是 NSArray 的子类,编译器不会抱怨,而且您现在手上有一颗定时炸弹,因为 NSArray 无法识别它是可变子类的方法(因为它不能改变它的内容)。

【讨论】:

  • 要明确:copy 发生在 setter 的综合实现中,而不是在调用站点。
  • @bbum 当然。这只是为了简洁起见。我真的不想进入这类问题的实际属性:)
  • @CodaFi 但是 NSArray 采用了 NSMutableCopying 协议,为什么它返回 NSArray 而不是 NSMutableArray??
  • NSMutableCopying 只是说一个类响应-mutableCopy(WithZone:),而不是它返回自身的可变副本在所有情况下。 Objective-C 中的协议与行为和实现几乎没有关系,而与对特定消息的响应有关。
  • @Kaiserludi 在将@property 添加到语言中时,我们进行了很长时间的讨论。最终,mutableCopy 被证明是一个边缘案例,具有足够多的与所述一次性相关的一次性业务逻辑,因此不值得添加。
【解决方案2】:

属性并不神奇,它们只是简写。在对象上声明 @property 会告诉编译器为其创建一个支持实例变量和访问器方法。实际生成的代码取决于您在属性上设置的属性。

请务必记住,使用点语法设置属性也是简写。当你打电话时……

self.words = mutWords;

……你实际上是在后台调用生成的访问器方法,像这样:

[self setWords:mutWords];

由于您在属性上指定了 copy 属性,因此您已经告诉编译器生成 -setWords: 访问器方法,代码如下所示:

- (void)setWords:(NSMutableArray *)words
{
    _words = [words copy];
}

知道了这一切,您就可以看到发生了什么:生成的 setter 方法将在输入参数上调用 -copy,并将结果分配给支持实例变量。因为-copy 方法总是被实现为返回一个非可变对象(执行[aMutableString copy] 将返回一个NSString,依此类推)设置该属性将始终存储一个非可变副本。

【讨论】:

    猜你喜欢
    • 2011-05-03
    • 2013-07-08
    • 2010-10-23
    • 2011-03-20
    • 2011-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多