前段时间在开发中遇到一个问题,需要将一个控制器的值传到另一个毫无关联的控制器上,不能用Block,不能用代理,然后考虑使用通知(NSNotification),但也遇到了很多问题,在这里与大家分享一些,问题最终还是解决了
比如大写字母为控制器:N代表导航控制器,T代表标签控制器,其他是普通控制器
N->T->A->B->C->D
N->T->E->F
当需要将D的值传给E,这种跨域跳转,我们不能用show,因为show过去后,A、B、C三个控制器没有被释放,模态跳转也一样,所以只能通过切换标签控制器的子控制类切换
跳转方法:
XMTabBarController *tabbarVC = (XMTabBarController *)[[UIApplication sharedApplication] keyWindow].rootViewController;
tabbarVC.selectedIndex = 1;
[self.navigationController popToRootViewControllerAnimated:YES];
现在,控制器可以跳转,但如何传值呢?
还有很多种方法,一是:通知 二是:NSUserDefaults 属性传值
我首先考虑的是通知传值
要想完成一个通知,主要有分三个执行步骤,而且是按顺序来的
顺序很重要,顺序很重要,顺序很重要,重要的事情说三遍
1)注册通知:
//注册通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notice:) name:@"sendMessage" object:nil];
ps:说一下几个参数意思:Observer:(谁来接受通知消息);selector(方法选择,执行哪个方法); name:(通知的名称,也可以说是通知消息的标识,按照这个来区分是否接受通知);object:(接受谁的通知,用这个参设置,nil为接受所有文件 发送的通知)。
2)发送通知:
//通过通知中心发送通知
[[NSNotificationCenter defaultCenter] postNotificationName:@"sendMessage" object:info userInfo:nil];
Name:(通知标识,与注册通知是的标识对应);object:(发送方);userInfo:(重点说一下,这是一个字典类型的对象,可以把需要传递 的值放进这个字典里)。
(2-1) 执行通知方法:实现注册通知是选择的方法,selector后边的。这里不在多说。
3)移除通知:
// 移除通知
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"sendMessage" object:nil];
问题就出现了:
当从控制器D跳到E时,第一次无法传值,第二次才成功,
原因是顺序的问题,控制器E 是从 控制器 D 跳转过来的,比D晚出现,在E中发送通知,D中注册通知并执行通知方法,显然是先执行post,然后执行add,所以第一次无法传值,第二次,通知已经被被注册了,所以可以传值
问题解决
只要保证add(注册通知)在post(发送通知)之前就可以了。
1.这种方法就是在B重写init方法,并把 [[NSNotificationCenter defaultCenter]addObserver: selector: name: object: ];方法写进init中,
2.把发送方法[[NSNotificationCenter defaultCenter]postNotificationName: object: userInfo:]; 写在点击按钮跳转出控制器的语句后边,这样就可以了。
#pragma mark ---------- 利用通知正向传值,需要在init方法中注册通知 ----------
-(instancetype)init {
self =[super init];
if (self) {
//注册通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notice:) name:@"sendMessage" object:nil];
}
return self;
}
总结:另外,通知是同步的,最好保持通知在同一个线程内,以免出现延迟或阻塞