1

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?

2
  • 1
    step is an optional, too, so you have to unwrap it before using it. Commented Nov 19, 2018 at 19:56
  • 1
    Also, why not use a table view? Commented Nov 19, 2018 at 20:16

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

2 Comments

thanks a lot! it helped! One more question - how would you advice to go with label + text? Are there some good practices?
When adding a series of subviews, a table view or collection view is great when it's an arbitrarily long list. If you know it won't exceed a certain number that can be shown at a given time, a stack view is good. Regarding the text view and label combination, the question is what is the purpose of the label. If it's to show some text until the user enters something, then use placeholder text in the text field and eliminate the label entirely. If you want to see the label and the text field at the same time, you probably just don't put them on top of each other, i.e. adjust their frames.

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.