什么是通知?
通知中心传值,可以跨越多个页面传值, 一般也是从后面的页面传给前面的页面。
通知传值的步骤
通知传值可分为三个步骤:
一.在发送者(视图二)中实现一个方法进行发送通知。
[[NSNotificationCenter defaultCenter] postNotificationName:@"TransDataNoti" object:nil userInfo:_dictionary];
//postNotificationName:之后的参数就是这个通知的名字,要和要和接收者中的名字一样,才能让接收者正确接收。
//object:接收对象。
//userInfo: 携带的参数,为字典类型的数据,在例子中我携带了一个字典,因为有时候我们要传递的参数不只是一个,所以把东西全部放在通知里面,在接收者中,根据字典里面的键来取出里面的值。
//_dictionary是我之前定义的一个字典实例。
二.在接收者(视图一)中注册通知,也就是接收者要进行接收通知,接收通知和发送通知的名字要一致。
//注册通知,用于接收通知,接收通知的名称必须和发送通知的名称保持一致才能接收到,否则无法接收到发出的通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notiReceived:) name:@"TransDataNoti" object:nil];
//注:务必让接收者中name后面的参数和发送者中的name后面的参数一样。
三.在接收者(视图一)中实现通知中的方法。
// 参数类型是NSNotification
- (void)notiReceived:(NSNotification*)sender {
self.textField.text = sender.userInfo[@"content"];
self.label.text = sender.userInfo[@"content"];
}
四.在不用的时候移除通知。
- (void)dealloc {
//移除所有通知
// [[NSNotificationCenter defaultCenter] removeObserver:self];
//移除某个通知
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"TransDataNoti" object:nil];
}
注意参数Observer为要删除的观察者,一定不能置为nil。
如果为nil它会报警告:
Null passed to a callee that requires a non-null argument。
iOS9以上对其不进行移除处理不会崩溃,但是如果这个对象是在监听一个单例对象的属性的话,在其他地方,又修改该属性,还是会崩溃。
界面传值的小实例
- 发送者(视图二)的NewViewController.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface NewViewController : UIViewController<UITextFieldDelegate>
@property (nonatomic, strong) UIButton *back;
@property (nonatomic, strong) UITextField *textField;
@property (nonatomic, copy) NSMutableDictionary *dictionary;
@end
NS_ASSUME_NONNULL_END
- 发送者(视图二)的NewViewController.m
#import "NewViewController.h"
@interface NewViewController ()
@end
@implementation NewViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor whiteColor];
self.title = @"子界面";
_back = [UIButton buttonWithType:UIButtonTypeRoundedRect];
_back.frame = CGRectMake(200, 300, 50, 40);
[_back setTitle:@"返回" forState:UIControlStateNormal];
[_back addTarget:self action:@selector(back:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_back];
_textField = [[UITextField alloc] initWithFrame:CGRectMake(100, 400, 250, 50)];
_textField.keyboardType = UIKeyboardTypeDefault;
_textField.borderStyle = UITextBorderStyleRoundedRect;
_textField.delegate = self;
[self.view addSubview:_textField];
}
//协议事件,textField结束编辑的时候执行
- (void)textFieldDidEndEditing:(UITextField *)textField {
NSString *string = [[NSString alloc] initWithString:_textField.text];
_dictionary = [[NSMutableDictionary alloc] init];
[_dictionary setObject:string forKey:@"content"];
}
//按钮事件
- (void)back:(UIButton*)button {
//发送通知回传数据,回传的数据格式自定义,这里定义为dictionary类型
[[NSNotificationCenter defaultCenter] postNotificationName:@"TransDataNoti" object:nil userInfo:_dictionary];
[self dismissViewControllerAnimated:YES completion:nil];
}
//点击空白处键盘回收,同时结束textField编辑
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[_textField endEditing:YES];
}
@end
- 接收者(视图一)的ViewController.h
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController<UITextFieldDelegate>
@property (nonatomic, strong) UIButton *button;
@property (nonatomic, strong) UITextField *textField;
@property (nonatomic, strong) UILabel *label;
@end
- 接收者(视图一)的ViewController.m
#import "ViewController.h"
#import "NewViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor whiteColor];
self.title = @"主界面";
_button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[_button setTitle:@"跳转" forState:UIControlStateNormal];
[_button addTarget:self action:@selector(jump:) forControlEvents:UIControlEventTouchUpInside];
_button.frame = CGRectMake(100, 200, 60, 30);
[self.view addSubview:_button];
_label = [[UILabel alloc] init];
_label.text = @"通知";
_label.frame = CGRectMake(200, 300, 100, 40);
[self.view addSubview:_label];
_textField = [[UITextField alloc] initWithFrame:CGRectMake(100, 400, 250, 50)];
_textField.keyboardType = UIKeyboardTypeDefault;
_textField.borderStyle = UITextBorderStyleRoundedRect;
_textField.delegate = self;
[self.view addSubview:_textField];
//注册通知,用于接收通知,接收通知的名称必须和发送通知的名称保持一致才能接收到,否则无法接收到发出的通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notiReceived:) name:@"TransDataNoti" object:nil];
}
- (void)notiReceived:(NSNotification*)sender {
self.textField.text = sender.userInfo[@"content"];
self.label.text = sender.userInfo[@"content"];
}
- (void)dealloc {
//移除所有通知
// [[NSNotificationCenter defaultCenter] removeObserver:self];
//移除某个通知
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"TransDataNoti" object:nil];
}
- (void)jump:(UIButton*)button {
NewViewController *show = [[NewViewController alloc] init];
show.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:show animated:YES completion:nil];
}
@end
- 效果图
- 点击跳转按钮进入第二个界面并且在textField中输入内容
- 再点击返回按钮返回第一个界面,发现label和textField中都有刚才输入的内容,传值成功
补充:
一.这是我豪哥发现的问题,让我学到了:
这是注册通知:
[[NSNotificationCenter defaultCenter] postNotificationName:@"Network" object:nil userInfo:self];
这是注册观察者:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(ClickEvents:) name:@"Network" object:nil];
如果你注册观察者处的object
写为nil
,那么你注册通知的object
写什么都可以接收到数据,但是你如果注册观察者处的object
写为self
,那么你注册通知的object
只能写self
,写其他的你都获取不到数据。
这是因为通知的查找方式并不是我们想象的那样,从注册通知处找观察者,恰恰相反的是,它是从你注册的观察者来找通知的,注册观察者的时候object
写为nil
它就代表可以接收所有的通知发来的数据。但是你要是写为self
,它就会从注册中心来找self
,找不到就不会调用,所以在这里我建议大家尽量把通知处的object
都写为nil
,防止不必要的麻烦,当然这只是对像我一样的菜鸟来说。
二.这是我美丽的房学姐问的:
假如你一个通知接收到通知然后执行回调方法为1秒,有10个观察者,那么得需要多长时间?
这个问题的答案是要需要10秒钟,因为通知的串联的关系,只能执行完一个后再执行另一个,这就相当于一个循环一样的,它会逐一执行,知道执行完毕,具体的让它共同执行的方法我还没太了解到,等了解了再添加补充。