I'm writing a getter/setter for a class property that uses a struct. This is ultimately parsed from JSON and converted back to JSON in order to store data in the cloud.

// struct:
public struct CompletedTask {
    var uuid: String!
    var amount: Float?
}

// array of completed tasks on the class:
public var completedTasks: [CompletedTask] {
    get {
        var getValue: [CompletedTask] = []
        if let _completedTasks = self["completedTasks"] as? [Dictionary<String, AnyObject>] {
            _completedTasks.forEach({
                getValue.append(CompletedTask(uuid: $0["uuid"], amount: nil))
            })
        }
        return getValue
    }
    set(value) {
        var setValue: [Dictionary<String, AnyObject>]
        value.forEach({
            if let amount = $0.amount where $0.amount != nil {
                setValue.append(["uuid": $0.uuid, "amount": amount])
            } else {
                setValue.append(["uuid": $0.uuid])
            }
        })
        self["completedTasks"] = setValue
    }
}

The setter (I think, although I cannot test) is working fine (it compiles, anyway). But the getter is throwing:

Cannot subscript a value of type '[String : AnyObject]' with an index of type 'String'

What's going on? I think this is a simple fix, but I've tried several different options and it's not working.

3

There are 3 answers

0
ArtSabintsev On

First things first,

if let amount = $0.amount where $0.amount != nil

is redundant, as the optional binding without the where clause guarantees that amount is not nil when the if let condition is satisfied.

As for that message, change AnyObject to Any, as String is a Struct and not a Class. AnyObject only works with classes.

More on Any vs AnyObject can be found here.

1
nshoute On

Sorry to say this, but your code is completely wrong.

It's worthy to note that this code did not compile for me. I'm using Swift 2.0 and xcode 7.2. In addition, there are a few things I'd like to point out.

  1. You shouldn't be writing to your computed property. Look into stored properties instead. https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html#//apple_ref/doc/uid/TP40014097-CH14-ID259

  2. Unless you're extending a dictionary, you can't subscript properties of a class. To access a class's properties within a closure use self.completedTask.

  3. You can't simply cast a collection of a type you created to a collection of dictionaries.

  4. I don't actually see anything converted to JSON. I assume you did this somewhere else in the code.

Under the assumption that you wanted to created a computed property that saves a list of CompletedTasks as a Dictionary and returns a list of CompletedTask objects..

public struct CompletedTask {
    var uuid: String!
    var amount: Float?
}

private var tasks : [[String: AnyObject?]] = []

var completedTasks: [CompletedTask] {
    get {
        var _cT : [CompletedTask] = []

        tasks.forEach({
            _cT.append(CompletedTask(uuid: $0["uuid"] as! String, amount: $0["amount"] as? Float))
        })

        return _cT
    }
    set (value) {
        var _t : [[String: AnyObject?]] = []

        value.forEach({
            _t.append(["uuid": $0.uuid, "amount": $0.amount])
        })

        tasks = _t
    }
}
let task_1 = CompletedTask(uuid: "1", amount: nil)
let task_2 = CompletedTask(uuid: "2", amount: nil)
completedTasks = [task_1, task_2]
print("Completed Tasks \(completedTasks)")
0
brandonscript On

The error was simply due to the fact that I wasn't casting my types in the getter:

getValue.append(CompletedTask(uuid: $0["uuid"], amount: nil))

Should have been:

getValue.append(CompletedTask(uuid: $0["uuid"] as? String, amount: nil))