Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Immutable value of type 'Any[]' only has mutating members named 'append' in Swift, despite the array is defined as 'var'

Tags:

ios

swift

I want to append a new object to my Array, which is defined as var in my Swift app, but despite me defining it as var, the following error occurred when I tried to append it.

`Immutable value of type 'Any[]' only has mutating members named 'append'`

Here's my code:

var contactsArray: Any[]!
func popoverWillClose(notification: NSNotification) {
    if popoverTxtName.stringValue != "" && popoverTxtContactInfo.stringValue != "" {
        contactsArray.append(makeDictionaryRecord(popoverTxtName.stringValue, withInfo: popoverTxtContactInfo.stringValue))
    }
}

(makeDictionaryRecord(withInfo:) method takes two String and returns Dictionary<String, Any>)

My original code defines contactsArray as let, and later I found it was my mistake, so I changed it to var. However, things still didn't make it so far.

I also changed the type of components of contactsArray to AnyObject[], Any[], and AnyObject[]!, but nothing didn't change at all.

( That being said, since the contactsArray has to take Dictionary within it, it has to be defined as either Any[] or Any[]!, since Dictionary is defined as struct, if I understand it correctly. )

What's wrong with my code? How can I properly append the component to contactsArray?

like image 741
Blaszard Avatar asked Jul 03 '14 14:07

Blaszard


2 Answers

Problem 1: You've defined contactsArray as an implicitly unwrapped Optional, but the values of Optional variables are always immutable. You can define it this way instead to allow appending values:

var contactsArray: [Any]

Update: This hasn't been a problem since Swift introduced assignment through optional chaining. With implicitly unwrapped optionals, this happens automatically.

Problem 2: You haven't given the array an initial value -- the compiler starts complaining about that when you fix problem 1 for an implicitly unwrapped optional, that means the value is nil, so you'll get a runtime exception. The solution is to initialize the variable with an empty array:

var contactsArray: [Any]! = []

You almost never need an optional Array—an empty array is just as good a signifier of "no values" as nil, and safer, to boot. If you decide to use an optional array anyway, use a regular optional (i.e., declared with ?), not an implicitly unwrapped one:

var contactsArray: [Any]? = []
like image 172
Nate Cook Avatar answered Oct 20 '22 09:10

Nate Cook


The syntax for array declaration has been changed, it's now

var contractsArray: [Any] = []

Also if you're modifying an array as part of a struct or an enum you might see this error. A struct or an enum is a value type and the method needs the mutating keyword:

struct contacts {
    var contactsArray:[Any] = []
    mutating func popoverWillClose(notification: NSNotification) {
        if popoverTxtName.stringValue != "" && popoverTxtContactInfo.stringValue != "" {

            contactsArray.append(makeDictionaryRecord(popoverTxtName.stringValue, withInfo: popoverTxtContactInfo.stringValue))
        }
    }
}

In addition you cannot save instances of a struct with mutating methods as a constant using the let keyword, it needs to be declared as var because the value for the variable will change when you call a mutating function.

like image 23
Bjorn Avatar answered Oct 20 '22 10:10

Bjorn