前面我们学习了协议传值与属性传值,协议传值里面关键点在于确实不要忘了在推出后页面的时候将后页面设置代理
backViewController.delegate = self;
后页面的数据通过将此代理作为对象,调用协议的对象方法用来传值,要传的数据会作为协议的对象方法的参数传入该协议方法,再在前页面用前页面的变量去接收协议方法的参数,即可在前页面的任意地方使用后页面传过来的数据,配合属性传值可以达到前后页面数据的互通,但这样很不方便,传一个数据要用到两种传值方式,光是听一下,血压都上来了。 我们的传值方法很多,我来介绍一下其他传值方法,相信在你看完以后对于传值方法会有更深的理解。 如果对于协议传值和属性传值还不熟悉的推荐看一下我的上一篇关于协议传值和属性传值的介绍。 协议传值与属性传值
block传值
block传值和协议传值比较像,都是从后页面传数据给前页面
block介绍
在了解block传值之前,我们还是先来看一下block的介绍 Block是带有自动变量的匿名函数,是C语言的一个扩充功能。Block本质上也是一个OC对象。 block其本质和变量相同,只不过block存储的数据是一个函数体,你可以像调用其他标准函数一样,传入参数,并切获得返回值。 传值:只要能拿到对方就能传值 顺传:给需要传值的对象,直接定义属性就能传值 逆传:用代理,block,就是利用block去代替代理
使用block传值
我们既然知道其方法和协议传值类似(反向传值),我可以借鉴,协议传值的思路去理清block传值的关系。 我们需要在后页面的.m文件中去定义一个block属性。
@property (nonatomic, copy) void (^dataBlock) (NSString* textOfData);
我这里想传一个NSString类型的变量,我可以在后页面的.m文件中再定义一个NSString类型变量
@property (nonatomic, strong) NSString* myTextOfData;
既然是后页面向前页面传值,那么和协议传值类似,在由后页面推向前页面的button事件函数中可以添加此block
- (void)pressSecondButton {
_dataBlock (myTextOfData);
[self dismissViewControllerAnimated:NO completion:nil];
}
接下来在前页面跳向后页面的Button事件函数中调用此block(dataBlock)
- (void)pressFirstButton {
BackViewController* backViewController = [[BackViewController alloc] init];
backViewController.block = ^(NSString* textOfData) {
self.TitleLabel.text = textOfData;
};
backViewController.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:nextViewController animated:NO completion:nil];
}
和协议传值类似,数据都是以一个函数参数的方式传过去的,学习过协议传值后,再去理解block传值就会方便很多。 接下来看看KVO传值
KVO传值
KVO介绍
在了解KVO传值前,按照惯例还是先来看看什么事KVO吧,家人们。 KVO是(Key - Value Observing)的简称,这是一种观察者模式的应用。当观察者将被观察者的某个属性设置为观察的对象时,若被观察的该属性值发生变化时,就会触发观察者对象所实现的KVO接口方法,从而达到通知观察者的目的。
注意:由于KVO通知是通过重写属性的setter方法实现的,所以必须通过属性的setter方法来改变属性值时KVO通知才会被触发,如果通过属性的"_"成员变量来修改属性值时是不会触发KVO的。
KVO只是监听setter方法,例如像可变数组添加元素的方法(addObject)它不属于setter方法,所以即使你向数组中add多少个元素也不会有监听反应。
已经学了那么多传值方法了,对于前后页面的具体数据我就不展示了,这里只关注函数里面的调用方案
使用KVO传值
既然是观察者模式,那我们势必是要去注册一个人去当这个观察者的,让他去盯着被观察者,被观察者的属性值发生变化的时候,我们观察者肯定也是第一个收到,该项变化的属性值的。
注册观察者
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
observer:观察者对象; KeyPath:要监测的键路径;options:需要监测的选项;context:上下文用来区分消息; 移除观察者 - (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
- 一定要在观察者消失之前调用removeObserver,否则会导致Crash。
监听回调 – (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey, id> *)change context:(nullable void *)context; 这里先简单看看这三个函数,这几个是使用KVO传值的关键 我们在使用KVO传值的时候,可以先建立一个NSObject的子类ObserverMan.h 其中声明一个属性 @property (nonamtic, assign) int number; 我们在一个viewcontroller中添加新建的子类的头文件,并为其设置一个属性名为 observerSon 在其实现文件中去初始化我们的新观察者并为其注册观察者身份
_observerSon = [[ObserverMan alloc] init];
[_observerSon addObserver:self forKeyPath:@"number" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
我们可以设置一button去更改这个numer
- (void)addNumber:(UIButton*)button {
static int a = 0;
_observerSon.number = a++;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
NSString *string = [[NSString alloc] initWithFormat:@"number:%d", _observerSon.number];
_label.text = string;
NSLog(@"old number: %@ --- new number: %@", [change valueForKey:@"old"], [change valueForKey:@"new"]);
}
- (void)dealloc {
[_observerSon removeObserver:self forKeyPath:@"number"];
}
我们现在已经了解了KVO的传值方式,接下来简单一说多界面中使用KVO传值
我们先创建一个后页面 为后页面创建一个按钮事件
- (void)pressBack:(UIButton*)button {
self.content = _textField.text;
[self dismissViewControllerAnimated:YES completion:nil];
}
接下来我们需要在前页面的头文件中去定义后页面的属性
@property (nonatomic, strong) BackViewController *back;
在推出后页面的按钮事件函数中初始化当前视图属性 并且为其注册观察者,主要的参数forKeyPath:@“content” (此处的content为后页面中自定义的属性content)
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
if ([keyPath isEqualToString:@"content"]) {
id value = [change valueForKey:@"new"];
_label.text = value;
}
}
记住在不用的时候销毁观察者,不能让他知道的太多了
通知传值
通知传值的介绍
首先通知传值也是逆向传值的一种,我们必须要 知道通知传值是谁要监听值的变化,谁就注册通知 特别要注意,通知的接受者必须存在这一条件 。可以跨越多个页面传值
- 注册通知
- 通知中心发送通知消息,其中name(通知名)前后要保持一致性
- 实现通知内部的方法,并实现传值
- 消息发送完之后,要移除通知
使用通知传值
在前页面注册通知 第三个参数的事件名,系统使用此事件名来区分不同的事件
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(message:)name:@“message” object:nil];
在前页面的实现文件中,添加函数,设置接受到通知的事件
- (void)message:(NSNotification *)text {
_textOfLabel.text = text.userInfo[@"textOfData"];
}
在前页面的dealloc将通知移除掉 移除通知:removeObserver:和removeObserver:name:object: 其中,removeObserver:是删除通知中心保存的调度表一个观察者的所有入口,而 removeObserver:name:object:是删除匹配了通知中心保存的调度表中观察者的一个入口。 注意参数removeObserver为要删除的观察者,一定不能置为nil。
- (void)dealloc {
-
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"message" object:self];
}
在后页面中建立一个通知中心,通过此通知中心来发送通知,将要传输的值作为object的值传给前页面
[[NSNotificationCenter defaultCenter] postNotificationName:@"message" object:nil userInfo:_dictionary];
发送通知,其中的name填写第一界面的name, 系统知道是第一界面来相应通知, object就是要传的值。 userInfo是一个字典, 如果要用的话,提前定义一个字典, 可以通过这个来实现多个参数的传值使用。
NSDictionary *zidian =[[NSDictionary alloc]initWithObjectsAndKeys:self.firstTextField.text,@"textOfData", nil];
NSNotification *notification =[NSNotification notificationWithName:@"message" object:nil userInfo:zidian];
[[NSNotificationCenter defaultCenter] postNotification:notification];
我目前所了解到的就这么多,个人学识有限,还望各位大佬指正,学习还是要再接再厉,多努力一点,大概能多幸运一点,我们下次再见。
|