92

I was referring to Apple's Swift programming guide for understanding creation of Mutable/ immutable objects(Array, Dictionary, Sets, Data) in Swift language. But I could't understand how to create a immutable collections in Swift.

I would like to see the equivalents in Swift for the following in Objective-C

Immutable Array

NSArray *imArray = [[NSArray alloc]initWithObjects:@"First",@"Second",@"Third",nil];

Mutable Array

NSMutableArray *mArray = [[NSMutableArray alloc]initWithObjects:@"First",@"Second",@"Third",nil];
[mArray addObject:@"Fourth"];

Immutable Dictionary

NSDictionary *imDictionary = [[NSDictionary alloc] initWithObjectsAndKeys:@"Value1", @"Key1", @"Value2", @"Key2", nil];

Mutable Dictionary

NSMutableDictionary *mDictionary = [[NSMutableDictionary alloc]initWithObjectsAndKeys:@"Value1", @"Key1", @"Value2", @"Key2", nil];
[mDictionary setObject:@"Value3" forKey:@"Key3"];
0

7 Answers 7

120

Arrays

Create immutable array

First way:

let array = NSArray(array: ["First","Second","Third"])

Second way:

let array = ["First","Second","Third"]

Create mutable array

var array = ["First","Second","Third"]

Append object to array

array.append("Forth")


Dictionaries

Create immutable dictionary

let dictionary = ["Item 1": "description", "Item 2": "description"]

Create mutable dictionary

var dictionary = ["Item 1": "description", "Item 2": "description"]

Append new pair to dictionary

dictionary["Item 3"] = "description"

More information on Apple Developer

5
  • 12
    "Fixed length" array would be more precise. It's not immutable.
    – Sulthan
    Commented Jun 7, 2014 at 11:31
  • 1
    immutable Dictionary is truly immutable (opposite to Array)
    – Bryan Chen
    Commented Jun 7, 2014 at 11:45
  • @BryanChen Yep, I forgot to remove var.
    – nicael
    Commented Jun 7, 2014 at 11:53
  • 2
    Yup. More info on the un-immutability of arrays in this question and its answers. Commented Jun 7, 2014 at 14:34
  • array += "Forth" no long work in Xcode 6 GM change it to array += ["Forth"] or array.append("Forth")
    – dopcn
    Commented Sep 12, 2014 at 7:45
36
+100

Swift does not have any drop in replacement for NSArray or the other collection classes in Objective-C.

There are array and dictionary classes, but it should be noted these are "value" types, compared to NSArray and NSDictionary which are "object" types.

The difference is subtle but can be very important to avoid edge case bugs.

In swift, you create an "immutable" array with:

let hello = ["a", "b", "c"]

And a "mutable" array with:

var hello = ["a", "b", "c"]

Mutable arrays can be modified just like NSMutableArray:

var myArray = ["a", "b", "c"]

myArray.append("d") // ["a", "b", "c", "d"]

However you can't pass a mutable array to a function:

var myArray = ["a", "b", "c"]

func addToArray(myArray: [String]) {
  myArray.append("d") // compile error
}

But the above code does work with an NSMutableArray:

var myArray = ["a", "b", "c"] as NSMutableArray

func addToArray(myArray: NSMutableArray) {
  myArray.addObject("d")
}

addToArray(myArray)

myArray // ["a", "b", "c", "d"]

You can achieve NSMutableArray's behaviour by using an inout method parameter:

var myArray = ["a", "b", "c"]

func addToArray(inout myArray: [String]) {
  myArray.append("d")
}

addToArray(&myArray)

myArray // ["a", "b", "c", "d"]

Re-wrote this answer 2015-08-10 to reflect the current Swift behaviour.

