Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a Dictionary as a optional property using Swift

Tags:

xcode

ios

swift

I created a swift class to test Dictionaries. So, I wrote the code below:

import Foundation

   class MyClass {

    var myFirstDictionary:[String :String]
    var myThirdDictionary:[String :String]?

    init(){
        var mySecondDictionary:[String :String] = [String :String]()
        mySecondDictionary["animal"] = "Monkey"
        mySecondDictionary.updateValue("something", forKey: "SomeKey")

        self.myFirstDictionary = [String :String]()
        addOneThingToSecondDictionary()
        addAnotherThingToSecondDictionary()

        self.myThirdDictionary! = [String :String]()
        addOneThingToThirdDictionary()
        addAnotherThingToThirdDictionary()
    }

    func addOneThingToSecondDictionary(){
        self.myFirstDictionary["animal"] = "Monkey"
    }

    func addAnotherThingToSecondDictionary(){
        self.myFirstDictionary.updateValue("Superman", forKey: "hero")
    }

    func addOneThingToThirdDictionary(){
        self.myThirdDictionary["animal"]! = "Monkey"
    }

    func addAnotherThingToThirdDictionary(){
        self.myThirdDictionary!.updateValue("Superman", forKey: "hero")
    }

  }

So, I got 3 errors referring to "myThirdDictionary" :

  • In the Dictionary initialization compiler said: Could not find an overload for 'init' that accepts the supplied arguments
  • When I tried to add a Key/value pair in addOneThingToThirdDictionary() : '[String : String]?' does not have a member named 'subscript'
  • When I tried to add a Key/value pair in addAnotherThingToThirdDictionary() : Immutable value of type '[String : String]' only has mutating members named 'updateValue'

Any thoughts ?

like image 273
Sebastian Avatar asked Oct 01 '22 04:10

Sebastian


1 Answers

Some of these issues are conceptual errors, and some of them have to do with behaviors that changed in today's Xcode 6 beta 5 release. Running through them all:

  • This line compiles, but has a superfluous !:

    self.myThirdDictionary! = [String :String]()
    

    You don't need to unwrap an optional to assign to it -- it doesn't matter if its current contents are nil if you're providing new contents. Instead, just assign:

    self.myThirdDictionary = [String :String]()
    
  • Similarly, this line fails because you're subscripting before unwrapping:

    self.myThirdDictionary["animal"]! = "Monkey"
    

    This is a problem because you could be subscripting nil if myThirdDictionary has not been initialized. Instead, subscript after checking/unwrapping the optional. As of beta 5, you can use mutating operators or methods through an optional check/unwrap, so the shortest and safest way to do this is:

    self.myThirdDictionary?["animal"] = "Monkey"
    

    If myThirdDictionary is nil, this line has no effect. If myThirdDictionary has been initialized, the subscript-set operation succeeds.

  • This line failed on previous betas because force-unwrapping produced an immutable value:

    self.myThirdDictionary!.updateValue("Superman", forKey: "hero")
    

    Now, it works -- sort of -- because you can mutate the result of a force-unwrap. However, force unwrapping will crash if the optional is nil. Instead, it's better to use the optional-chaining operator (which, again, you can now mutate through):

    self.myThirdDictionary?.updateValue("Superman", forKey: "hero")
    

Finally, you have a lot of things in this code that can be slimmed down due to type and scope inference. Here it is with all the issues fixed and superfluous bits removed:

class MyClass {

    var myFirstDictionary: [String: String]
    var myThirdDictionary: [String: String]?

    init(){
        var mySecondDictionary: [String: String] = [:]
        mySecondDictionary["animal"] = "Monkey"
        mySecondDictionary.updateValue("something", forKey: "SomeKey")

        myFirstDictionary = [:]
        addOneThingToSecondDictionary()
        addAnotherThingToSecondDictionary()

        // uncomment to see what happens when nil
        myThirdDictionary = [:]
        addOneThingToThirdDictionary()
        addAnotherThingToThirdDictionary()
    }

    func addOneThingToSecondDictionary(){
        myFirstDictionary["animal"] = "Monkey"
    }

    func addAnotherThingToSecondDictionary(){
        myFirstDictionary.updateValue("Superman", forKey: "hero")
    }

    func addOneThingToThirdDictionary(){
        myThirdDictionary?["animal"] = "Monkey"
    }

    func addAnotherThingToThirdDictionary(){
        myThirdDictionary?.updateValue("Superman", forKey: "hero")
    }

}

(Changes: Foundation import unused, empty dictionary literal instead of repeated type info)

like image 139
rickster Avatar answered Oct 17 '22 00:10

rickster