prepareForSegue是在视图控制器之间传递值的正确方法

我正在努力学习Swift,我正在努力开发着名的笔记应用程序。

有一个数组绑定到tableview和另一个视图来添加注释。 在第二个视图textfieldshould返回事件触发segue并返回到tableview。

我想知道这是否正确。 因为通过这样做我操纵另一个视图控制器中的variables。 我不是一个MVC主,但我觉得这是错的。 这是我的代码片段:

func textFieldShouldReturn(textField: UITextField) -> Bool { self.performSegueWithIdentifier("backSegue", sender: self) return true } override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { if(segue.identifier == "backSegue"){ let navController = segue.destinationViewController as UINavigationController; let myController = navController.topViewController as NotesTableViewController; if(self.ourTextField?.text != nil || self.ourTextField?.text != ""){ myController.notes.append(self.ourTextField?.text ?? ""); } } } 

谢谢。

你的问题不是关于prepareForSegue而是视图控制器之间的关系。 你的devise“感觉不对”的原因是这样的。 问题是你的笔记写视图控制器知道太多关于使用它的视图控制器,因为它直接操作调用视图控制器的variables。 为了直接操作variables,它必须知道调用者的类。

为什么这是个问题? 它使你的笔记写视图控制器不能重复使用。 如果您正确书写笔记书写视图控制器,那么您可以在其他应用程序中重复使用它。 为了使其可重用,您需要将来自调用者的音符书写视图控制器分离出来,而不必知道究竟是谁调用了它。

所以问题就变成了,如果我不知道是谁打给我的,我怎么把数据传回给对方呢? 答案是代表团

代表团的工作如下:

  1. 您创build一个协议来描述该协议的实现者将实现的一个或多个方法。 在你的情况下,你可以使用像NoteWriterDelegate这样的协议来实现方法takeNote(note: String)

     protocol NoteWriterDelegate { func takeNote(note: String) } 

    在你的笔记写视图控制器的文件中定义这个。

  2. 您的笔记编写者将有一个可选的指向该代表的指针:

     weak var delegate: NoteWriterDelegate? 
  3. 您需要将您的第一个视图控制器声明为NoteWriterDelegate

     class ViewController: UITableViewController, NoteWriterDelegate 
  4. 然后在您的第一个视图控制器中实现所需的方法:

     func takeNote(note: String) { notes.append(note) } 
  5. 当你准备转移笔记编写视图控制器时,你会打电话给prepareForSegue ,你把自己当成代表:

     destinationViewController.delegate = self 
  6. 在笔记书写视图控制器中,当你有一个笔记传回给调用者时,你takeNote在委托上调用takeNote

     delegate?.takeNote(self.ourTextField?.text ?? "") 

通过这样做,你的笔记作者只知道它正在和一个NoteWriterDelegate 。 如果你想在将来重用这个,你只需要把你的笔记编写器类放到另一个工程中,实现这个委托,而且它不需要触摸笔记编写器类中的代码。

我build议在大多数情况下通过prepareForSegue传递数据。 这很容易设置和易于理解。

但是,我build议不要直接更新目标视图上的UI元素(标签,文本字段等)。 在我看来,这是不好的耦合,造成了很多问题。

而是在目标视图控制器上创build一个或多个属性,调用者可以在prepareForSegue中将其设置为将数据传递给它。 这些应该是专门用于传递数据的专用属性。 目标视图控制器然后负责使用这些属性中的数据来更新其UI或内部状态。

授权是一个有效的方法,但是我发现它在大多数情况下是过分的。 它需要更多的设置,更抽象。 这种抽象在很多视图控制器关系中是不需要的。 如果您发现需要重用视图控制器,则可以随时重构以便稍后使用委派。

我不相信prepareSegue是在视图控制器之间传递数据的理想方式…至less不是直接的。

我分享你使用prepareForSegue在视图控制器之间传递值的顾虑。 源视图控制器不应该知道任何关于目标视图控制器(和其他方式)。 理想情况下, 视图控制器应该是独立的岛屿,彼此之间没有可见性

为了解决故事板似乎鼓励的耦合,我经常使用某种forms的中介模式在视图控制器之间传递数据。 这里是一个相当不错的博客文章,关于如何实现这个模式版本的故事板: http : //coding.tabasoft.it/ios/mediator-pattern-in-swift/ 。 与往常一样,这种模式可能并不适合所有情况,但是我认为这是我过去很多项目中的一个很好的解决scheme。

基本上,介体模式在故事板范例中的工作方式是,在每个视图控制器的prepareForSegue方法中,将segue对象传递给mediator对象。 视图控制器不关心导航下一步的内容或位置; 它只是知道它将不可见。 刚刚通过segue对象(包含源视图控制器和目标视图控制器)的中介器负责在源视图控制器和目标视图控制器之间传递数据。

使用这种模式,每个视图控制器都是幸福的不知道另一个的存在。 另一方面,介体类必须知道导航path中视图控制器(和视图控制器的接口)之间的关系。 显然,如果导航改变了,或者视图控制器本身改变了,中介类也需要调整。 但是,每个视图控制器不需要彼此依赖,因此不需要更新以适应导航path中的改变或沿着该导航path改变到其他视图控制器。

这不是“正确”的方式,但这是一个正确的方法。 特别是在故事板应用程序。

这是传递价值和调用视图的另一种方式。

 var myNewVC = NewViewController() myNewVC.data = self navigationController?.presentViewController(myNewVC, animated: true, completion: nil)