实际开发中,几乎到处都会有用到传值,而传值分为正向传值以及逆(反)向传值,比如从界面一调到界面二,并将值从界面一传递到界面二,将此称之为正向传值;而从界面一调到界面二,再从界面二(或界面二的TableViewCell中的子控件)返回至界面一并将值传递给界面一的过程,称之为逆(反)向传值。在此,小编将给大家回顾一下实际开发中常用的正向传值以及逆向传值的几种方法,如果不当之处,欢迎指正!
正向传值
最常见的正向传值方式是属性传值,方便简单,理解起来也容易,举例代码如下:
- 属性传值
ZWSecondViewController.h文件
#import <UIKit/UIKit.h>
@interface ZWSecondViewController : UIViewController
//在界面二的.h文件中声明一个字符串的属性titleName
@property(nonatomic,copy)NSString *titleName;
@end
ZWFirstViewController.m文件
- (IBAction)clickFirstBtnAction:(id)sender {
ZWSecondViewController *secondVc = [[ZWSecondViewController alloc] init];
secondVc.titleName = @"我是第二个控制器";
[self presentViewController:secondVc animated:YES completion:nil];
}
ZWSecondViewController.m文件
- (void)viewDidLoad {
[super viewDidLoad];
///在界面二的.m文件中可以对该属性的值进行需要的操作
NSLog(@"%@", self.titleName);//打印结果:我是第二个控制器
}
逆(反)向传值
常见的逆(反)向传值包括代理,通知以及Block,下面一一给大家举例。
一、** 代理**
- 代理的步骤:
被代理者
》设置代理协议
》创建代理方法
》设置代理属性
》判断代理方法
代理者
》设置代理
》遵守代理协议
》实现代理方法
- 代理的注意事项:
1、"一对一",就像一个婴儿对象只对应一个保姆对象,对同一个协议,一个对象只能设置一个代理delegate,所以单例对象就不能用代理;
2、①协议定义时,尽量用关键字@required,和@optional来明确代理是否是必须实现某些方法 ②代理的类型需用id类型,weak修饰,d并写明要遵守的协议 ③就是在调用代理方法的时候需要判断代理是否实现该方法。 - 举例代码:
1、ZWSecondViewController.h文件中①设置代理协议,②创建代理方法③设置代理属性
/** 被代理者 **/
#import <UIKit/UIKit.h>
/*1.设置代理协议*/
@protocol ZWSecondDelegate <NSObject>
/*2.创建代理方法*/
//@optional为非必须实现方法,如果没有加@optional,默认为必须实现方法,跟@required一样
@required
//method 传递NSString类型的值
- (void)sendMessage:(NSString *)message;
@end
@interface ZWSecondViewController : UIViewController
//在界面二的.h文件中声明一个字符串的属性titleName
@property(nonatomic,copy)NSString *titleName;
/*3.设置代理属性*/
//声明属性,使用weak修饰
@property(nonatomic,weak)id<ZWSecondDelegate>delegate;
2、ZWSecondViewController.m文件中④判断代理方法
- (void)clickSecondBtnAction:(UIButton *)btn {
/*4.判断代理方法*/
if (self.delegate && [self.delegate respondsToSelector:@selector(sendMessage:)]) {
//赋值前验证代理方法是否存在,存在则赋值
[self.delegate sendMessage:@"我要调回至第一个控制器"];
}
//返回上一个控制器
[self dismissViewControllerAnimated:YES completion:nil];
}
3、ZWFirstViewController.m文件中①设置代理,②遵守代理协议③实现代理方法
/** 代理者 **/
#import "ZWFirstViewController.h"
#import "ZWSecondViewController.h"
/*2.遵守代理协议*/
@interface ZWFirstViewController ()<ZWSecondDelegate>
@end
@implementation ZWFirstViewController
- (IBAction)clickFirstBtnAction:(id)sender {
ZWSecondViewController *secondVc = [[ZWSecondViewController alloc] init];
/*1.设置代理*/
secondVc.delegate = self;
[self presentViewController:secondVc animated:YES completion:nil];
}
/*3.实现代理方法*/
- (void)sendMessage:(NSString *)message {
NSLog(@"message = %@",message);//打印结果:message = 我要调回至第一个控制器
}
二、** 通知**
“一对多”,在实际开发中,很多控制器都需要知道一个事件,应该用通知;而且可以在任意对象之间传递,不需要二者有联系,这也是使用通知的优点。当然他的实现和代理相比较稍微绕一点,注册,发通知,收通知
- 通知的步骤:
》获取通知中心对象
》添加监听者和监听的对象
》销毁
》被监听者 接收通知
》实现通知方法
- 通知的注意事项:
1.跟代理不同的是:代理是一对一(就像一个婴儿对象只对应一个保姆对象),通知是多对多(例如一个tx发布者可以对应n个监听者,同样一个监听者可以监听tx也可以监听wy),就是某个对象想告诉某个对象一些事,或者某个对象想监听某个对象的一些事件。
2.无论发布通知还是订阅通知,都需要通过消息中心:NSNotificationCenter
3.订阅了某个消息后,一定要记得在dealloc方法里移除订阅,否则除了性能的问题还会有其他的问题出现。 - 举例代码:
1.在* ZWSecondViewController.m*按钮中的点击事件中
- (void)clickSecondBtnAction:(UIButton *)ban {
/** 1.通过消息中心NSNotificationCenter发送通知消息*/
/**
NotificationName:通知名称,此处为sendMessage
object:发通知的对象
userInfo:发通知附带的额外消息
*/
[ [NSNotificationCenter defaultCenter] postNotificationName:@"sendMessage" object:self userInfo:@{@"message":@"返回第一个控制器"}];
//返回上一个界面
[self dismissViewControllerAnimated:YES completion:nil];
}
2.在ZWFirstViewController.m文件中
- (void)viewDidLoad {
[super viewDidLoad];
//2、注册观察者
/**
Observer:监听者
selector:通知方法
name:通知名称
object:nil代表所有的"sendMessage"消息不管是谁发出的,我都订阅,如果为某个对象,就代表只接受该对象发出的通知
*/
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(achiveMessage:) name:@"sendMessage" object:nil];
}
- (void)achiveMessage:(NSNotification *)notification {
//传递的值保存在通知的userInfo中
NSDictionary * dic = notification.userInfo;
//在此对传输的数据进行需要的操作
NSLog(@"message = %@", [dic objectForKey:@"message"]); //打印结果:message = 返回第一个控制器
}
//4、重写dealloc方法移除通知 如果不移除有可能会造成程序崩溃
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
三、** Block**
Block是目前开发最常用的一种方式,功能比较强大,但是在理解和使用上可能需要一段时间摸索和熟悉。他的最大特点就是回调,而且回调时可以传入参数,最重要的是,无论在哪调用,block的执行都会回到block创建的地方执行,而非调用的地方。而block本身可以封装一段代码。
- Block的优点:
1,写法更简练,不需要写protocol、函数等
2,block注重结果的传输:比如对于一个事件,只想知道成功或者失败,并不需要知道进行了多少或者额外的一些信息。
3,block需要注意防止循环引用:
在ARC模式下这样防止:
*__weak typeof(self) weakSelf = self;*
- Block的注意事项
1.访问外部变量的问题
① 在block代码块的内部可以定义1个和外部的变量名称相同的变量访问的时候,是就近原则.
②在block代码块的内部可以去取出外部的全局变量和局部变量的值.但是,在block代码块的内部,可以修改全局变量的值,但是不能修改外部的局部变量的值
③如果就是希望在block代码块的内部去修改外部的局部变量的值.那么就给这个局部变量加个__block的修饰符.
- 举例代码:
1.ZWSecondViewController.h文件中定义一个block类型的属性, 属性名为myBlock的属性,
#import <UIKit/UIKit.h>
@interface ZWSecondViewController : UIViewController
//1.定义带两个NSString类型的参数的myBlock属性
@property(nonatomic,copy)void(^myBlock)(NSString *,NSString *);
@end
2.ZWSecondViewController.m文件中
- (void)clickSecondBtnAction:(UIButton *)btn {
//2、给block属性赋值 传递参数
//执行存储在block变量中的代码
self.myBlock(@"我要返回第一个控制器",@"这是我传回来的值");
//返回上一个界面
[self dismissViewControllerAnimated:YES completion:nil];
}
3.ZWFirstViewController.m文件中
- (IBAction)clickFirstBtnAction:(id)sender {
ZWSecondViewController *secondVc = [[ZWSecondViewController alloc] init];
secondVc.myBlock = ^(NSString *str1,NSString *str2){
//此处的str1和str2为回调的参数,在此可以对此参数进行相应的操作使用
NSLog(@"str1 = %@", str1); //打印结果:str1 = 我要返回第一个控制器
NSLog(@"str2 = %@", str2); //打印结果:str2 = 这是我传回来的值
};
[self presentViewController:secondVc animated:YES completion:nil];
}
网友评论