【问题标题】:Making a Delegate Call from One View Controller to Another从一个视图控制器到另一个视图控制器进行委托调用
【发布时间】:2017-04-08 18:04:00
【问题描述】:

我在 Swift 中没有做过的一件事是使用委托。所以我试图从一个视图控制器到另一个视图控制器进行委托调用以传递数据。

我有两个跨两个独立故事板的视图控制器。一个是 HomeViewController,第一个视图控制器。这就是用户现在所处的位置。然后他点击右侧导航项按钮转到第二个视图控制器 SettingsViewController。然后他点击导航项按钮返回到第一个视图控制器。在返回的路上,SettingsViewController 向 HomeViewController 发送了一个Int 值。我所拥有的是以下内容。

// 1st view controller //
class HomeViewController: UIViewController, SettingsViewControllerDelegate {
    @IBAction func rightTapped(sender: AnyObject) {
        let storyboard = UIStoryboard(name: "Settings", bundle: nil)
        let controller = storyboard.instantiateViewControllerWithIdentifier("InitialController") as! UINavigationController
        let view = controller.topViewController as! SettingsViewController
        view.selectedRow = lineSelection
        self.navigationController?.pushViewController(view, animated: true)
    }

    override func viewDidLoad() {
        let storyboard = UIStoryboard(name: "Settings", bundle: nil)
        let controller = storyboard.instantiateViewControllerWithIdentifier("InitialController") as! UINavigationController
        let settingsViewController = controller.topViewController as! SettingsViewController
        settingsViewController.delegate = self
    }

    func didChangeLine(number: Int) {
        print(number) // <<<<<<<<< not getting a delegate call
    }
}

// 2nd view controller //
protocol SettingsViewControllerDelegate {
    func didChangeLine(number: Int)
}

class SettingsViewController: UIViewController {
    var selectedRow = Int() // the row selected from a table view
    var rightButton = UIBarButtonItem()

    override func viewDidLoad() {
        rightButton = UIBarButtonItem(title: "Change", style: .Plain, target: self, action: #selector(changeNumber))
        self.navigationItem.rightBarButtonItem  = rightButton
    }

    // going back to 1st view controller (HomeViewController)
    func changeNumber() {
        self.delegate?.didChangeLine(selectedRow)
        self.navigationController?.popViewControllerAnimated(true)
    }
}

当用户从第二个(设置)返回到第一个视图控制器(主页)时,我没有接到电话。我可以用不同的方法传递数据,但我想知道我在这种情况下做错了什么。

谢谢。

【问题讨论】:

  • 您确定要更改选定的行值吗?如果是这样,你能显示更多的代码吗?
  • @J. Koush 我可以为 didChangeLine 设置一个幻数。第一个视图控制器永远不会收到它。
  • 是的。用户将被送回第一个视图控制器。
  • 如果委托不是nil,您能否使用changeNumber() 方法中的调试器进行检查。
  • 您正在 viewDidLoad 中创建 SettingsViewController 的实例并设置其委托,但您没有保存或呈现此设置视图控制器实例。你如何呈现设置视图控制器?

标签: ios swift uiviewcontroller delegates


【解决方案1】:

在这个Protocol-Sample 中,我模拟了调用 HomeViewController 的 'didChangeLine' 函数的相同场景,如下图所示。

【讨论】:

    【解决方案2】:

    试试这个方法,这里我创建了一个变量 settingsViewController,我在 viewDidLoad() 方法中设置它,并在用户点击右键时使用它,而不是创建一个新的 settingsViewController。

    // 1st view controller //
    class HomeViewController: UIViewController, SettingsViewControllerDelegate {
    
        var settingsViewController: SettingsViewController? 
        // creating a variable so that we can use it in the IBOutlet 
        // method after setting it in the viewDidLoad() method
    
