Протокольный делегат между представлением перед стеком навигации - PullRequest
3 голосов
/ 29 января 2020

View1 переходит на Navigation Controller - View2 переходит на View3

Я пытаюсь создать делегата протокола от View3 до View1

в View1

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

В View3

weak var delegate: NormalUserDelegate?

func test() {

self.delegate?.showAddressView()

}

Протокол

protocol NormalUserDelegate: class {
    func showAddressView()
}

Я не мог заставить его работать. Есть идеи?

Ответы [ 6 ]

4 голосов
/ 09 февраля 2020

На мой взгляд, у вас есть 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 - передать 3-го контроллера второму контроллеру


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. Просто убедитесь, что пространство имен вашего уведомления указано c достаточно, чтобы потом его не перехватить.

0 голосов
/ 12 февраля 2020
**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()

    }

    }
0 голосов
/ 12 февраля 2020

Я думаю, вы можете использовать SwiftEventBus для этой ситуации. Ссылка

Пример:

@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)
}
0 голосов
/ 10 февраля 2020

Размотка сегментов

Если вы используете конструктор интерфейса, может быть проще / понятнее использовать раскручивание сегментов.

  1. Создать действие построителя интерфейса в VC1:

    class VC1: UIViewController {
    
        @IBAction func backToVC1(_ segue: UIStoryboardSegue) {
            self.showAddress()
        }
    
        func showAddress() {
            addressView.isHidden = false
        }
    }
    
  2. В вашей раскадровке для VC3 нажмите на значок контроллера представления, перетащите мышь над значком выхода и отпустите. Нажмите, чтобы выбрать последовательность размотки, созданную в VC1.

    enter image description here

  3. После создания перехода выберите его в структуре документа.

    enter image description here

  4. И назовите его в инспекторе атрибутов.

    enter image description here

  5. Наконец, вызовите segue в своем коде VC3.

    class VC3: UIViewController {
    
        func test() {
            self.performSegue(withIdentifier: "unwindToVC1", sender: self)
        }
    }
    
0 голосов
/ 06 февраля 2020

Вам не хватает класса маршрутизатора, это простой пример того, как я бы его реализовал.


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()
}
0 голосов
/ 06 февраля 2020

Если я правильно понимаю ваш сценарий, вам нужны два делегата, каждый из которых передает данные обратно в предыдущий UIViewController. Насколько мне известно, вы не можете обойти дополнительный UIViewController.

...