【问题标题】:Protocol delegate between view before navigation stack导航堆栈之前视图之间的协议委托
【发布时间】:2020-01-29 09:53:34
【问题描述】:

View1 转至 导航控制器 - 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()
}

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

【问题讨论】:

  • 我想在这种情况下最好使用 NSnotifications
  • 您没有得到答案的原因是您的问题根本不清楚。不要让我们破译你的代码来弄清楚你想问什么,并给我们更多关于你是如何失败的信息,而不是“我无法让它工作”。此外,视图控制器不是视图,因此称它们为“View1”和“View3”只会让您的问题更难理解。
  • 在您的示例中,connviewDidLoad 之后超出范围。 View3 的delegate 成员被标记为weak,因此当viewDidLoad 返回时,对它的引用会丢失。要使您的代码正常工作,您必须使 conn 成为 View1 类的成员,或者删除 View3 的 delegate 成员上的 weak 关键字。
  • @UtkuDalmaz,请分享一个演示项目,它重现了您面临的相同问题。

标签: ios swift delegates segue protocols


【解决方案1】:

在我看来,您有 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 可怕的选择

使用单例/全局变量....(请不​​要)

个人意见

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

【讨论】:

  • 注意,这不使用情节提要。
  • 虽然我认为你仍然可以这样做,只需将文件中的属性设置为 IBoutlet 并将它们连接到故事板中
【解决方案2】:

如果我正确理解您的场景,您需要两个委托,每个委托将数据传递回之前的 UIViewController。据我所知,您无法绕过辅助 UIViewController。

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

      放松转场

      如果您使用的是界面生成器,则使用展开转场可能是最简单/最干净的。

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

        class VC1: UIViewController {
        
            @IBAction func backToVC1(_ segue: UIStoryboardSegue) {
                self.showAddress()
            }
        
            func showAddress() {
                addressView.isHidden = false
            }
        }
        
      2. 在您的 VC3 故事板中,按住控件并单击视图控制器图标,将鼠标拖到退出图标上并释放。单击以选择您在 VC1 中创建的展开转场。

      3. 创建转场后,在文档大纲中选择它。

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

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

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

      【讨论】:

        【解决方案5】:

        我认为您可以在这种情况下使用SwiftEventBusLink

        示例:

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

        【讨论】:

          【解决方案6】:
          **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()
          
              }
          
              }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-10-30
            相关资源
            最近更新 更多