Reputation: 1683
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
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