Home > OS >  How to assign the stringValue coming from QR code scanner to another variable on another class
How to assign the stringValue coming from QR code scanner to another variable on another class

Time:02-05

I am having problems assigning the stringValue from qrcode scanner to a variable on another class.

  1. Scan the QR code
  2. the string from QR code need's to be assigned to id variable of the other class
  3. 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...

  •  Tags:  
  • Related