Anna F
Anna F

Reputation: 1683

Declare array as property of class and use it in Swift

I have a cooking app, where I have meal with name, and cooking steps, which are presented as an array of strings:

class Meal {    
    var name: String
    var steps: Array<String>?
}

And then I try to pass the data to view:

override func viewDidLoad() { 
    super.viewDidLoad()

    // Handle the text field’s user input through delegate callbacks.
    nameTextField.delegate = self

    // Set up views if editing an existing Meal.
    if let meal = meal {
        nameTextField.text = meal.name
    }
    createLabelAndText()
}

The createLabelAndText method should create for each element of an array label - something like Step 1, Step 2 and textView

  func createLabel() {

        for (index, element) in (meal?.steps){
            let myLabel = UILabel()

            //Assigning value or text to label
            myLabel.text = "Step \(index)"

            //Assigning frame to the label
            myLabel.frame = CGRect(x: 10, y: index*100, width: 200, height: 30)

            let textView = UITextView()
            textView.text = element
            textView.frame = CGRect(x: 10, y: index*100, width: 200, height: 30)

            //Finally we need to add label to view to display it on screen.
            self.view.addSubview(myLabel)
            self.view.addSubview(textView)
        }
    }

And what I want to get is something like this: [http://a1.mzstatic.com/us/r30/Purple30/v4/24/3e/64/243e64b5-79cf-9a35-5386-d81ed250b926/screen696x696.jpeg][1]

Right now I have a problem - I can't loop trough meal?.steps and get the error Type '[Any]?' does not conform to protocol 'Sequence'

Also I try to configure a view controller before it's presented. But it doesn't allow me to access and assign steps from class meal.

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    super.prepare(for: segue, sender: sender)
    let name = nameTextField.text ?? ""
    let steps = meal?.steps
    // Set the meal to be passed to MealTableViewController after the unwind segue.
    meal = Meal(name: name, steps: steps )

}

How could I solve this problems or maybe there are some better approaches?

Upvotes: 1

Views: 60

Answers (1)

Rob
Rob

Reputation: 437452

You need to unwrap steps, because not only is meal an optional, but so is steps. E.g.

func createLabel() {
    guard let steps = meal?.steps else { return }

    for (index, element) in steps.enumerated() {
        let label = UILabel()

        //Assigning value or text to label
        label.text = "Step \(index)"

        //Assigning frame to the label
        label.frame = CGRect(x: 10, y: index*100, width: 200, height: 30)

        let textView = UITextView()
        textView.text = element
        textView.frame = CGRect(x: 10, y: index*100, width: 200, height: 30)

        //Finally we need to add label to view to display it on screen.
        view.addSubview(label)
        view.addSubview(textView)
    }
}

Obviously, if you want the index as you enumerate through steps, you need to use enumerated(), too.

As an aside, I'm not sure why you're setting your text view to have the same frame as the label, effectively putting it on top of the label, but that's beyond the scope of this question. The main issue here is just to make sure you unwrap your steps optional before trying to use it.

Upvotes: 2

Related Questions