45

As the title says, what's the difference between Array vs NSArray vs [AnyObject]?

Also, what is most recommended way of approaching this. What i mean recommended is, what's the easiest implementation. Thank you.

shle2821
  • 1,856
  • 1
  • 19
  • 26
  • This has nothing to do with Xcode. `Array` is not a type in itself, you need a type parameter. `[AnyObject]` is the same as `Array`, and it's Swift's built-in array type. `NSArray` is an Objective-C class type. – The Paramagnetic Croissant Mar 05 '15 at 23:22

4 Answers4

75

Array is a struct, therefore it is a value type in Swift. NSArray is an immutable Objective C class, therefore it is a reference type in Swift and it is bridged to Array<AnyObject>. NSMutableArray is the mutable subclass of NSArray.

var arr : NSMutableArray = ["Pencil", "Eraser", "Notebook"]
var barr = ["Pencil", "Eraser", "Notebook"]

func foo (var a : Array<String>)
{
    a[2] = "Pen"
}

func bar (a : NSMutableArray)
{
    a[2] = "Pen"
}

foo(barr)
bar(arr)

println (arr)
println (barr)

Prints:

(
    Pencil,
    Eraser,
    Pen
)
[Pencil, Eraser, Notebook]

Because foo changes the local value of a and bar changes the reference. It will also work if you do let arr instead of var as with other reference types.

Krzak
  • 1,441
  • 11
  • 12
  • 1
    For Swift 3, var parameters have been removed, add this to the first line of foo(): `var a = a` – tonethar Oct 22 '16 at 13:28
  • The removal of var parameters in Swift 3.0 is due to the confusion with reference and value types. (See the [SE-0003 Proposal](https://github.com/apple/swift-evolution/blob/master/proposals/0003-remove-var-parameters.md)). The code will no longer compile, but IMO best shows the difference, so I'll keep it as is. – Krzak Nov 01 '16 at 22:48
  • 1
    which is better NSMutableArray vs (inout:[AnyObject]) – Jaydeep Vyas Mar 28 '18 at 12:19
  • `bar(arr)` will modify `arr`, so `print(arr)` will print `[Pencil, Eraser, Pen]` – std.denis Mar 13 '22 at 23:39
26

Array is a Swift construct, and generic struct, which means that it can be an array of any specific type (Int, String, AnyObject, etc.)

[T] is syntactic sugar for Array<T>

AnyObject is an object of any class, including Objective-C classes.

NSArray is an Objective-C construct that can hold any Objective-C object and is transparently mapped to and from Array<AnyObject>

David Berry
  • 40,941
  • 12
  • 84
  • 95
  • The construct NSArray is not always transparently mapped to [AnyObject]. You can convert it by adding "as [anyObject]". This is useful when you are using arrayByAddingObjectsFromArray() to append a NSArray to another one. – JSWilson Jul 19 '16 at 15:38
1

Using the Krzak answer, here is a practical example:

// Let´s create an Array as a struct showing alternative ways
    var arrStruct = ["Pencil", "Eraser", "Notebook"]
    // or var arrStruct: [String] = ["Pencil", "Eraser", "Notebook"]
    // or var arrStruct: Array = ["Pencil", "Eraser", "Notebook"]
    // or var arrStruct = Array(["Pencil", "Eraser", "Notebook"])
    // All this alternative ways create an array as struct

    // Now let´s create a function that modifies this array struct
    func modifyArr(alternativeArr: [String]) 
    // or func modify(alternativeArr: Array<String>)
    {
        alternativeArr[2] = "Pen" // compilation error
        // This won´t work. In swift >= 3.0 all func parametes are a let variable, 
        // this means alternativeArr is defined as a let. What one has to do is 
        // create a local variable and copy the value.

        var localAlternativeArr = alternativeArr
        // or var localAlternativeArr: [String] = alternativeArr
        // or var localAlternativeArr: Array = alternativeArr

        // now we can change it.
        localAlternativeArr[2] = "Pen"
        print(localAlternativeArr) // ["Pencil", "Eraser", "Pen"]
        print(alternativeArr) // ["Pencil", "Eraser", "Notebook"]
    }

    modifyArr(alternativeArr: arrStruct)
    print(arrStruct) // ["Pencil", "Eraser", "Notebook"]

    // Since the arrStruct is a struct every time we assign to another variable or 
    // pass it as a func argument a copy is made.



// Now let´s create as an NSMutableArray
    var arrClass: NSMutableArray = ["Pencil", "Eraser", "Notebook"]
    // or var arrStruct = NSMutableArray(array: ["Pencil", "Eraser", "Notebook"])
    // All this create an NSMutableArray as a class

    // Now let´s create a function that modifies this array struct
    func modifyArr(alternativeArr: NSMutableArray)
    {
        alternativeArr[2] = "Pen"
        print(alternativeArr)
        // (
        //   Pencil,
        //   Eraser,
        //   Pen
        // )
    }

    modifyArr(alternativeArr: arrClass)
    print(arrClass)
    // (
    //   Pencil,
    //   Eraser,
    //   Pen
    // )

    // Since the arrClass is a class everytime we assign to another variable or 
    // pass it as a func argument is passed by reference. Means that any change
    // inside modifyArr is going to change the arrClass outside. The change 
    // is made in the same pointer.
lopes710
  • 315
  • 1
  • 3
  • 19
0

Adding to @Krzak's excellent answer, this is why

print(NSArray().object(at: 1))   // Triggers an UnmanagedException

2018-11-09 11:38:08.798088-0600 AppName[38786:10497909] * Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArray0 objectAtIndex:]: index 1 beyond bounds for empty NSArray'

and

print(Array<Int>()[1])  // Halts with "Thread 1: Fatal error: Index out of range"

This different handling of the error helped me understanding the difference..... e

eharo2
  • 2,553
  • 1
  • 29
  • 39