I am having problems assigning the stringValue from qrcode scanner to a variable on another class.
- Scan the QR code
- the string from QR code need's to be assigned to id variable of the other class
- perform a segue to that class's viewController
So i created a init on the other class where the variable id is and assigned it to temp as you can see but still the temp is not being assigned to the id variable and when i execute the code it gets error nil to the variable id...?
Class: QRScannerController
if metadataObj.stringValue != nil {
let destVC = MonitorimiViewController(temp: metadataObj.stringValue!)
destVC.id = metadataObj.stringValue!
do {
guard let tabBarController = self.storyboard?.instantiateViewController(withIdentifier: "tabBarController") as? UITabBarController else {
return
}
(tabBarController.viewControllers![0] as? MonitorimiViewController)?.id = metadataObj.stringValue!
tabBarController.modalTransitionStyle = .crossDissolve
tabBarController.modalPresentationStyle = .custom
self.present(tabBarController, animated: true, completion: nil)
}
}
captureSession.stopRunning()
}
Class: MonitorimiViewController
init(temp : String){
id = temp
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
var id:String?
func fetchAndReloadData(){
APICaller.shared.getVehicles(for: id!) {[weak self] (result) in // error nil value at id!
guard let self = self else { return }
switch result {
case .success(let vehicle):
self.listOfVechicle = vehicle
DispatchQueue.main.async {
self.monitorimiTableView.reloadData()
}
case .failure(let error):
print(error)
}
}
}
For any clarifications please feel free to ask because I have been stuck with this problem for days :(
CodePudding user response:
If you can't debug yourself (experience will be earned later), never write this kind of code:
(tabBarController.viewControllers![0] as? MonitorimiViewController)?.id = metadataObj.stringValue!
So, what does it says:
tabBarController.viewControllers!: If there is no viewControllers: crash.
(... as? SomeClass): If it's not of that class (or compliant to the protocol, or a subclass, etc.), the cast will fail, and it will be nil.
So in your case, it's:
(someNilValue)?.id = someId
So, nothing gets someId.
How to know that by yourself:
guard let viewcontrollers = tabBarController.viewControllers else {
print("tabBarController.viewControllers is nil")
return
}
guard let firstVC = viewControllers.first else {
print("viewControllers is empty")
return
}
guard let asMonitorimiVC = firstVC as? MonitorimiViewController else {
print("firstVC is NOT a MonitorimiViewController instance: \(firstVC)") //by default, you should see its type in console, by you could also use type(of:)
return
}
asMonitorimiVC.id = someId
Yours should then fail at guard let asMonitorimiVC, because firstVC is a UINavigationController.
guard let asNavigationVC = firstVC as? UINavigationController else {
print("firstVC is NOT a UINavigationController instance: \(firstVC)") //by default, you should see its type in console, by you could also use type(of:)
return
}
guard let firtVCFromNavVC = asNavigationVC.viewcontrollers.first else {
print("asNavigationVC.viewcontrollers is empty") //But that shouldn't be the case, I used viewcontrollers, but you could also use topViewController in this case
return
}
guard let asMonitorimiVC = firtVCFromNavVC as? MonitorimiViewController else {
print("firtVCFromNavVC is NOT a MonitorimiViewController instance: \(firstVC)") //by default, you should see its type in console, by you could also use type(of:)
return
}
asMonitorimiVC.id = someId
Of course, that's a verbose solution, you might want to cut it a little, but when debugging, do not hesitate to make explicit code:
guard let navVC = tabBarController.viewControllers?.first as? UINavigationController else {
print("tabBarController.viewControllers is nil or empty, or the first of it is not a UINavigationController")
return
}
guard let asMonitorimiVC = navVC.viewControllers.first as? MonitorimiViewController else {
print("navVC.viewControllers is empty, or its first is not a is NOT a MonitorimiViewController instance: \(navVC.viewControllers.first)")
return
}
Side note: You might notice, that if you had answered correctly my first question in comment in your previous question, we would have spotted directly the issue:
Is
(tabBarController.viewControllers![0] as? MonitorimiViewController)nil?
Because print("Is it nil: (tabBarController.viewControllers![0] as? MonitorimiViewController))` should show that's it's in fact nil, since the cast fails...
