[TOC] ## ViewController之间传值 IOS中,在两个ViewController之间传值有多种方式,这里我们只介绍其中部分方式。界面间的传值可以分为两种:正向传值、反向传值。 由当前界面(a)向即将**跳转**的界面(b)传输信息即为正向传值,特点界面(b)中的内容由前一个界面(a)传输而来的数据决定。界面(b)在**返回**界面(a)时向界面(a)传输数据的事件为反向传值,特点为前一个界面(a)的内容由后一个界面(b)传输而来的数据决定。 ### 1. ViewController 正向传值 在使用present()和dismiss()进行视图切换时,往往不只是进行单纯的视图切换,大多需要进行数据的传输。正向传值比较容易,可以通过对将要跳转的视图控制器的**属性**进行赋值,或者设计新的**构造方法**,在构造时对其属性进行初始化。 #### 1.1 属性传值 在将要跳转界面(b)的视图控制器(NotificationViewController 的父类 PresentViewController )中声明一个属性来接收传递的数据: ```swift var text: String? override func viewDidLoad() { super.viewDidLoad() lable = InsetLabel(Text: "接收 Main View 信息: \nValue: \(text ?? "nil")") ...... } ``` 界面(a)视图控制器(ViewController)的跳转代码如下: ```swift // MARK: 属性正向传值 @objc func touch1(sender: UIButton) { let notificationViewController = NotificationViewController() // 属性赋值 ——> 正向传值 notificationViewController.text = textField.text self.present(notificationViewController, animated: true) { print("跳转至-> Notification View") } } ``` #### 1.2 构造方法传值 在Swift的构造方法中需要对所有非Optional类型的属性完成初始化工作,在将要跳转的界面(c)的视图控制器(ProtocolViewController 的父类 PresentViewController) 中定义一个新的构造方法,并实现`required init?(coder: NSCoder)`方法(**required**关键字修饰的构造方法在子类中必须实现——继承或复写)。代码如下: ```swift var text: String? init(Text: String?) { self.text = Text super.init(nibName: nil, bundle: nil) } required init?(coder: NSCoder) { super.init(coder: coder) } ``` 界面(a)视图控制器(ViewController)的跳转代码如下: ```swift // MARK: 初始化函数正向传值 @objc func touch2(sender: UIButton) { // 自定义构造方法创建对象 ——> 初始化函数正向传值 let protocolViewController = ProtocolViewController(Text: textField.text) self.present(protocolViewController, animated: true) { print("跳转至-> Protocol View") } } ``` ### 2. ViewController 反向传值 在跳转后的界面进行一些处理后,可能需要将结果传输给上一个界面,这种数据的传输可以使用反向传值来实现。反向传值包括: 闭包传值、协议传值、通知传值等。 #### 2.1 闭包传值 ```mermaid graph LR 闭包声明 --> 闭包定义并赋值 闭包定义并赋值 --> 闭包调用 ``` 通过闭包的方式进行反向传值主要使用闭包参数来传值,首先在ClosureViewController类中**声明**一个Optional类型的闭包,代码如下: ```swift // 闭包声明 var closure: (([String: String]) -> Void)? ``` 闭包的**调用**代码放在返回按钮的点击事件回调中: ```swift override func touch(sender: UIButton) { let info = [textField1.text ?? "": textField2.text ?? ""] guard let closure = closure else { return } // 闭包反向传值: 闭包调用 closure(info) super.touch(sender: sender) } ``` 在ViewController对ClosureViewController进行实例化,**定义**闭包,并将其**赋值**给ClosureViewController的代理属性: ```swift // MARK: 闭包反向传值 属性正向传值 @objc func touch3(sender: UIButton) { let closureViewController = ClosureViewController() closureViewController.text = textField.text closureViewController.presentationController?.delegate = self // 闭包定义并赋值 closureViewController.closure = { info in self.lable.text = "接收 Closure View 信息\nKey:\(info.keys.first ?? "nil")\nValue: \(info.values.first ?? "nil")" self.lable.textColor = .red self.lable.isHidden = false } self.present(closureViewController, animated: true) { print("跳转至-> Closure View") } } ``` #### 2.2 协议传值 ```mermaid graph LR 协议定义 --> 协议遵守 --> 协议实现 --> 代理声明 --> 代理赋值 --> 代理调用 ``` 首先为协议的创建,即**定义**: ```swift // 反向传值 所需协议 protocol ReverseProtocol { func informationTransmission(info: [String: String]) } ``` 创建出的协议由即将返回的界面ViewController**遵守**并**实现**(想让谁接收数据就让谁遵守嘛): ```swift class ViewController: UIViewController, ReverseProtocol{ ..... // 协议反向传值: 协议方法实现 func informationTransmission(info: [String: String]) { lable.text = "接收 Protocol View 信息\nKey:\(info.keys.first ?? "nil")\nValue: \(info.values.first ?? "nil")" lable.textColor = .red lable.isHidden = false } } ``` 之后需要在界面ProtocolViewController中**声明**代理(承载准守了协议的实例): ```swift // 反向传值 代理/协议 var reverseDelegate: ReverseProtocol? ``` 代理声明之后就可以在ViewController界面中对其进行**赋值**了: ```swift // MARK: 协议反向传值 初始化函数正向传值 @objc func touch2(sender: UIButton) { let protocolViewController = ProtocolViewController(Text: textField.text) protocolViewController.presentationController?.delegate = self protocolViewController.reverseDelegate = self self.present(protocolViewController, animated: true) { print("跳转至-> Protocol View") } } ``` 最后即可在返回按钮的点击事件回调中**调用** 代理/协议 方法: ```swift override func touch(sender: UIButton) { let info = [textField1.text ?? "": textField2.text ?? ""] guard let customDelegate = reverseDelegate else { return } // 代理/协议 方法调用 customDelegate.informationTransmission(info: info) super.touch(sender: sender) } ``` #### 2.3 通知传值 ```mermaid graph LR 通知注册 --> 回调定义 --> 通知发送 ``` 最后就是通知传值了,也是最简单的一个,只需要注册通知,让后调用就行了。 首先是**注册**通知: ```swift // 注册通知: 通知反向传值所需 NotificationCenter.default.addObserver(self, selector: #selector(callback), name: NSNotification.Name(rawValue: "ReverseValueTransmission"), object: nil) ``` 然后是接收到通知之后的回调函数定义: ```swift // 通知反向传值: 通知回调 @objc func callback(notifunction: NSNotification) { lable.text = "接收 Notification View 信息\nKey:\(notifunction.userInfo?.keys.first as? String ?? "nil")" + "\nValue: \(notifunction.userInfo?.values.first as? String ?? "nil")" lable.textColor = .red lable.isHidden = false } ``` 最后是在返回按钮的点击事件回调中发送通知: 可以通过userInfo字典传值 / 也可通过object进行 ```swift override func touch(sender: UIButton) { let info = [textField1.text: textField2.text] // 通过userInfo字典传值 / 也可通过object进行 let notification = NSNotification.Name(rawValue: "ReverseValueTransmission") NotificationCenter.default.post(name: notification, object: nil, userInfo: info as [AnyHashable: Any]) super.touch(sender: sender) } ``` **[GitHub源码](https://github.com/ZhangHaoKun91/BlogProjectExample '博客 源码')** 最后修改:2022 年 06 月 09 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 2 如果觉得我的文章对你有用,请随意赞赏