尝试从不同的Swift类调用方法
我有两个swift类,在其中一个类中,我需要引用另一个swift类中的方法。两个各自的视图控制器都连接到一个尝试从不同的Swift类调用方法,swift,xcode,uitabbarcontroller,Swift,Xcode,Uitabbarcontroller,我有两个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
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
包含我希望调用的方法。而地图视图
是选项卡
上的第二个选项,因此索引为1。但是,当我强制转换对象mapVC
时,我得到了错误[致命错误:在展开可选值时意外发现nil]
。我相信这个问题与创建一个实例mapVC
有关,我相信我可能没有正确设置它,但我不确定如何修复它
我不太清楚如何表达我的问题,因此如果您仍然感到困惑,我可以在评论中提供更多信息。实现这一点的两种方法是通过委派或通知。在您的情况下,我认为您应该查看通知并在收到通知后调用
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()
您可以使用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()中注册要接收通知的类的通知。我通常使用自定义的
tabBarController
作为每个选项卡的委托,但我非常喜欢您访问堆栈中ViewController
的方法。让我们看看你的版本有什么问题
试着像这样运行它
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
属性将根据设置为零
如果视图控制器未嵌入选项卡栏控制器中,则此属性为nil
一种解决方案是根据此图将tabBarController
的引用从vc2
传递到vc3
[tabBarController]
| |
[vc1] [vc2] - both have a reference to tabBarController
|
[vc3] - no reference yet
设置vc3
以保持选项卡栏引用
-最好为此创建一个新的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)
}
}
我还没有测试过这段代码,但它在理论上应该可以工作,让我知道你进展如何。我会先将这个安全阵列扩展添加到你的项目中
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)
很可能您调用此方法的时间太早了。听起来好像选项卡栏或控制器未加载。作为最后手段,请尝试在ViewWillDisplay或ViewDidDisplay中打电话。您能进一步解释什么是通知以及我如何实现此功能吗?@Kevin我已编辑了我的回复,其中包括一个示例,您可以在操场上进行测试。我喜欢通过通知传递信息的概念。您的代码已经在操场上运行了,但是当我尝试将其实现到我的文件中时,它给了我一系列错误(必需的初始值设定项init(coder)必须由UIViewController的子类提供)。与操场相比,实施方式不同吗?@Kevin正确,这是不同的。我刚刚制作了两个类,而不是视图控制器。正如我在编辑中所说,如果您没有使用视图控制器进行任何奇特的初始化,您应该在
viewdiload
中移动寄存器代码。我在代码中实现了这一点,它返回“找不到选项卡栏”。这就是我所认为的问题所在,但这很奇怪,因为我的视图控制器是在tabBarController中构造的。你知道怎么回事吗?@Kevin你是如何将ViewController添加到选项卡栏的?我设置选项卡栏的方式是最初使用默认设置(2个选项卡),然后我在底部添加了一个选项卡项,该选项卡项与第三个视图控制器相连。这回答了你的问题吗?如果你需要更多的信息,我很乐意提供!我认为我的问题是,我正在使用的viewController底部没有选项卡栏。因此,我试图将信息从常规的viewController发送到tabBarController。我已经更新了答案,我认为Swift 3具有不同的prepare for segue方法实现。。可能值得自动填充以确保其正确。。你可以随意命名你的序列。