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,它必须知道调用者的类。
为什么这是个问题? 它使你的笔记写视图控制器不能重复使用。 如果您正确书写笔记书写视图控制器,那么您可以在其他应用程序中重复使用它。 为了使其可重用,您需要将来自调用者的音符书写视图控制器分离出来,而不必知道究竟是谁调用了它。
所以问题就变成了,如果我不知道是谁打给我的,我怎么把数据传回给对方呢? 答案是代表团 。
代表团的工作如下:
-
您创build一个协议来描述该协议的实现者将实现的一个或多个方法。 在你的情况下,你可以使用像
NoteWriterDelegate
这样的协议来实现方法takeNote(note: String)
。protocol NoteWriterDelegate { func takeNote(note: String) }
在你的笔记写视图控制器的文件中定义这个。
-
您的笔记编写者将有一个可选的指向该代表的指针:
weak var delegate: NoteWriterDelegate?
-
您需要将您的第一个视图控制器声明为
NoteWriterDelegate
:class ViewController: UITableViewController, NoteWriterDelegate
-
然后在您的第一个视图控制器中实现所需的方法:
func takeNote(note: String) { notes.append(note) }
-
当你准备转移到笔记编写视图控制器时,你会打电话给
prepareForSegue
,你把自己当成代表:destinationViewController.delegate = self
-
在笔记书写视图控制器中,当你有一个笔记传回给调用者时,你
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)