In the prepare segue, I add data to a dictionary in the other controller, here is that dictionary:
var data = [String:String]()
and in prepare segue I add value and key to the dictionary
movieDetail.data.updateValue("title", forKey: self.animationItems[index!].snippet.title)
movieDetail.data.updateValue("description", forKey: self.animationItems[index!].snippet.description)
Is it right?
Then, there is an outlet in the new controller:
#IBOutlet weak var movieTitle: UILabel!
this title should get the value(title) of the dictionary
I did that:
override func viewDidLoad() {
super.viewDidLoad()
movieTitle.text = data[title]?
}
but it shows an error:
Cannot subscript a value of type '[String : String]' with an index of type 'String?'
Could you help me on that?
It should have been:
override func viewDidLoad() {
super.viewDidLoad()
movieTitle.text = data["title"]
}
You should have added the "" to denote a string literal.
Your prepareForSegue is also wrong. The two arguments for updateValue are the other way around. To avoid confusion, you should just always use the dict[key] = value syntax:
movieDetail.data["title"] = self.animationItems[index!].snippet.title
movieDetail.data["description"] = self.animationItems[index!].snippet.description
Anyway, you should use a class/struct to represent your movies, then these problems will go away.
struct Movie {
var title: String
var description: String
}
// in MovieDetailController
var movie: Movie!
// in prepareForSegue
movieDetail.movie = Movie(title: self.animationItems[index!].snippet.title, description: self.animationItems[index!].snippet.description)
// in viewDidLoad
movieTitle.text = movie.title
Related
I have a data model which I made for API returns, it is something like this:
struct VehicleData: Codable {
let _embedded: Embedded
}
struct Embedded: Codable {
let userVehicles: [UserVehicles]
}
struct UserVehicles: Codable {
let id: String
let images: [String]
let userId: String
let vehicle: Vehicle
let originalPrice: OriginalPrice
let hasBasicInsurance: Bool
}
I have used callback function to pass it to my ViewController, now I want to get check in the useVehiclers list, how many vehicles hasBasicInsurance. basically, vehicleList?._embedded.userVehicles[i] = true
this is my function code to use the vehicle data in ViewController:
var vehicleManager = VehicleManager()
var vehicleList: VehicleData?
var i: Int = 0
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
vehicleManager.retrieveUserVehicle()
vehicleManager.onDataUpdate = { [weak self] (data: VehicleData) in
self?.useData(data: data)
}
tableView.dataSource = self
tableView.delegate = self
tableView.tableFooterView = UIView() //remove empty tableView cells
tableView.register(UINib(nibName: Constants.vehicleListCellNibName, bundle: nil), forCellReuseIdentifier: Constants.vehicleListToBeInsuredIdentifier)
}
func useData(data: VehicleData) {
vehicleList = data
// code below has issues....
for i in [vehicleList?._embedded.userVehicles] {
if let vechile = vehicleList?._embedded.userVehicles[i].hasBasicInsurance {
if vehicle == true {
i = i + 1
print(">>number of of insured vehidle: \(i)")
} else {
print(">>>number of of insured vehidle: \(i)")
}
}
}
}
Do you know how to fix it?
You need to supply a default value for optional as a good practise instead of force unwrap
for i in vehicleList?._embedded.userVehicles ?? [] { }
It's not clear from your code, but it looks like vehicleList is optional. It probably should not be (see Leo Dabus's comments). It is rare that it makes sense to have an optional array. That suggests there's some difference between an empty array and a missing array. If there is, then that's fine, but in most cases you should just use a non-optional array and make it empty.
Whether you fix that or not, the solution to this particular problem is to just use a non-optional value, and you have one: data. So change the loop to:
for i in data._embedded.userVehicles { ... }
From your updated question, you note "I want to get check in the useVehiclers list, how many vehicles hasBasicInsurance." It seems you want to put that value in i. If so, that would be:
func useData(data: VehicleData) {
vehicleList = data
i = data._embedded.userVehicles
.filter(\.hasBasicInsurance)
.count
}
You can also use for_each loop for this, for eg like this:
vehicleList?._embedded.userVehicles.for_each(x in /*Do your thing here*/)
Yes, another found nil while unwrapping an Optional value error. I have read tons of other stack overflow posts with similar errors such as this one and many others. I still do not fully understand how to properly deal with unwrapping a variable.
I have a class that is similar to the following:
#IBOutlet weak var nameTextField: UITextField?
#IBOutlet weak var valueInput: UITextField?
var checkbox : CheckBox?
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let name = nameTextField.text ?? ""
let state = buttonState.getIsChecked()
let value : Int? = Int(valueInput.text!)
let isMoveable = true
checkbox = CheckBox(name: name, value: value, state: state, isMoveable: isMoveable)
}
I get the error on the line the "let value : Int? = Int(valueInput.text!) line.
You can safely unwrap the value using if let construct
var value : Int? = nil
if let val = valueInput.text {
value = Int(val) // it would either nil or optional value
}
and also you can do it by nil coalescing operator ?? in a single line
let value : Int? = Int(valueInput.text ?? "")
UPDATE
First check if textfields disconnected from the Interface Builder , if not connect, connect them. and if you become your textfields optionals you also have to safely unwrap the textfields ( you forgot to add it from interface builder and it will not crash if you make them optionals).
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
var name: String? = nil
var value : Int? = nil
let state = buttonState.getIsChecked()
let isMoveable = true
if let nameTextField = self.nameTextField where nameTextField.text != nil {
name = nameTextField.text!
}
if let valueTextField = self.valueInput where valueTextField.text != nil {
value = Int(valueTextField.text!)
}
checkbox = CheckBox(name: name, value: value, state: state, isMoveable: isMoveable)
}
Sahil's answer is on track, but doesn't address that valueInput is also an optional. Use this code:
if let valueInput = valueInput,
let val = valueInput.text {
value = Int(val)
}
In addition regarding properly unwrapping the optional valueInput I wanted to add that chances are that if valueInput is an IBOutlet it's defined as:
#IBOutlet weak var valueInput: UITextField!
That's called an implicitly unwrapped optional. The annoying thing is that since it is also an IBOutlet, if it ever becomes disconnected from the UITextField in Interface Builder, the variable will become nil, and accessing it from anywhere in the code will cause a crash.
Change it to this:
#IBOutlet weak var valueInput: UITextField?
I've also written about this on my blog: http://cleanswifter.com/implicitly-unwrapped-iboutlets/
Note: you didn't show the definition of valueInput so I assumed it to be a UITextField
I have a dummy question...
in one of my ViewController, I set a UILabel text with a String var coming from a singleton:
var nom: String!
var prenom: String!
override func viewDidLoad() {
.....
self.nom = User.sharedInstance.nom
self.prenom = User.sharedInstance.prenom
....
print("User: \(self.nom) - \(self.prenom)")
self.labelWelcome.text = ("Bienvenue \(self.prenom) \(self.nom)")
the print is displaying the right user value, but my View is displaying Bienvenue nil nil....
any idea ?
try this:
if let nom1 = self.nom {
print("User: \(nom1)")
}
Here is my code, I am a beginner using swift and my code does not work, the application should take the value of 'ageInput' textField and multiply it by 7 then show the results inside resultLabel, I always get the error:
Cannot assign a value of type 'int' to a value of type 'String?'
class ViewController: UIViewController {
#IBOutlet weak var resultLabel: UILabel!
#IBOutlet weak var ageInput: UITextField!
#IBAction func findAge(sender: AnyObject) {
var catAge = ageInput.text.toInt() ?? 0
catAge = catAge * 7 ?? 0
resultLabel.text = catAge
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
Where did i go wrong?
Try:
resultLabel.text = String (catAge)
You can also do:
resultLabel.text = "\(catAge)"
here i have tray to solve your problem using example and i hope your issue will solved..
var stringNumber = "1234"
var numberFromString = stringNumber.toInt()
println(numberFromString)
Note toInt():
If the string represents an integer that fits into an Int, returns the corresponding integer.
I'm playing around with the Master-Detail iOS project in Xcode6.01 and Swift. I have a simple data entry screen that adds swift dictionary objects to a Swift datasource array for the table.
The data entry and table view work fine. I've run into this problem when tapping on a cell, extracting a dictionary object from the array and trying to pass that dict object along to the detail view.
The configureView() function in the detail view is causing an exception. Here's the code:
func configureView() {
if let dictObject:Dictionary = detailItem as? Dictionary<String,String> {
if var strName = dictObject["name"] {
// prints fine:
println(strName)
// fatal error
self.detailDescriptionLabel.text = strName
// debug output:
// prints the string in strName (no mention of optional)
// assigning to label:
// fatal error: unexpectedly found nil while unwrapping an Optional value
}
}
}
It seems strange that the println() statement has no problem with the strName variable and there is no mention of it being an optional in the output panel. As soon as it tries to assign the string to the label, bang - crash.
Found the answer my self. It was not the dictionary object that was nil, but the labels in the view!
After adjusting the code with an IF LET construct for the labels it works like this:
func configureView() {
if let dictObject:Dictionary = detailItem as? Dictionary<String,String> {
if let dLabel = detailDescriptionLabel {
dLabel.text = dictObject["name"]
}
if let eLabel = emailLabel {
eLabel.text = dictObject["email"]
}
}
}
I must admit though, I don't know why this is needed. I thought the storyboard would init the labels. The labels in question are regular IBOutlets:
#IBOutlet weak var detailDescriptionLabel: UILabel!
#IBOutlet weak var emailLabel: UILabel!