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

Posted

技术标签:

【中文标题】导航堆栈之前视图之间的协议委托【英文标题】: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,请分享一个演示项目,它重现了您面临的相同问题。 【参考方案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】:

放松转场

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

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

    class VC1: UIViewController 
    
        @IBAction func backToVC1(_ segue: UIStoryboardSegue) 
            self.showAddress()
        
    
        func showAddress() 
            addressView.isHidden = false
        
    
    

    在您的 VC3 故事板中,按住控件并单击视图控制器图标,将鼠标拖到退出图标上并释放。单击以选择您在 VC1 中创建的展开转场。

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

    并在属性检查器中命名。

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

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

【讨论】:

【参考方案5】:

我认为您可以在这种情况下使用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)

【讨论】:

【参考方案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()

    

    

【讨论】:

以上是关于导航堆栈之前视图之间的协议委托的主要内容,如果未能解决你的问题,请参考以下文章

使用委托将数据传回导航堆栈

XIB 和视图控制器之间的协议委托

当视图控制器弹出或推入导航控制器堆栈时如何获得通知

如何在将数据推送到导航堆栈之前将数据传递给视图控制器并加载它?

iOS在导航堆栈中的视图控制器之间循环

为啥在我的视图被推送到导航堆栈之前我的 UIAlertView 没有在屏幕上消失?