22

Now that Swift's Array's are truly immutable thanks to full value semantics, how can I create an mutable copy of an immutable array? Similar to Obj-C mutableCopy(). I can of course downcast the array to an NSArray and use mutableCopy() but don't want to use NSArray because it does not strictly typed.

I have a toolbar which has items from the storyboard. I want to remove an item from the toolbar and use toolbar.setItems. I wanted to do it without casting as a NSArray, because none of these functions take NSArrays, they take [AnyObject].

Obviously now when I call removeAtIndex() it does not work, which is correct. I just need a mutableCopy

Simply assigning to var does not work for me and give 'Immutable value of type [AnyObject]'

var toolbarItems = self.toolbar.items
toolbarItems.removeAtIndex(2) //Immutable value of type [AnyObject]

I am using Beta 3

6 Answers 6

23

The problem is that self.toolbar.items is an implicitly unwrapped optional (of type [AnyObject]!) and they are always immutable. When you assign to the variable toolbarItems without explicitly stating its type, it too becomes an implicitly unwrapped optional, and thus is immutable as well.

To fix this do either:

var toolbarItems:[AnyObject] = self.toolbar.items
toolbarItems.removeAtIndex(2)

Or:

var toolbarItems = self.toolbar.items as [AnyObject]
toolbarItems.removeAtIndex(2)

Update

As of Xcode 6 Beta 5, you can update collections that are stored in optional variables, so the original code now works:

var toolbarItems = self.toolbar.items
toolbarItems.removeAtIndex(2)
Sign up to request clarification or add additional context in comments.

1 Comment

This is pretty much what I said in my answer, but with a concise explanation of what's under the hood - hence you deserve my upvote
13

Arrays are value types (struct), so they are passed around by value and not by reference.

That said, if you create a variable of array type and assign it the immutable array, a copy of the immutable array is actually created and assigned to it - and of course that copy has no relationship with the original immutable array (besides having the same values at the time it is created).

let immutable = [1, 2, 3]

//immutable[0] = 1 // Fails, ok

var mutable = immutable

mutable[0] = 5

In your case, you are accessing an immutable array which is an NSArray of AnyObjects (see documentation). You can use it as an Array in swift, make a copy of it and modify as follows:

let immutable : NSArray = [ 1, 2, 3 ]

//immutable[0] = 1 // Fails, ok

var mutable : [AnyObject] = immutable

mutable.removeAtIndex(1) // mutable now is [1, 3]

mutable[0] = 7 // mutable now is [7, 3]

After you're done with your changes, you can assign to the items property

6 Comments

This does not work for me I think because of beta 3?: var toolbarItems = self.toolbar.items;toolbarItems.removeAtIndex(2) `//Immutable value of type '[AnyObject]' Added Edit to question.
I think the problem is because self.toolbar.items is an NSArray. Looking into it
Perhaps with an NSArray, you need to go a little more old-school? Try var mutable = immutable.mutableCopy() as NSMutableArray?
Read addition to my answer above
Aha. So typing it as a [AnyObject] did it.
|
1

It is as simple as declaring a var with your array.

var items = toolbar.items

Now you can change items and then reassign to the toolbar.

toolbar.items = items

Note that you can cannot (as of Beta 3) alter the elements of an "immutable" array declared with let as well. Just the length of the array is was fixed, which is why you cannot remove items.

However, according to Apple's documentation of UIToolbar, the items array is already mutable.

SWIFT
var items: [AnyObject]!

5 Comments

See my edit. I am not sure if this is because of Beta 3?
Your latest edit (with var b = a) works fine in Xcode build 6A254o. If you try a[1] = 5 you will see that b is altered as expected.
yah I am dumbo I didn't mean to type that. I removed it. That does work but for some reason self.toolbar.items is still immutable. And I think that arrays now are completely immutable if you assign them. From the apple release notes: "Array in Swift has been completely redesigned to have full value semantics like Dictionary and String have always had in Swift. This resolves various mutability problems – now a 'let' array is completely immutable, and a 'var' array is completely mutable"
@Mundi, I think that is no longer valid in beta 3, they fixed it. You cannot change the value of an element in an immutable array
See my additional answer - I tested it and it works.
1

Tested + works:

    var mutable : [UIBarButtonItem] = []
    for button in toolbar.items {
        mutable += button as UIBarButtonItem
    }
    mutable.removeAtIndex(2)
    toolbar.setItems(mutable, animated: true)

Comments

1

TO REMOVE AN OBJECT FROM PARTICULAR INDEX OF AN ARRAY.

let fullArray : NSArray = Userdefaults().value(forKey: "YOUR_ARRAY_STRING") as! NSArray
var mutableArray : [AnyObject] = fullArray as [AnyObject]
mutableArray.remove(at: INDEX_TO_REMOVE) //Eg: mutableArray.remove(at: 0)
mutableArray.append(ARRAY_TO_APPEND)

Comments

0

In Beta3 constant arrays are completely immutable while variable arrays are entirely mutable. So just change let array:to var array: and then verify your code

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.