3
  • 1
    This has obviously been changed now. A constant array is now truly immutable, and a variable array is now truly mutable. They are passed as values, therefore they will be copied when assigned to another variable or passed between functions. This, however, has nothing to do with mutability or immutability.
    – Balthazar
    Commented Aug 9, 2015 at 9:59
  • Also as I mentioned in my answer, being passed as values is relevant to mutability/immutability since the only time you care about that is when passing an array to other code (which may modify it). Commented Aug 9, 2015 at 23:48
  • But if you access the array as a property, you can still modify it from another object. One of the benefits of an immutable array, is that you can safely pass it to another object, without worrying whether the other object might modify the original. This concern doesn't exist anymore when the objects are passed as values. So, different semantics require different coding practices. EDIT: I now see you have reworded the post, so we agree. I agree the differences are important to be aware of wrt. the use of mutable collections.
    – Balthazar
    Commented Aug 10, 2015 at 17:50
6

There is only one Array and one Dictionary type in Swift. The mutability depends on how you construct it:

var mutableArray = [1,2,3]
let immutableArray = [1,2,3]

i.e. if you create an assign to a variable it is mutable, whereas if you create an assign to constant it is not.

WARNING: Immutable arrays are not entirely immutable! You can still change their contents, just not their overall length!

3
  • 1
    FYI: the array behavior is changing in an upcoming beta; I think everyone piled on about that one
    – russbishop
    Commented Jun 24, 2014 at 3:17
  • @xenadu Source? ETA on that beta? Commented Jun 26, 2014 at 15:44
  • Sorry, no source. It came from a discussion with one of the compiler team members. He also said Beta 2 was basically only a couple of already checked in bug fixes and has nothing related to the post-WWDC feedback.
    – russbishop
    Commented Jun 27, 2014 at 1:44
5

Just declare your (any)object or variable with

'let' key word -> for "constan/Immutable" array, dictionary, variable, object..etc.

and

'var' key word -> for "Mutable" array, dictionary, variable, object..etc. 

For more deeply information

“Use let to make a constant and var to make a variable. The value of a constant doesn’t need to be known at compile time, but you must assign it a value exactly once. This means you can use constants to name a value that you determine once but use in many places."

var myVariable = 42
myVariable = 50
let myConstant = 42

Read “The Swift Programming Language.”

1
3

If you want to work with Array (Swift) as with NSArray, you can use a simple bridge function. Example:

var arr1 : Array = []

arr1.bridgeToObjectiveC().count

It works the same for let.

0

From Apple's own docs:

Mutability of Collections

If you create an array, a set, or a dictionary and assign it to a variable, the collection that is created will be mutable. This means that you can change (or mutate) the collection after it is created by adding, removing, or changing items in the collection. Conversely, if you assign an array, a set, or a dictionary to a constant, that collection is immutable, and its size and contents cannot be changed.

https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html#//apple_ref/doc/uid/TP40014097-CH8-ID105

Other uses of immutable/mutable collections depend on why you want them to be mutable/immutable. Collections are value types in Swift, which means their contents is copied when they are assigned to another value, or passed to another function/method. Therefore, you do not need to worry about whether a receiving method function might change the original array. Therefore you don't need to ensure to return an immutable collection if your class is holding a mutable collection, for instance.

0

Swift Mutable/Immutable collection

[Unmodifiable and Immutable]

Swift's array can be muted

[let vs var, Value vs Reference Type]

Immutable collection[About] - is a collection structure of which can not be changed. It means that you can not add, remove, modify after creation

let + struct(like Array, Set, Dictionary) is more suitable to be immutable

There are some classes(e.g. NSArray) which doesn't provide an interface to change the inner state

but

class A {
    var value = "a"
}

func testMutability() {
    //given
    let a = A()
    
    let immutableArr1 = NSArray(array: [a])
    let immutableArr2 = [a]
    
    //when
    a.value = "aa"
    
    //then
    XCTAssertEqual("aa", (immutableArr1[0] as! A).value)
    XCTAssertEqual("aa", immutableArr2[0].value)
}   

It would rather is unmodifiable array

Not the answer you're looking for? Browse other questions tagged or ask your own question.