如何将NSMutableArray转换为NSArray?


Answers:


511
NSArray *array = [mutableArray copy];

Copy制作不可变的副本。这非常有用,因为Apple可以进行各种优化。例如,发送copy到不可变数组仅保留对象并返回self

如果您不使用垃圾收集或ARC,请记住-copy保留该对象。


2
这个答案很好,但是如何从文档中分辨出copy创建普通的NSArray而不是NSMutableArray?
丹·罗森斯塔克

22
@Yar:你看的文档NSCopying它规定有:copyWithZone 副本返回是不可变的,如果考虑“不可改变的与可变”适用于接收对象; 否则,副本的确切性质由类别决定。
GeorgSchölly10年

1
非常整洁-我更喜欢m5h的解决方案。既简洁又高效。
2011年

1
我同意戴维,更新了我的回复以指出此回复。
hallski

2
@Brad:这仅意味着具有可变和不可变实现的类。例如NSArrayNSMutableArrayNSStringNSMutableString。但不是例如NSViewController它总是包含可变状态。
GeorgSchölly2014年

361

An NSMutableArray是的子类,NSArray因此您不必总是进行转换,但是如果您要确保无法修改该数组,则可以NSArray根据是否希望其自动发布来创建以下两种方式之一:

/* Not autoreleased */
NSArray *array = [[NSArray alloc] initWithArray:mutableArray];

/* Autoreleased array */
NSArray *array = [NSArray arrayWithArray:mutableArray];

编辑: GeorgSchölly提供的解决方案是一种更好的方法,而且更清洁,尤其是现在我们有了ARC,甚至不必调用自动发布。


7
我可以做(NSArray *)myMutableArray吗?
Vojto

2
是的,因为NSMutableArray是有效的NSArray的子​​类。
hallski 2010年

4
但是,强制转换为(NSArray *)仍允许强制转换为(NSMutable *)。不是这样吗?
sharvey

1
@sharvey:是的,这是正确的。如果不进行强制转换,而是直接将超类分配给子类,则会收到警告。通常,您要返回一个不可变的副本,因为这是确保您的数组确实不会被修改的唯一方法。
GeorgSchölly10年

1
以前称为“ Upcasting”(NSArray *)myMutableArray,而反向称为“ Downcasting”
FranciscoGutiérrez13年

113

我喜欢两种主要解决方案:

NSArray *array = [NSArray arrayWithArray:mutableArray];

要么

NSArray *array = [mutableArray copy];

我在其中看到的主要区别是,当mutableArray为nil时,它们的行为如何

NSMutableArray *mutableArray = nil;
NSArray *array = [NSArray arrayWithArray:mutableArray];
// array == @[] (empty array)

NSMutableArray *mutableArray = nil;
NSArray *array = [mutableArray copy];
// array == nil

错了 刚刚检查。[mutableArray copy]也返回一个空数组。
durazno

@durazno这没错。仔细检查您的测试。如果[mutableArray copy]返回一个空数组,则mutableArray必须是一个空数组。我的答案仅在mutableArray为nil时适用。
理查德·维纳布尔

尽管这是真的,但我觉得您在示例中缺少了一个更基本的事实。由于您已将mutableArray分配为nil,[mutableArray copy]因此可以简化为[nil copy]。在Objective-C中,发送到nil的任何消息始终为nil。重要的是要记住“什么都没有”和“其中没有任何东西的数组”之间的区别。
mkirk '16

@mkirk让我们不要分散眼前的问题:“如何将NSMutableArray转换为NSArray?” 有2个主要解决方案,它们之间的主要区别是可变数组为nil时它们的行为。
理查德·文布尔


5

目标C

下面是将NSMutableArray转换为NSArray的方法:

//oldArray is having NSMutableArray data-type.
//Using Init with Array method.
NSArray *newArray1 = [[NSArray alloc]initWithArray:oldArray];

//Make copy of array
NSArray *newArray2 = [oldArray copy];

//Make mutablecopy of array
NSArray *newArray3 = [oldArray mutableCopy];

//Directly stored NSMutableArray to NSArray.
NSArray *newArray4 = oldArray;

迅速

在Swift 3.0中,有一个新的数据类型Array。使用let关键字声明Array ,它将变为NSArray;如果使用var关键字声明,则将变为NSMutableArray

样例代码:

let newArray = oldArray as Array

Swift部分并不完全正确。请参见此处此处以了解可变/不可变Arrays和NSArray/ NSMutableArrays 之间的区别。他们不一样。
Bruno Ely


2
NSArray *array = mutableArray;

[mutableArray copy]反模式是所有示例代码。停止这样做是为了暂时丢弃并在当前作用域的末尾重新分配的一次性可变数组。

运行时无法优化即将超出范围,可变为0并永久释放的可变数组的无用复制。


分配的NSMutableArray一个NSArray变量不会隐蔽它(这是OP的问题是关于什么的)。如果该值意外突变,则暴露这样的值(例如,作为返回值或作为属性)可能会导致很难调试的问题。由于可变值是共享的,因此这适用于内部和外部突变。
DavidRönnqvist,

要更改该数组,您必须[NSMutableArray arrayWithArray:...或类似的东西。
安东·特罗帕什科

不必要。只需将其分配给NSMutableArray变量就足够了。由于对象从未停止过成为可变数组,因此对其调用变异方法将成功并变异共享数据。另一方面,如果将原始的可变数组复制(将其更改为不可NSMutableArray变数组),然后分配给变量并调用了mutation方法,则这些调用将失败并doesNotRespondToSelector出错,因为接收到mutating方法调用的对象位于事实是不可变的,并且不响应这些方法。
DavidRönnqvist18年

好的,这对于那些不注意编译器有关yoyope转换设置的警告的开发人员来说是有好处的
Anton Tropashko 18-10-12

1

如果要通过可变性构造一个数组,然后要返回一个不变的版本,则可以通过继承简单地将可变数组作为“ NSArray”返回。

- (NSArray *)arrayOfStrings {
    NSMutableArray *mutableArray = [NSMutableArray array];
    mutableArray[0] = @"foo";
    mutableArray[1] = @"bar";

    return mutableArray;
}

如果您“信任”调用方将(技术上仍然可变的)返回对象视为不可变的NSArray,则这是比便宜的选择[mutableArray copy]

苹果同意:

为了确定它是否可以更改接收到的对象,消息的接收者必须依赖于返回值的形式类型。例如,如果它收到类型为不可变的数组对象,则不应尝试对其进行突变。根据对象的类成员资格确定对象是否可变是不可接受的编程习惯。

上述做法将在此处详细讨论:

最佳实践:如果返回类型为NSArray,则返回mutableArray.copy或mutableArray


0

我在swift 3中搜索答案,这个问题在搜索中显示为第一个结果,我从中得到了启发,所以这里是swift 3代码

let array: [String] = nsMutableArrayObject.copy() as! [String]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.