我有两个swift类,在一个中,我需要引用另一个swift类中的方法。两个相应的视图控制器都附加到tabBarController
,因此我尝试创建这样的实例:
let mapVC : MapVC = self.tabBarController!.viewControllers![1] as! MapVC
mapVC.loadViewIfNeeded()
mapVC.add(newLocation:location_one) // .add is the method I want to call
其中MapVC
包含我想要调用的方法。并且mapView
是tabBar
上的第二个选项,因此索引为1.但是,当我转换对象[fatal error: unexpectedly found nil while unwrapping an Optional value]
时,我收到错误mapVC
。我认为问题与创建实例mapVC
有关,我相信我可能没有正确设置它,但我不确定如何解决它。
我不太确定如何表达我的问题所以如果您仍然感到困惑,我可以在评论中提供更多信息。
答案 0 :(得分:3)
我通常使用自定义tabBarController
作为每个标签的委托来执行此操作,但我非常喜欢您访问堆栈中viewControllers
的方法。让我们弄清楚你的版本有什么问题。
尝试像这样运行
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")
}
这可能有助于我们使用您的代码调试最新情况,您确定mapVC
正在返回nil
吗?
修改:正如您在评论中所述,如果您偏离tabBarController
,那么新呈现的viewController的tabBarController
属性将为零每Apple Docs。
如果视图控制器未嵌入标签栏控制器中,则此属性为nil。
根据此图,一种解决方案是将tabBarController
的引用从vc3
传递给vc2
。
[tabBarController]
| |
[vc1] [vc2] - both have a reference to tabBarController
|
[vc3] - no reference yet
设置vc3
以保留tabBar参考
- 最好为此创建一个新的var,而不是使用现有的tabBarController
属性。
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)
}
}
}
}
然后在vc2
内使用prepare for segue方法访问vc3
并在呈现之前为其提供参考。
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)
}
}
我没有测试过这段代码,但它应该在理论上有用,让我知道你是怎么做的。
答案 1 :(得分:1)
我会首先将这个安全数组扩展添加到您的项目中......
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
}
}
然后......我会检查你的视图控制器是否像这样......
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)
有可能你很快就会调用这种方法。听起来像标签栏或控制器没有加载。尝试在viewWillAppear或viewDidAppear中调用作为最后的手段。
答案 2 :(得分:0)
实现此类目标的两种方法是通过委托或通知。在您的情况下,我认为您应该查看通知并在通知后调用add(newLocation:)
函数。
下面是一个类在另一个类中调用函数的快速示例。你可以将它扔进游乐场,看看它是如何工作的。
对于视图控制器,您通常会开始观察viewDidLoad
上的事件,但根据您的课程结构,其他地方可能更适合。
class MapVC {
init() {
print("Adding self as observer now...")
NotificationCenter.default.addObserver(self, selector: #selector(add), name: NSNotification.Name.init("addNewLocation"), object: nil)
}
@objc func add(notification: Notification) {
guard let location = notification.object as? CLLocation else {
return print("Did not recieve a CLLocation object in notification")
}
print("Got location with lat: \(location.coordinate.latitude), and lon:\(location.coordinate.longitude)")
// your code for handling the addition of a new location
}
}
class OtherVC {
func add() { // however you're calling this function... you might be passing in a location here, but for demonstration, just creating a new one
let location = CLLocation(latitude: 100, longitude: 100)
NotificationCenter.default.post(name: NSNotification.Name.init("addNewLocation"), object: location)
}
}
let mapVC = MapVC()
let otherVC = OtherVC()
otherVC.add()
答案 3 :(得分:0)
您可以使用NotificationCenter执行此操作。 您需要在要接收通知的类中注册通知侦听器并执行操作。然后,您需要发布其他类的通知。你可以这样做:
// Define identifier
let notificationName = Notification.Name("MyNotification")
// Register to receive notification
NotificationCenter.default.addObserver(self, selector: #selector(methodToCallWhenReceivingNotification), name: notificationName, object: nil)
// Post notification
NotificationCenter.default.post(name: notificationName, object: nil)
通常,您应该在要接收它的类的viewDidLoad()中注册通知。