395

How do I convert NSMutableArray to NSArray in ?

3
  • 12
    just NSArray *array = [mutableArray copy]; Commented Dec 3, 2013 at 20:30
  • 1
    NSArray *array = mutableArray; Commented Jul 18, 2014 at 19:26
  • 4
    beryllium: Absolutely right. vladof81: Of course not. Commented May 14, 2015 at 17:59

9 Answers 9

525
NSArray *array = [mutableArray copy];

Copy makes immutable copies. This is quite useful because Apple can make various optimizations. For example sending copy to a immutable array only retains the object and returns self.

If you don't use garbage collection or ARC remember that -copy retains the object.

Sign up to request clarification or add additional context in comments.

6 Comments

this answer is great, but how can I tell from the docs that copy creates a normal NSArray and not an NSMutableArray?
@Yar: You look at the documentation of NSCopying It states there: copyWithZone The copy returned is immutable if the consideration “immutable vs. mutable” applies to the receiving object; otherwise the exact nature of the copy is determined by the class.
Very neat - I prefer this to m5h's solution. Both terse and more efficient.
I agree David, updated my response to point to this response.
@Brad: That just means classes that have both mutable and immutable implementations. E.g. NSArray & NSMutableArray, NSString & NSMutableString. But not for example NSViewController which always contains mutable state.
|
363

An NSMutableArray is a subclass of NSArray so you won't always need to convert but if you want to make sure that the array can't be modified you can create a NSArray either of these ways depending on whether you want it autoreleased or not:

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

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

EDIT: The solution provided by Georg Schölly is a better way of doing it and a lot cleaner, especially now that we have ARC and don't even have to call autorelease.

5 Comments

Can I just do (NSArray *) myMutableArray ?
Yes, as NSMutableArray is a subclass of NSArray that is valid.
However, casting to (NSArray *) still allows a cast back up to (NSMutable *). Ain't that the case?
@sharvey: Yes, that's correct. You'll get a warning if you don't cast but assign a superclass to a subclass directly. Usually, you want to return a immutable copy, because that's the only way to be sure, that your array really won't get modified.
Formerly That's known as "Upcasting" (NSArray *) myMutableArray and the inverse is called "Downcasting"
116

I like both of the 2 main solutions:

NSArray *array = [NSArray arrayWithArray:mutableArray];

Or

NSArray *array = [mutableArray copy];

The primary difference I see in them is how they behave when mutableArray is nil:

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

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

4 Comments

This is so wrong. Just checked. [mutableArray copy] also returns an empty array.
@durazno It is not wrong. Double check your test. If [mutableArray copy] is returning an empty array, then mutableArray must have been an empty array. My answer only applies when mutableArray is nil.
Although this is true, I feel like you're missing a more fundamental truth in your example. Since you've assigned mutableArray to be nil, [mutableArray copy] can be simplified to [nil copy]. In objective-c any message sent to nil will always be nil. It's important to remember the distinction between "nothing" and "an array with nothing in it".
@mkirk Let's not distract from the question at hand: "How do I convert NSMutableArray to NSArray?" There are 2 primary solutions, and the primary difference between them is how they behave when the mutable array is nil.
18

you try this code---

NSMutableArray *myMutableArray = [myArray mutableCopy];

and

NSArray *myArray = [myMutableArray copy];

1 Comment

What does this do that the others don't do?
8

Objective-C

Below is way to convert NSMutableArray to 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

In Swift 3.0 there is new data type Array. Declare Array using let keyword then it would become NSArray And if declare using var keyword then it's become NSMutableArray.

Sample code:

let newArray = oldArray as Array

1 Comment

The Swift part is not entirely right. See here and here for the difference between mutable/immutable Arrays and NSArray/NSMutableArrays. They are not the same.
3

In objective-c :

NSArray *myArray = [myMutableArray copy];

In swift :

 var arr = myMutableArray as NSArray

Comments

1
NSArray *array = mutableArray;

This [mutableArray copy] antipattern is all over sample code. Stop doing so for throwaway mutable arrays that are transient and get deallocated at the end of the current scope.

There is no way the runtime could optimize out the wasteful copying of a mutable array that is just about to go out of scope, decrefed to 0 and deallocated for good.

4 Comments

Assigning an NSMutableArray to an NSArray variable will not covert it (which is what the OP's question is about). Exposing such a value (for example as a return value or as a property) could result in very hard to debug issues if that value was unexpectedly mutated. This applies to both internal and external mutations since the mutable value is shared.
To mutate that array you'd have to [NSMutableArray arrayWithArray:... or something like that.
Not necessarily. Simply assigning it to a NSMutableArray variable is enough. Since the object never stopped being a mutable array, calling mutating methods on it will succeed and mutate the shared data. If on the other hand the original mutable array was copied—changing it to an immutable array—and then assigned to a NSMutableArray variable and had mutating methods called on it, those calls would fail with doesNotRespondToSelector errors because the object that received the mutating method call is in fact immutable and doesn't respond to those methods.
ok, this might have some merit for developers that don't heed the compiler warning about tyope conversion assigments
0

If you're constructing an array via mutability and then want to return an immutable version, you can simply return the mutable array as an "NSArray" via inheritance.

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

    return mutableArray;
}

If you "trust" the caller to treat the (technically still mutable) return object as an immutable NSArray, this is a cheaper option than [mutableArray copy].

Apple concurs:

To determine whether it can change a received object, the receiver of a message must rely on the formal type of the return value. If it receives, for example, an array object typed as immutable, it should not attempt to mutate it. It is not an acceptable programming practice to determine if an object is mutable based on its class membership.

The above practice is discussed in more detail here:

Best Practice: Return mutableArray.copy or mutableArray if return type is NSArray

Comments

0

i was search for the answer in swift 3 and this question was showed as first result in search and i get inspired the answer from it so here is the swift 3 code

let array: [String] = nsMutableArrayObject.copy() as! [String]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.