I'm currently working on the currency rates app. I have a main
ViewController which has a UILabel which presents parsed rate for selected currencies. Also, there is a button which is used for changing one of the currency rates in order to get a new rate (second
ViewController is presented with N tableView cells).
I have some troubles with transferring data of new selected value to the main
ViewController. When I select a new rate, I get this error for UILabel:
Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
I guess I know how to fix it - create a variable inside main
and set its value inside second
viewcontroller, but i don't know how do it properly. Here is my code. Thanks in advance.
class MainVC: UITableViewController {
var convertedValue: String = ""
// some stuff
func parseCurrency(top: String) {
let URL_Exchange = URL(string: "MY URL\(top)")!
let task = URLSession.shared.dataTask(with: URL_Exchange) {(data, response, error) in
guard let data = data else { return }
let queue = DispatchQueue(label: "result")
queue.async {
let JSON = String(data: data, encoding: .utf8)
let jsonData = JSON!.data(using: .utf8)!
let result: Rates = try! JSONDecoder().decode(Rates.self, from: jsonData)
let currencies = result.conversion_rates?.dictionary
var doubleVar:Double = 0
for item in currencies! {
if (item.key == self.BottomCurrency.sublabel) {
doubleVar = item.value as! Double
}
}
// this value is the text to print inside "Result" Label
let mult = Double(round(10000*doubleVar * self.InputText)/10000)
self.convertedValue = String(mult)
DispatchQueue.main.async {
if self.convertedValue == "0" {
self.Result.text = String(0)
} else {
// Here I get an error
self.Result.text = self.formatNumber(num: Double(self.convertedValue))
}
}
}
}
task.resume()
}
Code for second
VC:
class SecondVC: UITableViewController {
private var temp: Int = 0
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
if isBeingDismissed {
// updating temp value...
let vc = storyboard!.instantiateViewController(withIdentifier: "main") as! MainVC
vc.parseCurrency(top: Currencies[temp].short)
// or to call vc.convertedValue = something
// vc.parseCurrency(...)
}
}
If I had to guess, the reason that your code is crashing is that the property Result
you are calling on a freshly created instance of main
view controller, is actually an IBOutlet
pointing to a UILabel!
which is not yet created.
There is a great amount of resources available on the internet on passing data between view controllers so I am pointing you towards already existing post with huge amount of answers: Passing data between view controllers
However, I will describe one of the available ways to solve it below
One way to solve it would be to use a "traditional" UIKit pattern which is Delegation
.
You simply create a protocol, that will enable a way for the secondVC
communicate with mainVC
protocol SecondVCDelegate: AnyObject {
func secondVCDidSelect(currency: String)
}
Then you add a weak
property on the secondVC
class SecondVC: UITableViewController {
weak var delegate: SecondVCDelegate?
// ...
}
And now you should be able to pass any value you want to the delegate. For the sake of the example, you could do it on the didSet
observer of the temp
property
class SecondVC: UITableViewController {
private var temp: Int = 0 {
didSet {
delegate?.secondVCDidSelect(currency: Currencies[temp].short)
}
}
weak var delegate: SecondVCDelegate?
}
Personally I would call the delegate the moment user is selecting the value, and not store it in the
temp
property
the only thing missing is setting a mainVC
as the delegate of the secondVC
and conforming to the protocol. Perfect place to do it is at the moment you are presenting the secondVC
from mainVC
let viewController: SecondVC = // init SecondVC or load from storyboard
viewController.delegate = self
// present secondVC
extension MainVC: SecondVCDelegate {
func secondVCDidSelect(currency: String) {
parseCurrency(top: currency)
}
}
I encourage you to read more about Delegation since this is a very popular pattern in the iOS development
Delegation in Swift by John Sundell