在iOS开发新中经常会遇到在两个界面之间进行传值的情况,在页面之间进行数据传递有正向传递(控制器A跳转到控制器B),也有反向传值(控制器B跳转到A).可以通过属性,代理,block,通知等等. 就解释一下怎么使用block和代理进行页面之间反向传值;
使用block进行反向传值 在Xcode中创建新的项目 创建两个控制器A,B. 在A控制器中添加一个按钮,对按钮添加点击跳转到B控制器,然后再A中再次添加一个label,作为接受B控制器中传回来的值. 在B控制器中创建一个UITextField,用于输入信息. 在A控制器中.m文件中代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| // // ViewController.m // 反向传值 // // Created by 两好三坏 on 16/3/3. // Copyright © 2016年 qinakun. All rights reserved. // import "ViewController.h" 使用block传值的控制器 import "BlockVC.h" 使用delegate传值的控制器 import "DelegateVC.h" @interface ViewController () //用于接受数据的label @property (weak, nonatomic) IBOutlet UILabel *inputLabel; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } //跳转控制器的 - (IBAction)jumpVC:(id)sender { //调用block进行传值 // [self block]; //调用bdelegate进行传值 [self delegate]; } //使用block进行反向传值 -(void)block{ UIStoryboard *sb = [UIStoryboard storyboardWithName:@"BlockSB" bundle:nil]; BlockVC *blockVc = [sb instantiateViewControllerWithIdentifier:@"blockVC"]; //inputBlock是定义好的block [blockVc setInputBlock:^(NSString *string) { //在这里对A控制器的label进行设置,这个string参数是从B控制器中传过来的; self.inputLabel.text = string; }]; [self.navigationController pushViewController:blockVc animated:YES]; } //使用delegate进行反向传值 -(void)delegate{ DelegateVC *vc = [DelegateVC new]; //需要让控制器A成为控制器B的代理. vc.delegate = self; [self.navigationController pushViewController:vc animated:YES]; } //代理方法中给input进行传值 -(void)changeValue:(NSString *)string{ self.inputLabel.text = string; } @end
|
接下来是在控制器B中定义一个block的代码块,这个block的参数是字符串,在控制器B的.h文件中声明如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @property (nonatomic, copy) void (^inputBlock)(NSString *string); 控制器B的.m文件代码如下: import "BlockVC.h" @interface BlockVC () @property (weak, nonatomic) IBOutlet UITextView *input; @end @implementation BlockVC - (void)viewDidLoad { [super viewDidLoad]; } //点击屏幕是输入框失去第一响应者的资格 -(void)touchesBegan:(NSSet _)touches withEvent:(UIEvent _)event{ [self.input resignFirstResponder]; } //在控制器即将消失的时候调用, -(void)viewWillDisappear:(BOOL)animated{ [super viewWillDisappear:animated]; //取到输入框的内容保存在代码块中,在需要的时候将参数传给控制器A if (self.inputBlock) { self.inputBlock (self.input.text); } } @end
|
这样就算完成了一个简单的在两个页面之间进行反向传值的功能. 使用delegate进行反向传值 代理应用场景及使用步骤 对象A内部发生了一些事情,想通知对象B 对象B想监听对象A内部发生了什么事情 对象A想在自己的方法内部调用对象B的某个方法,并且对象A不能对对象B有耦合依赖 对象A想传递数据给对象B 以上情况,结果都一样:对象B是对象A的代理(delegate) 1.先搞清楚谁是谁的代理(delegate) 2.定义代理协议,协议名称的命名规范:控件类名 + Delegate 3.定义代理方法 代理方法一般都定义为@optional 代理方法名都以控件名开头 代理方法至少有1个参数,将控件本身传递出去 设置代理(delegate)对象 (比如myView.delegate = xxxx;) 代理对象遵守协议 代理对象实现协议里面该实现的方法 在恰当的时刻调用代理对象(delegate)的代理方法,通知代理发生了什么事情 (在调用之前判断代理是否实现了该代理方法) 这是代理的使用场景以及使用步骤,下面是使用delegate实现前面block实现的功能 假如控制器C想利用代理给控制器A传值,那么 控制器C要有一个协议 控制器要有一个代理属性 控制器A遵守C的代理协议,并且成为C的代理对象. 控制器C的.h文件中作出如下声明:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| // // DelegateVC.h // 反向传值 // // Created by 两好三坏 on 16/3/5. // Copyright © 2016年 qinakun. All rights reserved. // import UIKit/UIKit.h @class DelegateVC; //协议 @protocol DelegateVCDelegate //A需要实现的代理方法 -(void)changeValue:(NSString *)string; @end @interface DelegateVC : UIViewController //代理属性 @property(nonatomic,weak) iddelegate; @end [/objc] 然后在.m文件中代码: [objc] // // DelegateVC.m // 反向传值 // // Created by 两好三坏 on 16/3/5. // Copyright © 2016年 qinakun. All rights reserved. // import "DelegateVC.h" define kWidth [UIScreen mainScreen].bounds.size.width define kHeight [UIScreen mainScreen].bounds.size.height @interface DelegateVC () @property(nonatomic,strong) UITextField *textValue; @end @implementation DelegateVC - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; 创建一个输入框,添加到控制器C的view上; UITextField _tf = [[UITextField alloc] init]; tf.backgroundColor = [UIColor grayColor]; tf.frame = CGRectMake(kWidth _0.5 - 50, kHeight * 0.5, 100, 40); self.textValue = tf; [self.view addSubview:_textValue]; } //当控制器C消失的时候调用的方法 -(void)viewWillDisappear:(BOOL)animated{ [super viewWillDisappear:animated]; //如果有对象响应了代理,就执行if判断中的方法, if ([self.delegate respondsToSelector:@selector(changeValue:)]) { //把输入框中的text取出来作为代理方法的参数传送给控制器A [self.delegate changeValue:self.textValue.text]; } } @end
|
在页面中传值得方法有很多,使用通知,KVO,单例,还有偏好设置,归档解档都可以实现,看情况哪个方便就是用哪个咯….