        @IBAction func rightTapped(sender: AnyObject) {
            settingsViewController.selectedRow = lineSelection
            self.navigationController?.pushViewController(settingsViewController, animated: true)
        }
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            let storyboard = UIStoryboard(name: "Settings", bundle: nil)
            let controller = storyboard.instantiateViewControllerWithIdentifier("InitialController") as! UINavigationController
            settingsViewController = controller.topViewController as? SettingsViewController
            settingsViewController.delegate = self
        }
    
        func didChangeLine(number: Int) {
            print(number) 
        }
    }
    

    【讨论】:

    • 我看不出这样做的目的。此外,应用程序在从第一个视图控制器转换到第二个视图控制器时会崩溃。
    • 崩溃信息是什么?
    【解决方案3】:

    您需要在第一个 viewcontroller 中覆盖 prepareForSegue 以将第一个 viewcontroller ref 传递给 secondviewcontroller 委托属性。

    override func prepareForSegue(segue: UIStoryboardSegue?, sender: AnyObject?) {
            let viewController = segue.destinationViewController as! SettingsViewController
            viewController.delegate = self
    }
    

    在HomeViewController viewDidLoad 中的代码没有任何意义,因为您正在从情节提要执行segue。

    更新

    @IBAction func rightTapped(sender: AnyObject) {
        let storyboard = UIStoryboard(name: "Settings", bundle: nil)
        let controller = storyboard.instantiateViewControllerWithIdentifier("InitialController") as! UINavigationController
        let view = controller.topViewController as! SettingsViewController
        view.delegate = self
    
       view.selectedRow = lineSelection
        self.navigationController?.pushViewController(view, animated: true)
    }
    

    您可以直接获取 SettingViewController 参考。只需设置 viewcontroller 故事板 id 并像这样获取它

     let storyboard = UIStoryboard(name: "Settings", bundle: nil)
     let controller = storyboard.instantiateViewControllerWithIdentifier("InitialController") as! UINavigationController
    
    let controller = storyboard.instantiateViewController(withIdentifier: "SettingsViewController") as! SettingsViewController
    

    【讨论】:

    • 我没有使用 segue 从第一个视图控制器转换到第二个。
    • 那么你将如何从第一个控制器呈现第二个视图控制器?
    • 我已经更新了代码。见@IBAction func rightTapped(sender: AnyObject)
    • 更新了代码。 view.delegate = 自我。您需要在推送之前将委托分配给自己。
    • 谢谢。如果你允许我问怎么办?
    【解决方案4】:
    @IBAction func rightTapped(sender: AnyObject) {
            let storyboard = UIStoryboard(name: "Settings", bundle: nil)
            let controller = storyboard.instantiateViewControllerWithIdentifier("InitialController") as! UINavigationController
            let view = controller.topViewController as! SettingsViewController
            view.selectedRow = lineSelection
            self.navigationController?.pushViewController(view, animated: true)
        }
    

    改为:

    @IBAction func rightTapped(sender: AnyObject) {
            let storyboard = UIStoryboard(name: "Settings", bundle: nil)
            let controller = storyboard.instantiateViewControllerWithIdentifier("InitialController") as! UINavigationController
            let view = controller.topViewController as! SettingsViewController
            view.selectedRow = lineSelection
    view.delegate = self
            self.navigationController?.pushViewController(view, animated: true)
        }
    

    【讨论】:

      【解决方案5】:

      在 SettingsViewController 类中更改以下方法:-

      override func viewDidLoad() {
              rightButton = UIBarButtonItem(title: "Back", style: .Plain, target: self, action: #selector(changeNumber))
              self.navigationItem.leftBarButtonItem  = rightButton
          }
      

      【讨论】:

      • 我为什么要这样做?
      • 因为你没有为后退按钮调用“changeNumber”方法。您正在为右键而不是后退按钮调用“changeNumber”方法。
      猜你喜欢
      • 1970-01-01
      • 2020-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-01
      • 1970-01-01
      相关资源
      最近更新 更多