Swift: Cannot assign to immutable expression of type 'AnyObject?!'

25,664

Solution 1

The error message says, you're trying to change an immutable object, which is not possible.

Objects declared as method parameters or return values in closures are immutable by default.

To make the object mutable either add the keyword var in the method declaration or add a line to create a mutable object.

Also index variables in repeat loops are immutable by default.

In this case a line is inserted to create a mutable copy and the index variable is declared as mutable.

Be careful to change objects while being enumerated, this could cause unexpected behavior

...
query.findObjectsInBackgroundWithBlock {(objects, error) -> Void in
    if error == nil {
        //this will always have one single object
        var mutableObjects = objects
        for var user in mutableObjects! {
            //user.count would be always 1
            for (key, value) in updateData {

                user[key] = value
...

Solution 2

In swift a lot of types are defined as structs, which are immutable by default.

I had the same error doing this :

protocol MyProtocol {
    var anInt: Int {get set}
}

class A {

}

class B: A, MyProtocol {
    var anInt: Int = 0
}

and in another class :

class X {

   var myA: A

   ... 
   (self.myA as! MyProtocol).anInt = 1  //compile error here
   //because MyProtocol can be a struct
   //so it is inferred immutable
   //since the protocol declaration is 
   protocol MyProtocol {...
   //and not 
   protocol MyProtocol: class {...
   ...
}

so be sure to have

protocol MyProtocol: class {

when doing such casting

Share:
25,664
PhilHarmonie
Author by

PhilHarmonie

Updated on July 23, 2022

Comments

  • PhilHarmonie
    PhilHarmonie almost 2 years

    I searched, but I didn't find a familiar answer, so...

    I am about to program a class to handle parse methods like updating, adding, fetching and deleting.

    func updateParse(className:String, whereKey:String, equalTo:String, updateData:Dictionary<String, String>) {
    
        let query = PFQuery(className: className)
    
        query.whereKey(whereKey, equalTo: equalTo)
        query.findObjectsInBackgroundWithBlock {(objects, error) -> Void in
            if error == nil {
                //this will always have one single object
                for user in objects! {
                    //user.count would be always 1
                    for (key, value) in updateData {
    
                        user[key] = value //Cannot assign to immutable expression of type 'AnyObject?!'
    
                    }
    
                    user.saveInBackground()
                } 
    
            } else {
                print("Fehler beim Update der Klasse \(className) where \(whereKey) = \(equalTo)")
            }
        }
    
    }
    

    As I am about to learn swift at the moment, I would love to get an answer with a little declaration, so that I would learn a little bit more.

    btw: I later call this method like this:

    parseAdd.updateParse("UserProfile", whereKey: "username", equalTo: "Phil", updateData: ["vorname":self.vornameTextField!.text!,"nachname":self.nachnameTextField!.text!,"telefonnummer":self.telefonnummerTextField!.text!])
    
  • vadian
    vadian over 8 years
    It affects also the index variable in the repeat loop. I changed the post
  • Chris Birch
    Chris Birch about 6 years
    Nice find - saved me a lot of time ta.
  • Tino
    Tino about 5 years
    This has been changed - it's recommended to use protocol MyProtocol: AnyObject { instead
  • Warpling
    Warpling over 4 years
    This is the only explanation I've found that made sense. Thank you!!
  • Abhishek Thapliyal
    Abhishek Thapliyal about 4 years
    @ZpaceZombor: Thanks my issue is resolved with you comments :)