OC—多界面传值
注:有关协议传值与属性传值的内容,在前面的博客中有介绍,这里就不在赘述了
通知传值
简介:通知传值是一种跨模块的通信机制,允许对象在不直接引用对方的情况下传递数据。通知传值使用NSNotificationCenter,它是观察者的一种实现方式,通知者的发送方负责发送NSNotification,通知的接收注册方注册成为观察者,处理通知
NSNotification类:(通知的载体)
@property (readonly, copy)NSString* name;//通知名称
@property (nullable, readonly, retain)id object;//发布者对象
@property (nullable, readonly, copy)NSDictionar* userInfo;//传递的参数
Notificationcenter类的核心方法:
+ (NSNotificationCenter* )defaultCenter;//获取全局通知中心- (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSString *)aName object:(nullable id)anObject;//添加观察者- (void)postNotificationName:(NSString *)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;//发布通知- (void)removeObserver:(id)observer;//移处观察者
使用步骤:
1.发送通知:
NSDictionary* userInfo = @{@"notice" : @(1)};[[NSNotificationCenter defaultCenter] postNotificationName:@"note" object:nil userInfo:userInfo];
注意:userInfo是用来传递数据得,需要用字典类型
2.监听通知:注册观察者
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeColor:) name:@"note" object:nil];
3.接收通知:回调方法
- (void)changeColor:(NSNotification* )notification {NSDictionary* dict = notification.userInfo;NSNumber* num = dict[@"notice"];if ([num intValue]) {self.view.backgroundColor = [UIColor blackColor];}
}
4.移除监听者:释放资源
在dealloc中移除监听者非常重要,防止内存泄露或崩溃:
典型应用场景:
登陆成功后,刷新首页
设置页面更改后,通知其他页面刷新UI
用户退出登录,用户清理数据
- 通知传值使用限制,适用范围
1.符合NSCoding协议的对象,对于自定义对象,需要实现NSCoding协议
2.必须手动移除通知观察者,避免内存泄漏,(原因:通知中心持有观察者对象的强引用)
3.传递的userInfo中的对象在通知发生后被系统自动释放,如果需要保留,可以copy一个副本
4.通知名称具有全局唯一性
- 实现NSCoding协议指南
1.NSCoding是OC中实现对象序列化(编码与解码)的核心协议,用于将对象转换为字节流(归档)或从字节流恢复对象(解档)
浅浅学习一下解档与归档的内容:
是一种用于对象序列化和反序列化的重要机制,核心目的是将对象转换为可存储或传输的字节流,以及将字节流还原为对象
NSKeyedArchiver与NSkeyedUnarchiver:
NSKeyedArchiver:归档工具类,通过键值对将对象编码为二进制数据
NSData *archivedData = [NSKeyedArchiver archivedDataWithRootObject:myObject]; [archivedData writeToFile:filePath atomically:YES];
NSkeyedUnarchiver:解档工具类,用于从二进制数据中解码对象
NSData *archivedData = [NSData dataWithContentsOfFile:filePath]; MyObject *decodedObject = [NSKeyedUnarchiver unarchiveObjectWithData:archivedData];
这个过程必须实现两个方法:
encodeWithCoder:将对象属性编码到归档中
initWithCoder:从归档中解码并初始化对象
@interface User : NSObject <NSCoding>
@property (nonatomic, copy) NSString *name;
@end@implementation User
- (void)encodeWithCoder:(NSCoder *)coder {[coder encodeObject:self.name forKey:@"name"];
}
- (instancetype)initWithCoder:(NSCoder *)coder {self = [super init];self.name = [coder decodeObjectForKey:@"name"];return self;
}
@end
KVO传值
KVO是观察者模式的一种具体实现,是apple提供的一套通知机制,允许对象监听另一个对应特殊属性的改变,并在改变时接收到该事件,一般继承自NSObject的对象都是默认支持KVO的。
KVO(Key-Value-Observing),即观察关键字值的变化,首先在子页面中声明一个待观察的属性,在返回主页面之前修改该属性的值。在主页面中提前分配并初始化子页面,并且注册对子页面中对应属性的观察者,在从子页面返回主页面之前通过修改观察者属性的值,在主页面中就能自动检测到这个改变,从而读取子页面数据。KVO只对属性发生作用。
底层原理:(基于OC的动态运行时特性)
1.动态创建子类:当对某个对象添加KVO观察时,系统会动态生成一个该对象类的子类,名为NSKVONotifying_原类名
2.重写setter方法:子类会重写被观察属性的setter方法。在方法中插入通知发送逻辑
3.isa混写:系统会将原对象的isa指针指向这个动态子类。使原对象实际成为子类的实例
4.通知触发:当调用setter方法时,子类会先调用父类(原类)的setter,再通知所有观察者
@interface NSKVONotifying_Person : Person - (void)setName:(NSString *)name; @end@implementation NSKVONotifying_Person - (void)setName:(NSString *)name {// 1. 调用原类的setter[super setName:name];// 2. 通知所有观察者属性已变更[self willChangeValueForKey:@"name"];[self didChangeValueForKey:@"name"]; } @end
- 传递方向:从前向后
KVO的基本使用流程:
1.注册观察者:监听某个属性
[self.person addOserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOldcontext:nil];
参数讲解:
self.person:被观察者对象
“name”:被观察者的属性名
options:监听新值、旧值等
选择监听的返回值的类型:
enum {NSKeyValueObservingOptionNew //接收方法中使用change参数传入变化后的新值NSKeyValueObservingOptionOld //接收方法中使用change参数传入变化前的旧值NSKeyValueObservingOptionInitial //change参数内容会包含新值NSKeyValueObservingOptionPrior //如果加入这个参数,接收方法会在变化前后分别调用一次,共两次,变化前的通知change参数
}
2.实现回调方法:监听属性变化
(2). 接受通知,使用方法observeValueForKeuPath:ofObject:change:context:
(3). 删除KVO,与通知传值相同
- (void)dealloc {[self removeObserver:self forKeyPath:@"name"];
}
- 使用注意与适用范围
1.KVO基于KVC实现,仅能观察通@property声明的属性,普通的成员变量无法被观察
2.基本类型需要NSNumber包装,不支持直接观察C结构体(如CGPoint),需要封装为对象属性
@property (nonatomic, assign) int age; //KVO会自动包装为NSNumber
3.动态属性(@dynamic):
若属性声明为@dynamic,需要手动实现KVO通知:
@interface DynamicPropertyClass : NSObject
@dynamic customProperty;
@implementation DynamicPropertyClass
- (void)setCustomProperty:(id)value {[self willChangeValueForKey:@"customProperty"];[self didChangeValueForkey;@"customProperty"];
}
@end
4.若多个KVO观察使用同一回调,需要通过context区分
Block传值
简介:
适用于后一个界面向前一个界面传值
Block 传值是一种反向数据传递机制,核心流程如下:
- 定义 Block 类型:在数据接收方(通常是子视图 / 子控制器)定义一个 Block 属性。
- 设置 Block 实现:在数据发送方(通常是父视图 / 父控制器)创建子对象时,为其 Block 属性赋值(实现数据处理逻辑)。
- 调用 Block:当子对象需要传递数据时,调用该 Block 并传入数据。
数据流向:子对象 → Block → 父对象
步骤:
1.在后一个页面定义一个Block属性
#import "SecondView.h"
@property (nonatomic, copy) void(^reutnblock)(NSString* str);
2.设置一个事件来触发返回上一级视图的时候,使用第一步定义的Block,把需要传递的值放在^Block内
#import "SecondView.h"
-(void)pressbutton{self.reutnblock(self.label.text);[self.navigationController popViewControllerAnimated:YES];
}
3.在前一个页面跳转到后一个页面的事件函数中,调用后一个页面的Block属性
#import "FirstView.h"
-(void)pressbutton {secondViewController* second = [[secondViewController alloc] init];second.reutnblock = ^(NSString * _Nonnull str) {self.label.text = str;};[self.navigationController pushViewController:second animated:YES];
}