两个容器视图之间的委派

我正在尝试通过委托Swift两个Container Views之间发送信息,并且在执行协议function时我不断出现解包错误

我的故事板布局

topContainerViewController.swift

 import UIKit protocol topContainerDelegate{ func send(text:String) } class topContainerViewController: UIViewController { var delegate: topContainerDelegate! = nil @IBOutlet var textField: UITextField! override func viewDidLoad() { super.viewDidLoad() } @IBAction func sendMessage(sender: AnyObject) { delegate!.send(textField.text!) } } 

bottomContainerViewController.swift

 import UIKit class bottomContainerViewController: UIViewController, topContainerDelegate { @IBOutlet var messageLabel: UILabel! override func viewDidLoad() { super.viewDidLoad() } func send(text: String) { messageLabel.text = text } } 

如何在两个容器视图之间正确设置委派?

您的代码的问题是:

  • 你从来没有在BottomContainerViewController你的委托设置为self
  • 在您的TopContainerViewController您将委托的初始值设置为nil,只需将其保留为可选项并使用保护程序将其解包。

这适用于我的测试应用程序:

 protocol TopContainerDelegate : class { func send(text:String) } class TopContainerViewController: UIViewController { @IBOutlet weak var textField: UITextField! weak var delegate : TopContainerDelegate? @IBAction func sendMessage(sender: UIButton) { guard let delegate = delegate else { return } delegate.send(textField.text!) } override func viewDidLoad() { super.viewDidLoad() } } class BottomContainerViewController: UIViewController, TopContainerDelegate { @IBOutlet weak var messageLabel: UILabel! override func viewDidLoad() { super.viewDidLoad() let app = UIApplication.sharedApplication().delegate! as! AppDelegate if let viewControllers = app.window?.rootViewController?.childViewControllers { viewControllers.forEach { vc in if let cont = vc as? TopContainerViewController { cont.delegate = self } } } } func send(text:String) { messageLabel.text = text } } 

如果您有任何其他问题,请随时下载我的工作项目并自行测试。

下载工作示例

我假设你在View A中有两个容器视图,所以检查一下:

一个更容易(也更方便?)的方式是A会在你的容器视图B&C之间进行通信。这样,你不必通过整个应用来设置委托,也应该有一个委托。如果您的应用程序真的很大,性能会更好。

查看A:

 @objc protocol InformContainerDelegate{ optional func notifyB() optional func notifyC() } var bDelegate: InformContainerDelegate var cDelegate: InformContainerDelegate override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { if segue.identifier == "toContainerB"{ let controller = segue.destinationViewController as! ContainerBViewController controller.delegate = self // A receives notifications from B self.bDelegate = controller // sending information from A to B } else if segue.identifier == "toContainerC"{ let controller = segue.destinationViewController as! ContainerCViewController controller.delegate = self // A receives notifications from C self.cDelegate = controller // sending information from A to C } } 

A现在是B&C和反向的代表。

让我们假设您希望B告知C关于某些事情:

  1. B将通过协议通知A,因为A符合协议
  2. A将与他自己的代表一起发送信息给C

查看B:

 protocol BChangedSomethingDelegate{ func informC() } class B : UIViewController // or whatever { //... usual methods func BDidSomething(){ delegate?.informC!() } } 

现在你需要使A符合B“BChangedSomethingDelegate”的协议:

 extension A: BChangedSomethingDelegate { func informC!(){ cDelegate!.notifyC!() } } 

对于C,您还必须实现一个协议,然后A将符合它。 致力于该解决方案,它的工作非常好。

额外提示:设置断点以测试A,B和C是否是相应的代表,在断点期间直接在日志中按“po xxx”,同时应用程序被断点停止以检查xxx是什么。

示例:(po cDelegate) – > Nil或委托

DUDE你错过了一步:

  1. 你创建了协议。
  2. 在topContainerViewController中创建协议的对象
  3. 在bottomContainerViewController中实现协议

这很酷..

但是你在topContainerViewController的实例中指定了委托的地方是bottomContainerViewController的实例???

你错过了一个步骤:你没有分配对象来委托topContainerViewController实例的对象SO YOU GOT ERROR这意味着你没有指定谁响应任何来自该对象的委托函数调用的调用???? 如果你没有给出谁回应它,那么很明显你会得到错误。 既然,我没有发现你已经创建了topContainerViewController的实例,我想你是通过使用segue做的。

当您创建topContainerViewController的实例时,您需要指定委托变量。 如果你转到topContainerViewController on button on bottomContainerViewController然后获取bottomContainerViewController的实例并将self分配给委托:

如果你通过segue做:给这里的segue标识符我给了“openTopContainerViewController”现在覆盖bottomContainerViewController中的prepareforsegue函数

 override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { if segue.identifier == "openTopContainerViewController" { let instanceOfTopContainerViewController = segue.destinationViewController as! topContainerViewController //######## HERE IS THE PROBLEM . YOU DIDN"T ASSIGN ANYTHING TO delegate variable so It became always nil to avoid it you need to assign like below instanceOfTopContainerViewController.delegate = self } } 

如果你通过代码转到topContainerViewController:这样做:(按下这个代码按下按钮或每当你触发打开topContainerViewController)

 //First you need to give storyboard id to view controller associated with topContainerViewController then let storyBoard = UIStoryboard(name: "Main", bundle: nil) let instanceOfTopViewController = storyBoard.instantiateViewControllerWithIdentifier("topContainerViewControllerIdentified") as! topContainerViewController //######## HERE IS THE PROBLEM. YOU DIDN"T ASSIGN ANYTHING TO delegate variable so It became always nil to avoid it you need to assign like below instanceOfTopViewController.delegate = self self.presentViewController(instanceOfTopViewController, animated: true, completion: nil) 

希望你得到它:)

这是问题所在。 你没有指定任何委托变量所以它总是为零避免你需要像上面那样分配

检查代表的价值为零!

更改

 @IBAction func sendMessage(sender: AnyObject) { delegate!.send(textField.text!) } to @IBAction func sendMessage(sender: AnyObject) { if let delegate = delegate { delegate.send(textField.text!) } }