两个容器视图之间的委派

时间:2016-01-22 02:28:11

标签: ios swift delegates protocols

我尝试通过委托Container ViewsSwift之间发送信息,并且当我继续解包错误时执行协议功能。

my story board layout

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
    }
}

问题

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

4 个答案:

答案 0 :(得分:2)

您的代码存在问题:

  • 您从未在self
  • 中将代理人设置为BottomContainerViewController
  • 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
    }
}

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

Download Working Example

答案 1 :(得分:2)

我假设你在View A中有两个容器视图,所以请看看:

一种更容易(也更方便?)的方式是A将在您的Container View B& D之间进行通信。 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& S的代表。 C和逆。

我们假设您希望B告知C有关某事的内容:

  1. B将通过协议通知A,因为A符合它
  2. A将与他自己的代表一起发送信息给C
  3. 查看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) - >无或代表

答案 2 :(得分:0)

DUDE你错过了一步:

  1. 您创建了协议。
  2. 创建协议的对象 topContainerViewController
  3. 实施协议 bottomContainerViewController
  4. 太酷了..

    但是你在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)
    

    希望你得到它:)

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

答案 3 :(得分:-1)

检查代表的值是否为nil!

更改

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

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