I have two swift classes and in one, I need to refer to a method in the other swift class. Both of the respective view controllers are attached to a tabBarController, so I tried to create an instance like such:
let mapVC : MapVC = self.tabBarController!.viewControllers![1] as! MapVC
mapVC.loadViewIfNeeded()
mapVC.add(newLocation:location_one) // .add is the method I want to call
Where MapVC holds the method I wish to call. And the mapView is the second option on the tabBar, hence the index of 1. However, I get the error [fatal error: unexpectedly found nil while unwrapping an Optional value] when I cast the object mapVC. I believe the problem has something to do with creating an instance mapVC, and I believe I may not have set it up properly, but I am not sure how to fix it.
I am not quite sure how to phrase my problem so if you are still confused, I can provide more information in the comments.
I normally do this with a custom tabBarController as the delegate for each tab, but I quite like your method of accessing the viewControllers in the stack. let's figure out whats wrong with your version.
Try running it like this
if let tC = self.tabBarController {
if let vcs = tC.viewControllers {
if let map = vcs[1] as? MapVC {
print("map vc found in stack")
map.loadViewIfNeeded()
map.add(newLocation:location_one)
} else {
print("no map vc found at index 1")
}
} else {
print("no stack found")
}
} else {
print("no tab bar found")
}
This might help us debug whats up with your code, are you sure it's the mapVC that is returning nil?
Edit: As you described in the comments, if you are segueing away from the tabBarController then the newly presented viewController's tabBarController property will be nil as per Apple Docs.
This property is nil if the view controller is not embedded inside a tab bar controller.
One solution would be to pass a reference of the tabBarController to vc3 from vc2 as per this diagram.
[tabBarController]
| |
[vc1] [vc2] - both have a reference to tabBarController
|
[vc3] - no reference yet
Setup vc3 to hold the tabBar reference
- It's probably best to create a new var for this instead of using the existing tabBarController property.
class vc3:UIViewController {
var tabBarReference:UITabBarController?
func addALocation(location:CLLocationCoordinate2D) {
if let tbc = self.tabBarReference {
if let map = tbc.viewControllers[1] as? MapVC {
map.loadViewIfNeeded()
map.add(newLocation:location)
}
}
}
}
Then inside vc2 use the prepare for segue method to access vc3 and give it the reference before it is presented.
class vc2:UIViewController {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc3 = segue.destinationViewController as? vc3
vc3.tabBarReference = self.tabBarController
}
}
func goToVC3() {
self.performSegueWithIdentifier("goToVC3", sender: nil)
}
}
I have not tested this code, but it should work in theory, let me know how you get on.
I would add this safe array extension to your project first...
extension Collection where Indices.Iterator.Element == Index {
/// Returns the element at the specified index iff it is within bounds, otherwise nil.
subscript (safe index: Index) -> Generator.Element? {
return indices.contains(index) ? self[index] : nil
}
}
Then... I would check if your view controller exists like this...
guard let mapVC : MapVC = self.tabBarController?.viewControllers?[safe: 1] as? MapVC else {
print("could not find mapVC")
return
}
mapVC.loadViewIfNeeded()
mapVC.add(newLocation:location_one)
Chances are that you are probably calling this method too soon. Sounds like either the tab bar or the controllers are not loaded. Try calling in in viewWillAppear or viewDidAppear as a last resort.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With