Search code examples
swiftconstantsnsmutabledictionaryletswift2

Adding object to let constant NSMutableDictionary works, but why?


I've been trying to figure out why it's possible to add objects to a let constant dictionary, but cannot find the answer.

The code below works, but I've always thought of let constants as immutable objects.

Anyone that can shed som light on this?

        // Create dictionary to allow for later addition of data
    let data: NSMutableDictionary = ([
        "firstname" : "john",
        "lastname" : "doe"
    ])

    // Add email to dictionary if e-mail is not empty
    if email != "" {
        data.setValue(email, forKey: "email")
    }

Solution

  • In Swift the let keyword is used to declare a constant. However, there are some things you need to be aware of depending on if you are declaring a constant for a reference type or a value type.

    Reference Type

    // Declare a class (which is a reference type)
    class Foo {
        var x = 1
    }
    
    // foo's reference is a constant. 
    // The properties are not unless they are themselves declared as constants.
    let foo = Foo()
    
    // This is fine, we are not changing the foo reference.
    foo.x = 2
    
    // This would result in a compiler error as we cannot change 
    // the reference since foo was declared as a constant.
    foo = Foo()
    

    Value Type

    // Declare a struct (which is a value type)
    struct Bar {
        var y = 1 // Note the var
    }
    
    // bar's value is a constant. The constant nature of the value type properties 
    // that are part of this value are subject to bar's declaration.
    let bar = Bar()
    
    // This would result in a compiler error as we cannot change 
    // the value of bar.
    bar.y = 2
    

    Mixture of Reference and Value Types

    Generally you wouldn't want to have a reference type property defined on a value type. This is for illustrative purposes.

    // Declare a struct (which is a value type)
    struct Car {
        let foo = Foo() // This a reference type
    }
    
    // The value is a constant. But in this case since the property foo 
    // is declared as a constant reference type, then the reference itself 
    // is immutable but its x property is mutable since its declared as a var.
    let car = Car()
    
    // This is fine. The x property on the foo reference type is mutable.
    car.foo.x = 2
    

    Since NSMutableDictionary is a class, declaring the reference as a constant ensures you cannot change its reference, however its mutable properties can be changed.

    The comment on your question from @vadian regarding NSMutableDictionary should be noted.