我有一个ViewController,这个视图容器有一个创建2个容器视图的类,并向第一个容器添加了一个表,为第二个容器添加了一个HashtagPicker。

hashTagPicker具有一个函数,只要对选定的hashTag进行更改,就会调用该函数。

问题:每当更改标签时,我想调用更新表函数。如何从包含容器的类中定义的hashtagclass调用函数?

最佳答案

我个人喜欢在通知上使用委托方法-后一种解决方案几乎总是导致混乱的体系结构。可悲的是,委托方法的示例(也是公认的答案)甚至更糟-它基本上为内存泄漏提供了机会。我会解释。在公认的解决方案中,ParentView拥有一个对HashtagPicker的强引用,进而,HastagPicker拥有了对ParentView的强引用,这创建了一个保留周期,这意味着两个控制器都不会被ARC接收并被初始化。因此,例如,如果您要从其他视图中呈现ParentView,并且继续浏览ParentView并返回,则将继续生成ParentView(和HashtagPicker)新实例,而旧实例仍然占据内存。

现在,应该怎么做。我将使用与接受的答案完全相同的名称。

该协议应定义如下:

// note the ": class" part
protocol HashTagPickerDelegate: class {
  func picked(hashtag: String)
}

如果指定class,则意味着该协议只能在类上使用。这将允许使用它创建弱引用,否则将是不可能的。
class HashtagPicker: UIViewController {
  // if HashTagPickerDelegate wouldn't be limited to class,
  // we couldn't have made a weak reference here!
  weak var delegate: HashTagPickerDelegate?

  // at some point, you call the delegate, it can be anywhere, this is just an example
  @IBAction func tappedHashtag(_ sender: Any) {
    delegate?.picked(hashtag: "bla")
  }
}

现在我们对委托的引用很少,因此没有保留周期,ARC可以很好地清理所有内容!

我将剩下的代码作为完整的答案:
class ParentView: UIViewController {
  func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    // we are presenting the nested controller
    if segue.identifier == "SegueHastagPickerContainer",
       let destinationController = segue.destination as? HashtagPicker {
      destinationController.delegate = self
    }
  }
}

extension ParentView: HashTagPickerDelegate {
  func picked(hashtag: String) {
    // we just got info from the child controller, do something with it!
  }
}

10-05 21:44