【问题标题】:My delegate function IS being called, still my UI does not update accordingly正在调用我的委托函数,但我的 UI 仍然没有相应更新
【发布时间】:2020-03-20 17:15:58
【问题描述】:

我的委托模式有效(如果我的委托函数只需要打印关于传回数据的语句)(程序化布局,没有 IB segues)。但是接收器类不会相应地更新其 UI。这——我相信——结束了这个案例,即我的委托模式是错误的。 我的 UI 怎么可能没有更新?什么情况下通常会阻止这种情况?我在这里处理手动输入,没有网络调用,没有大量数据或类似的东西。 例如我的委托函数是:

class DetailTableViewController: AddVCDelegate {

//delegate function of AddVCDelgate protocol

func didAddLesson(lesson: Lesson) { // my addVC is calling this through delegate
    self.lesson = lesson
    print("delegate function set navitem title: \(lesson.name!)")//printed out correctly
    self.navigationItem.title = lesson.name! //nothing changes
          self.tableView.reloadData()// no reload
}

/*Here lesson.name got printed out nicely, navigationItem title does not change accordingly , tableView does not reload data.*/

返回 AddVC ViewDidLoad

override func viewDidLoad() {
    super.viewDidLoad()
    let vc = DetailTableViewController()
    self.delegate = vc //etc..}

AddVC 使用这个函数:

   func passLesson() {
    if let lesson = lesson,
        let delegate = self.delegate {
               delegate.didAddLesson(lesson: lesson)
           }
}

我只是发布了这个小sn-p,因为现在项目有点太复杂,无法复制到这里,但我相信这是问题代码的相关部分。如果需要,我可以更新更多细节。提前致谢!

更新:我已将一个简单的演示项目上传到 GitHub,它正在重现该问题,我希望它有助于了解问题的真正原因。我还在拼命寻找,我在这里做错了什么。

github.com/gerkov77/DataPassing/tree/master

【问题讨论】:

  • 显示如何在调用didAddLesson 的对象上设置委托。最常见的错误是没有在视图控制器的屏幕实例上调用委托方法。
  • 更新了代码。
  • @Paulw11,AddVC 她已经是导航堆栈上的第三个,因为我有一个 mainVC presentig detailVC,它正在展示 addVC 进行修改。可能是某种问题吗?
  • 有趣的文章。我认为理解这个概念。然而类是引用类型,所以如果你使一个彼此相等,它们将被引用。我不知道的一点是,通过告诉视图控制器类“你们两个在同一个导航堆栈上”已经足以实现这一点。请纠正我,如果我在这里错了。

标签: ios swift user-interface delegates uikit


【解决方案1】:

您正在创建DetailTableViewController() 的新实例并将其分配给委托对象。您没有调用视图层次结构中存在的 DetailTableViewController,而是调用了一个新的。

您需要将委托分配给您已经存在的视图控制器。


澄清:

您在屏幕上显示DetailTableViewController。这就是您在调用委托时要更新的视图。我们称之为View A

当您分配委托时,您正在实例化一个新的DetailTableViewController,它不是View A,而是一个您没有向用户显示的新对象。我们称之为View B

当您执行函数passLesson() 时,您正在调用View B 中的方法didAddLesson(),该方法不会显示给用户。

您不应该创建新的View B,您需要在您的委托中使用View A。如何?好吧,您需要以某种方式将 View A 提供给您的 AddVC 类并将其用于您的委托。

TLDR:let vc = DetailTableViewController() 行是错误的。不要实例化一个新的控制器,使用你现有的。

【讨论】:

  • 你能告诉我我是怎么做的吗?正如我所说,我的函数在我现有的 DetailViewController() 上被调用(打印语句正在打印正确的数据),它是 UI 没有更新。有点我可能会在这里出错。
  • 我不知道如何通过写作来解释这一点,但我编辑了我的答案来尝试。我希望它有所帮助。
  • 好的,所以我在 DTVC 中创建了一个 DetailTableViewController 的共享实例,并在 addVC ViewíDidLoad: self.delegate = DetailTableViewController.shared,仍然没有 UI 更新,仍然调用我的函数,并打印数据正常。
  • 顺便说一句,当我在 DetailViewController 中添加VC.delegate = self 时,未调用委托函数。
  • 我上传了一个演示项目到 GitHub 来重现这个问题,我希望它有助于看看,发生了什么[链接]github.com/gerkov77/DataPassing/tree/master
【解决方案2】:

你是从后台线程调用你的委托吗? 如果是这样,您需要包装任何 UI 更新调用,以便在主队列上分派,如下所示:

func didAddLesson(lesson: Lesson) { // my addVC is calling this through delegate
    self.lesson = lesson
    print("delegate function set navitem title: \(lesson.name!)")//printed out correctly

    DispatchQueue.main.async {
        self.navigationItem.title = lesson.name! //nothing changes
        self.tableView.reloadData()// no reload
    }
}

【讨论】:

  • 我上传了一个演示项目到 GitHub 来重现这个问题,我希望它有助于了解,发生了什么 [link] github.com/gerkov77/DataPassing/tree/master
【解决方案3】:

好的,我找到了解决方案! 正如@Roberto 和@matt 所指出的,我创建了一个委托VC 的新实例,所以委托基本上不起作用!我很困惑,因为所有打印语句都在委托函数中工作。但这还不够。 我也把addVC.delegate = self放在了错误的方法中!在 addVC 类中将其更改为self.delgate = detailVC 的想法也是错误的。 正确的答案似乎是detailVC,当我转移到AddVC时,我是这样做的:

 @objc func handleEdit() {
         let avc = AddVC()
        avc.lesson = self.lesson
        avc.delegate = self
         let nc = UINavigationController(rootViewController: avc)
         present(nc, animated: true, completion: nil)
     }

这样,当 AddVC 出现时,detailVC已经知道她是代表!为什么?因为我通过这种方式告诉 detailVC,我所指的 addVC 是使“segue”的 navigationController 的 rootController。因为类是引用类型,这样 addVC 的新实例将是相同的,并引用到原来的。我希望我理解正确。 但是工作!

【讨论】:

    猜你喜欢
    • 2020-02-20
    • 2021-05-04
    • 2014-03-12
    • 1970-01-01
    • 2013-06-11
    • 2018-11-09
    • 1970-01-01
    • 2015-03-18
    • 1970-01-01
    相关资源
    最近更新 更多