导航堆栈之前的视图之间的协议委托

Protocol delegate between view before navigation stack

View1 转至 Navigation Controller - View2 转至 View3

我正在尝试创建从 View3 到 View1 的协议委托

在视图 1 中

class NormalUser: UIViewController, NormalUserDelegate {

    @objc func showAddressView() {
        addressView.isHidden = false
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        if let conn = self.storyboard?.instantiateViewController(withIdentifier: "View") as? View
        {
            conn.delegate = self
        }
    }
}

在视图 3 中

weak var delegate: NormalUserDelegate?

func test() {

self.delegate?.showAddressView()

}

协议

protocol NormalUserDelegate: class {
    func showAddressView()
}

我无法让它工作。有什么想法吗?

如果我对您的方案的理解正确,您需要两个委托,每个委托将数据传回前一个 UIViewController。据我所知,您不能绕过辅助 UIViewController。

您缺少的是路由器 class,这是我将如何实现它的一个简单示例。


protocol RoutingView1{
func openView2()
}

protocol RoutingView2{
func openView3()
}

protocol RoutingView3{
func foo()
}

class View1{

func foo(){
//this will get called when View3 calls its RootingView3.foo()
}
}

class Router: RoutingView1, RoutingView2{

var rootView: View1

func start() -> UIViewController{
view.routingDelegate = self
rootView = view1
}

func openView2(){
let vc = View2()
vc.routingDelegate = self
rootView.push()
}

func openView3(){
let vc = View3()
vc.routingDelegate = self
rootView.push()
}

func foo(){
rootView.foo()
}

在我看来,您有 2 个不错的选择来使用委托模式。 1 个糟糕的选项可以工作,但它很笨拙和懒惰,然后你就有了广播接收器模式。

2 个不错的选择

1 - 向前传递委托

class VC1: UIViewController, SomeDelegate {

    func delegateFunction() {}

    func showNextVC() {
        let next = VC2()
        next.forwardingDelegate = self
        present(next, animated: true)
    }
}

class VC2: UIViewController {
    var forwardingDelegate: SomeDelegate? = nil

    func showNextVC() {
        let next = VC3()
        next.delegate = forwardingDelegate
        present(next, animated: true)
    }
}

2 - 将第三个控制器传递给第二个控制器


class VC1: UIViewController, SomeDelegate {

    func delegateFunction() {}

    func showNextVC() {
        let final = VC3()
        final.delegate = self

        let next = VC2(withControllerToPresent: final)
        present(next, animated: true)
    }
}

class VC2: UIViewController {
    let controller: UIViewController

    init(withControllerToPresent controller: UIViewController) {
        self.controller = controller
        super.init(withNibName: nil, bundle: nil 
    }

    func showNextVC() {
        present(controller, animated: true)
    }
}

class VC3: UIViewController { 
    var delegate: SomeDelegate? = nil
}

1 个糟糕的选择

使用 singleton/global 变量....(请不​​要)

个人意见

我已经完成了前两个选项...它们有效。但是广播接收器模式可能更好,因为它会更干净。 VC2 不需要将任何内容转发给 3。只需确保将通知命名空间足够具体,以免以后被其他任何内容捕获。

解除 Segues

如果您使用的是界面生成器,则可能 easiest/cleanest 使用展开转场。

  1. 在 VC1 中创建界面生成器操作:

    class VC1: UIViewController {
    
        @IBAction func backToVC1(_ segue: UIStoryboardSegue) {
            self.showAddress()
        }
    
        func showAddress() {
            addressView.isHidden = false
        }
    }
    
  2. 在您的 VC3 故事板中,按住 Control 键并单击视图控制器图标,将鼠标拖到退出图标上并松开。单击 select 您在 VC1 中创建的 unwind segue。

  3. 在文档大纲中创建 segue select 后。

  4. 并在属性检查器中命名。

  5. 最后,在您的 VC3 代码中调用 segue。

    class VC3: UIViewController {
    
        func test() {
            self.performSegue(withIdentifier: "unwindToVC1", sender: self)
        }
    }
    

我认为您可以使用 SwiftEventBus 来应对这种情况。 Link

示例:

@IBAction func clicked(sender: AnyObject) {
     count++
     SwiftEventBus.post("doStuffOnBackground")
 }

 @IBOutlet weak var textField: UITextField!

 var count = 0

 override func viewDidLoad() {
     super.viewDidLoad()

     SwiftEventBus.onBackgroundThread(self, name: "doStuffOnBackground") { notification in
         println("doing stuff in background thread")
         SwiftEventBus.postToMainThread("updateText")
     }

     SwiftEventBus.onMainThread(self, name: "updateText") { notification in
         self.textField.text = "\(self.count)"
     }
}

//Perhaps on viewDidDisappear depending on your needs
override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    SwiftEventBus.unregister(self)
}
**Just set delegate of view 2 as a delegate of view 3 as below:**

 class View1: UIViewController, NormalUserDelegate {

       @objc func showAddressView() {

            addressView.isHidden = false
        }
    // Going to view 2 by any means i.e segue , navigation set  
       func goToView2Controller(){
         if let view2 = self.storyboard?.instantiateViewController(withIdentifier: "View2") as? View2
            {
              view2.delegate = self
            }
        self.navigationController?.pushViewController(view2, animated: true)

       }
    }

    class View2: UIViewController {
     weak var delegate: NormalUserDelegate?

    // Going to view 3 by any means i.e segue or other means  
       func goToView3Controller(){
         if let view3 = self.storyboard?.instantiateViewController(withIdentifier: "View3") as? View3
            {
              view3.delegate = self.delegate
            }
         self.navigationController?.pushViewController(view3, animated: true)
       }

    }

    class View3: UIViewController {
     weak var delegate: NormalUserDelegate?


    func test() {

      self.delegate?.showAddressView()

    }

    }