0

I'm trying to cast or convert a dictionary in to an object but I'm not sure how to do it.

This is my class:

import Foundation

class DTOStore: NSObject {

    var _Id: Int64?
    var _StoreId:String?
    var _Name:String?
    var _Address:String?

    var Id: Int64 {
        get {
            return _Id!
        }
        set (pValue) {
            _Id = pValue
        }
    }

    var StoreId:String {
        get {
            return _StoreId!
        }
        set (pValue) {
            _StoreId = pValue
        }
    }

    var Name:String {
        get {
            return _Name!
        }
        set (pValue) {
            _Name = pValue
        }
    }

    var Address:String {
        get {
            return _Address!
        }
        set (pValue) {
            _Address = pValue
        }
    }
}

And I want to do something like this:

let vDTOStore:DTOStore = SQLiteConnectionManager.selectRowDatabase(vCommand, pNumColumns: 4) as! DTOStore

Where the result of SQLiteConnectionManager.selectRowDatabase(vCommand, pNumColumns: 4) is a [String:String] dictionary, taking in consideration that the function will be casted as lot of different objects, that is why it always return a [String:String].

But as you can guess it does not work, and I have no clue on how to do it.

Thanks for the help.

2
  • 3
    Apart from the problem it's absolutely unusual to use backing instance variables in Swift. And why are those instance variables optional? They will never be nil. Commented Apr 20, 2017 at 14:34
  • When would there ever be a store without an id, store id (which is different?), name or address? Commented Apr 20, 2017 at 14:45

3 Answers 3

4

You cannot cast a dictionary to a custom object.
You need to map it by writing an appropriate initializer.

Your object can be reduced to

class DTOStore: NSObject {

    let id: Int64
    let storeId: String
    var name: String
    var address: String

    init(dictionary: [String:String]) {
        self.name = dictionary["name"] ?? ""
        self.storeId = dictionary["storeId"] ?? ""
        self.address = dictionary["address"] ?? ""
        let idString = dictionary["id"] ?? "0"
        self.id = Int64(idString) ?? 0
    }

    var dictionaryRepresentation : [String:String] {
        return ["name" : name, "storeId" : storeId, "address" : address, "id" : "\(id)"]
    }
}

If the keys don't exist the values are set to empty string / 0.
id and storeId are declared as constants (let).


PS: Since the source of the dictionary is a SQL database which will always return all requested fields in all records and if the fields are declared as non-NULL you can even write

    init(dictionary: [String:String]) {
        self.name = dictionary["name"]!
        self.storeId = dictionary["storeId"]!
        self.address = dictionary["address"]!
        self.id = Int64(dictionary["id"]!)
    }
Sign up to request clarification or add additional context in comments.

3 Comments

And there should probably be a reciprocal method that gives you a dictionary representation of DTOStore.
I know it's not your call but I'd also make most of those vars into lets. :D It seems unlikely that the storeId or id will change.
Thanks for the improvements, rmaddy and Fogmeister
3

I will use a struct (but if you prefer a class just replace the struct word with class).

struct DTOStore {
    let id: Int64
    let storeId:String
    let name:String
    let address:String

    init?(dict: [String:String]) {
        guard
            let idString = dict["id"],
            let id = Int64(idString),
            let storeId = dict["storeId"],
            let name = dict["name"],
            let address = dict["address"]
            else { return nil }


        self.id = id
        self.storeId = storeId
        self.name = name
        self.address = address
    }
}

Failable initializer

The DTOStore has a failable initializer.

This is useful when you want initialize an instance of your custom type using a dictionary or a JSON (because there's no guarantee all the required key/values will be there).

If the Failable initializer receives as input a dictionary that does not contains all the expected values, then the instance not created and the initializer returns nil.

More info about this approach here https://developer.apple.com/swift/blog/?id=37

2 Comments

This code is failing to deal with the fact that the id property is of type Int64 but the dictionary contains only strings.
@rmaddy Oops, let me fix it
0

Thanks to all your answers I have ended up doing this:

import Foundation

class DTOStore: NSObject {

    var _Id = Int64()
    var _StoreId = Int64()
    var _Name:String = ""
    var _Address:String = ""
    var _DTOStoreArray = [DTOStore]()

    var Id: Int64 {
        get {
            return _Id
        }
        set (pValue) {
            _Id = pValue
        }
    }

    var StoreId:Int64 {
        get {
            return _StoreId
        }
        set (pValue) {
            _StoreId = pValue
        }
    }

    var Name:String {
        get {
            return _Name
        }
        set (pValue) {
            _Name = pValue
        }
    }

    var Address:String {
        get {
            return _Address
        }
        set (pValue) {
            _Address = pValue
        }
    }

    var DTStoreArrar: [DTOStore] {
        get {
            return _DTOStoreArray
        }
    }

    init(pValue: [String:String]) {
        super.init()
        self._Id = Int64(pValue["Id"]!)!
        self._StoreId = Int64(pValue["StoreId"]!)!
        self._Name = String(pValue["Name"]!)!
        self._Address = String(pValue["Address"]!)!
    }

    init(pArray: [[String:String]]) {
        super.init()
        for vValue in pArray {
            self._DTOStoreArray.append(DTOStore(pValue: vValue))
        }
    }
}

And the call is like this:

let vDTOStore = DTOStore(pValue: SQLiteConnectionManager.selectRowDatabase(vCommand, pNumColumns: 4))

Happy coding.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.