UIViewController之间传值的7种方法
来源:互联网 发布:长城宽带 端口转发 编辑:程序博客网 时间:2024/06/05 23:04
当父UIViewController打开一个新的子UIViewController时, 二者之间可能需要双向传值即父传子、子回传父, 或者单向传值的父传子、子传父。
我整理了一下,大概分为7种方法(前3种方法较常用):
1、UIStoryBoardSegue, 前置条件是要使用storyboard做界面。
2、闭包, 即在父窗口实现闭包, 在子窗口保存闭包的引用。
3、协议, 跟闭包原理一样, 即在父窗口实现协议接口, 在子窗口保存协议引用。
4、单例模式, 即父/子界面访问同一个单例。
5、文件持久化, 例如Core Data、UserDefaults或其他三方数据库; 原理跟单例模式一样, 区别是单例模式读写的是内存。
6、网络接口, 即父/子窗口与网络服务器同步数据, 原理跟单例模式、文件持久化一样, 区别是将数据保存到网络。
7、 观察者模式, 即在UIViewController里注册监听对应的Notification; 例如父窗口观察, 子窗口修改值。一、 使用UIStoryBoard画界面是比较基础的行为,一般被认为是iOS开发入门级。 在讲述值传递前先看一下UIViewController的生命周期。
父UIViewController打开子UIViewController:
父界面prepare父窗口viewWillDisappear子界面viewDidLoad子窗口viewWillAppear父窗口viewDidDisappear子窗口viewDidAppear
子界面 prepareunwindToMain子窗口viewWillDisappear父窗口viewWillAppear子窗口viewDidDisappear父窗口viewDidAppear
可以看出当UIViewController不再是活动窗口时,最新执行prepare函数, 所以要在prepare函数里做业务逻辑!
/** * 父窗口向子窗口传值 * segue, 判断下一级UIViewController类型 * sender, 触发切换ViewController的地方,在这里是按钮控件 */ override func prepare(for segue: UIStoryboardSegue, sender: Any?) { print("父界面prepare") //方法一 通过目标UIViewController类型判断 if let vc = segue.destination as? SecondeViewController { vc.value = "第二级界面111" //print("显示SecondViewController") } //方法二 通过点击的控件判断 if sender as? UIButton == btnNext { //print("点击按钮显示二级界面") } }上面代码是在显示子窗口SecondViewController时, 通过segue参数的destination属性为子窗口赋值, 即实现了父传子(类似于Android startActivity时在intent里携带参数)。
子窗口SecondViewController在退出后需要传值给父窗口ViewController, 实现方法是在父窗口实现一个unwindToMain函数且在uistoryboard里将exit指向该函数。 具体如下:
//从子ViewController返回, 作用类似于Android的onAcitivityResult函数 @IBAction func unwindToMain(_ segue: UIStoryboardSegue) { print("unwindToMain") if let vc = segue.source as? SecondeViewController { print(fatherName) print("\(vc.age)") //子窗口给父窗口的传值, 在父窗口里能拿到子窗口的引用! } }
//退出当前界面时 保存值到变量里 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { //退出该界面时执行 print("子界面 prepare") if let vc = segue.destination as? ViewController { print("返回上一级界面") vc.fatherName = "子窗口修改父窗口值" //子ViewController也有父Controller的引用,能够修改父controller的值,但不建议这样做!!! //将本界面控件的值保存到变量里 value = "二级界面返回值" age = 100 } }
注意: UIStoryboardSegue可以修改父或子UIViewController的值(即双向的)!!! 但实际编码中建议单向传值, 即父UIViewController对子UIViewController取值或赋值。
二、 闭包, 在这里应该是逃逸闭包。 在子界面里保存闭包的引用, 在父窗口实现闭包。 下面的写法有点像Java, 其实可以声明个构造函数,将闭包作为构造函数的一个参数。
class SecondeViewController: UIViewController {....... var callback: (_ name: String?, _ age: Int?) -> Void? = {(name, age) in print("默认闭包") return nil } //设置闭包 func setCallBack(callback: @escaping (String?, Int?) -> Void?) { self.callback = callback }...}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { //退出该界面时执行 print("子界面 prepare") callback("张三", 100) //通过闭包回调通知 }
在父窗口实现闭包:
if let vc = segue.destination as? SecondeViewController { vc.value = "第二级界面111" vc.setCallBack(callback: { (name, age) in print("name: \(name), age: \(age)") //子界面的返回值 }) }
输出:
子界面 prepare
name: Optional("张三"), age: Optional(100)
unwindToMain
三、 协议, 跟Java的interface一模一样, 父类实现接口函数,子类保存接口的引用。
protocol SecondDelegate { func respond(name: String?, age: Int?)}在父类里实现protocol:
class ViewController: UIViewController, SecondDelegate { 。。。 /** * 父窗口向子窗口传值 * segue, 判断下一级UIViewController类型 * sender, 触发切换ViewController的地方,在这里是按钮控件 */ override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if let vc = segue.destination as? SecondeViewController { vc.value = "第二级界面111" vc.delegate = self } } func respond(name: String?, age: Int?) { print("接口返回: \(name), \(age)") } 。。。}
在退出子类时调用接口函数
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { //退出该界面时执行 print("子界面 prepare") delegate?.respond(name: "李四", age: 200) }
四、单例模式, 即进程里只有一个实例。 在父/子窗口读写该同一个实例时, 即可实现数据共享。 --- 不推荐这种做法
class SingleTon { static let instance = SingleTon() var name: String? var age: Int?}
五、 持久化, 即从文件里读写数据。 包括iOS提供的Core Data, UserDefaults、文件或其他三方框架等。 不同界面读写同一个文件, 因为文件IO比内存读写更浪费资源也更慢, 要注意使用的时机。
六、 网络接口, 这个很好理解,就是数据存储在服务器上。 现在的互联网app都会联网, 那么A界面上传到服务器的数据, B界面在使用时可以从服务器下载。 PS: 网络交互会遇到各种情况, 要跟进业务逻辑使用这种方式。 原则是以服务器的数据为准!!! 避免发生数据不同步的问题。
七、 观察者模式, 就是使用iOS的NotificationCenter注册监听, 当数据变化时接收到回调。 注意iOS和Android的区别: Android一般会在onStop函数里unregister监听、onResume函数里注册监听, 即只有当前活跃窗口保持监听; 而iOS是只要界面还存在, 那么就保留监听,直接界面销毁时才取消监听。 PS: 原因是Android的内存管理机制,后台的activity很可能被gc回收,如果不在onStop函数里释放资源就可能内存泄漏; 而iOS的内存管理更强大,一般不会出现内存溢出,这就是Swift的强大之处!
iOS没提供类似于Android startActivityForResult的功能, 日常开发中一般使用代码画界面, 所以UIViewConroller之间的数据交换一般用闭包或协议实现。
参考代码:http://download.csdn.net/detail/brycegao321/9916397
- UIViewController之间传值的7种方法
- UIViewController之间的传值 6种
- UIViewController之间的通讯方法
- UIViewController之间传值:
- iOS UIViewController之间的传值方式之一:委托代理
- UIViewController之间的传值方式二 通知
- UIViewController之间传递值的两种方式
- UIViewController 的addChildViewController:(UIViewController *) 方法
- 多个uiviewController之间传值
- UIViewController和UIViewController之间的交互
- UIViewController和UIViewController之间的交互
- 在iPhone开发中关于子UIViewController和父UIViewController之间相互调用方法的办法
- UIViewController 之间的动画切换
- iOS UIViewController之间的切换
- UIViewController的init方法
- Swift编程(二):UIViewController之间的传值以及闭包回调传值
- UIViewController间的传值
- 利用构造函数在两个UIViewController之间传值
- 【资源共享】《Rockchip RK818电量计 开发指南》
- HDU1285---确定比赛名次 (拓扑排序)
- Git入门
- Hadoop的一些基本介绍 jps
- git分支切换问题
- UIViewController之间传值的7种方法
- UVa10391(拆分)
- malloc函数两个使用实例
- 安卓隐藏键盘与点击空白区域隐藏键盘
- tensorflow教程学习三深入MNIST
- 走迷宫——DFS
- 玲珑杯round#19B 1149 Buildings
- [leetcode]166. Fraction to Recurring Decimal
- Errors reported here must be corrected before the service can be started.