Search code examples
macoscocoaswiftdictionarykey-value-store

Swift - Working with Dictionaries - Add multiple values


I've been looking for answers to this problem, but unfortunately without success.

I'm developing a mathematical app (Swift-based), which keeps data of every function the user enters.

(I then need to draw the functions on an NSView using a Parser)

The data structure is saved into a Dictionary but I'm not able to add values and keys.

The Dictionary is initialized like:

var functions = [String : [[String : NSBezierPath], [String : NSColor], [String : CGFloat], [String : Bool]]]();

//1A.The String key of the main Dictionary is the value of the function, such as "sin(x)"
//1B.The value of the `Dictionary` is an `Array` od `Dictionaries`

//2.The first value is a dictionary, whose key is a String and value NSBezierPath()
//3.The second value is a dictionary, whose key is a String and value NSColor()
//4.The third value is a dictionary, whose key is a String and value CGFloat()
//5.The first value is a dictionary, whose key is a String and value Bool()

To add the functions, I have implemented a method (I will report a part of) :

...

//Build the sub-dictionaries

let path : [String:NSBezierPath] = ["path" : thePath];
let color : [String:NSColor] = ["color" : theColor];
let line : [String:CGFloat] = ["lineWidth" : theLine];
let visible : [String:Bool] = ["visible" : theVisibility];

//Note that I'm 100% sure that the relative values are compatible with the relative types.
//Therefore I'm pretty sure there is a syntax error.


//Add the element (note: theFunction is a string, and I want it to be the key of the `Dictionary`)

functions[theFunction] = [path, color, line, visible]; //Error here

...

I'm given the following error:

'@|value $T10' is not identical to '(String,[([String:NSbezierPath],[String : NSColor],[String : CGFloat],[String : Bool])])'

I hope the question was enough clear and complete.

In case I will immediately add any kind of information you will need.

Best regards and happy holidays.


Solution

  • Dictionaries map from a specific key type to a specific value type. For example, you could make your key type String and your value type Int.

    In your case, you’ve declared quite a strange dictionary: a mapping from Strings (fair enough), to an array of 4-tuples of 4 different dictionary types (each one from strings to a different type).

    (It’s a new one on me, but it looks like this:

    var thingy = [String,String]() 
    

    is shorthand for this:

     var thingy = [(String,String)]()  
    

    Huh. Strange but it works. Your dictionary is using a variant of this trick)

    This means to make your assignment work you need to create an array of a 4-tuple (note additional brackets):

    functions[theFunction] = [(path, color, line, visible)]
    

    I’m guessing you didn’t mean to do this though. Did you actually want an array of these 4 different dictionary types? If so, you’re out of luck – you can’t store different types (dictionaries that have different types for their values) in the same array.

    (Well, you could if you made the values of the dictionary Any – but that’s a terrible idea and would be nightmare to use)

    Probably the result you wanted was this (i.e. make the functions dictionary map from a string to a 4-tuple of dictionaries of different types):

    var functions = [String : ([String : NSBezierPath], [String : NSColor], [String : CGFloat], [String : Bool])]()
    

    You’d assign values to the dictionary like this (note, no square brackets on the rhs):

    functions[theFunction] = (path, color, line, visible)
    

    This will work but it will be pretty unpleasant to work with. But do you really want to store your structured data in dictionaries and arrays? This isn’t JavaScript ;-) You’ll tie yourself in knots navigating that multi-level dictionary. Declare a struct! It’ll be so much easier to work with in your code.

    struct Functions {
        var beziers: [String:NSBezierPath]
        var color: [String:NSColor]
        var line: [String:NSColor]
        var floats: [String:CGFloat]
        var bools: [String:Bool]
    }
    var functions: [String:Functions] = [:]
    

    Even better, if all the beziers, colors etc are supposed to be references with the same key, declare a dictionary that contains all of them or similar.