1
votes

I have an array of AnyObject type like this: [[String : AnyObject]]

animalList = [["name": ABC, "color":red], ["name": DEF, "color": green], ["name": GHI, "color": blue ]]

The model class is like this:

class ModelAnimal {

    var name: String
    var color: String

    init(name: String, color: String){
        self.name = name
        self.color = color 
    }
}

How can I put them in an array of ModelAnimal type:

var myList = Array<ModelAnimal>()

    for var i = 0; i < animalList.count; i++ {

     myList.

    }
4
This code doesn't compile as-is. Are the values ABC and the colors like red Strings? - JAL

4 Answers

5
votes

Use map to create a new array of type [ModelAnimal]:

let animalList: [[String: AnyObject]] = [["name": "ABC", "color":"red"], ["name": "DEF", "color": "green"], ["name": "GHI", "color": "blue"]]

class ModelAnimal {

    var name: String
    var color: String

    init(name: String, color: String){
        self.name = name
        self.color = color
    }
}

let myList = animalList.map { ModelAnimal(name: $0["name"] as? String ?? "", color: $0["color"] as? String ?? "") }

This also makes use of conditional cast as? String along with the nil coalescing operator ?? to safely extract the values from the array of dictionaries and pass them to the constructor for ModelAnimal.

3
votes

1. Struct

First suggestion, use a Struct instead of a Class the model.

Why a Struct?

  1. A Struct does allow you to define a failable init that can return fail without initialising all the stored properties.
  2. A Struct is saved into the Stack Memory of your device that is much faster then the heap.
  3. Finally if the name and color field are not going to change you should really declare them as let. This way you Struct is going to be totally immutable (that is good for several reasons).

2. Failable initializer

Add a failable inititializer to your model that receives optional params

struct ModelAnimal {

    let name: String // you can change this back to var if needed
    let color: String  // you can change this back to var if needed

    init(name: String, color: String){
        self.name = name
        self.color = color
    }

    init?(name: String?, color: String?) {
        guard let name = name, color = color else { return nil }
        self.name = name
        self.color = color
    }
}

3. flatMap

Now you can use the powerful flapMap function

let animals = animalList.flatMap { ModelAnimal(name: $0["name"], color: $0["color"]) }

Why flatMap?

  1. The beauty of flatMap is that it does returns only non nil values. Infact animalList contains unstructured data and you have no guarantee (at least at compile time) that each element has a name and a color key. This way if bad data is contained into animalList it is simply discarded.
  2. Another advantage of flatMap is that it does return an array of ModelAnimal, not ModelAnimal?.
0
votes

The code just iterates over animalList and adds new items to myList:

var myList = Array<ModelAnimal>()

for var i = 0; i < animalList.count; i++ {
    myList.append(ModelAnimal(name: animalList[i]["name"]!, color: animalList[i]["color"]!))
}

It works, however calling append every time isn't good for performance. Better way to achieve this is to create array with needed length:

for var i = 0; i < animalList.count; i++ {
    myList[i] = ModelAnimal(name: animalList[i]["name"]!, color: animalList[i]["color"]!)
}
0
votes

First initialize your ModelAnimal objects, then add them to an array:

let animalOne = ModelAnimal(name: "ABC", color: "red")
let animalTwo = ModelAnimal(name: "DEF", color: "green")
let animalThree = ModelAnimal(name: "GHI", color: "blue")

let myList: Array<ModelAnimal> = [animalOne, animalTwo, animalThree]

You could also do this in-line:

let myList: Array<ModelAnimal> = [ModelAnimal(name: "ABC", color: "red"), ModelAnimal(name: "DEF", color: "green"), ModelAnimal(name: "GHI", color: "blue")]