前言
“这是我参与8月更文挑战的第16天,活动详情查看:8月更文挑战”
自定义 KVO
准备工作
上篇文章,我们对 KVO
的底层进行了详细的分析,那么这篇文章,就仿照 KVO
的实现,进行自定义。
因为在底层中,KVO
是以 NSObject+NSKeyValueObserving
分类的形式展示出来的,那么我们自定义,也先创建 NSObject+LGKVO
的分类。
在 NSObject+LGKVO.h
中:
- (void)lg_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
- (void)lg_removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
复制代码
在NSObject+LGKVO.m
中:
首先定义两个全局静态常量:
static NSString *const kLGKVOPrefix = @"LGKVONotifying_";
static NSString *const kLGKVOAssiociateKey = @"kLGKVO_AssiociateKey";
复制代码
再导入#import <objc/message.h>
头文件。
然后再分别把 getter
和 setter
方法给定义好,方便后面直接运行调试:
setter
方法
#pragma mark - 从get方法获取set方法的名称 key ===>>> setKey:
static NSString *setterForGetter(NSString *getter) {
if (getter.length <= 0) { return nil;}
NSString *firstString = [[getter substringToIndex:1] uppercaseString];
NSString *leaveString = [getter substringFromIndex:1];
return [NSString stringWithFormat:@"set%@%@:",firstString,leaveString];
}
复制代码
getter
方法
#pragma mark - 从set方法获取getter方法的名称 set<Key>:===> key
static NSString *getterForSetter(NSString *setter){
if (setter.length <= 0 || ![setter hasPrefix:@"set"] || ![setter hasSuffix:@":"]) { return nil;}
NSRange range = NSMakeRange(3, setter.length-4);
NSString *getter = [setter substringWithRange:range];
NSString *firstString = [[getter substringToIndex:1] lowercaseString];
return [getter stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:firstString];
}
复制代码
注册观察者
接着就在NSObject+LGKVO.m
中实现注册观察者方法,
思路是:
- 1: 验证是否存在
setter
方法 : 不让实例进来 - 2: 动态生成子类
- 3:
isa
的指向 :LGKVONotifying_LGPerson
- 4: 保存观察者
代码如下:
- (void)lg_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context{
// 1: 验证是否存在setter方法 : 不让实例进来
[self judgeSetterMethodFromKeyPath:keyPath];
// 2: 动态生成子类
Class newClass = [self createChildClassWithKeyPath:keyPath];
// 3: isa的指向 : LGKVONotifying_LGPerson
object_setClass(self, newClass);
// 4: 保存观察者
LGKVOInfo *info = [[LGKVOInfo alloc] initWitObserver:observer forKeyPath:keyPath options:options];
NSMutableArray *observerArr = objc_getAssociatedObject(self, (__bridge const void * _Nonnull)(kLGKVOAssiociateKey));
if (!observerArr) {
observerArr = [NSMutableArray arrayWithCapacity:1];
[observerArr addObject:info];
objc_setAssociatedObject(self, (__bridge const void * _Nonnull)(kLGKVOAssiociateKey), observerArr, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
}
复制代码
验证是否存在 setter
方法
#pragma mark - 验证是否存在setter方法
- (void)judgeSetterMethodFromKeyPath:(NSString *)keyPath{
Class superClass = object_getClass(self);
SEL setterSeletor = NSSelectorFromString(setterForGetter(keyPath));
Method setterMethod = class_getInstanceMethod(superClass, setterSeletor);
if (!setterMethod) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"老铁没有当前%@的setter",keyPath] userInfo:nil];
}
}
复制代码
动态生成子类
思路:
- ①、验证动态子类是否已经创建
- 如果是已创建了,就直接返回
- 如果是未创建,就进入②
- ②、创建子类
- 先申请类,需要父类、新类的名称、开辟新空间
- 再注册类
- 最后添加方法,需要
class
、setter
方法
#pragma mark - 动态生成子类
- (Class)createChildClassWithKeyPath:(NSString *)keyPath{
NSString *oldClassName = NSStringFromClass([self class]);
NSString *newClassName = [NSString stringWithFormat:@"%@%@",kLGKVOPrefix,oldClassName];
Class newClass = NSClassFromString(newClassName);
// 防止重复创建生成新类
if (newClass) return newClass;
/**
* 如果内存不存在,创建生成
* 参数一: 父类
* 参数二: 新类的名字
* 参数三: 新类的开辟的额外空间
*/
// 2.1 : 申请类
newClass = objc_allocateClassPair([self class], newClassName.UTF8String, 0);
// 2.2 : 注册类
objc_registerClassPair(newClass);
// 2.3.1 : 添加class : class的指向是LGPerson
SEL classSEL = NSSelectorFromString(@"class");
Method classMethod = class_getInstanceMethod([self class], classSEL);
const char *classTypes = method_getTypeEncoding(classMethod);
class_addMethod(newClass, classSEL, (IMP)lg_class, classTypes);
// 2.3.2 : 添加setter
SEL setterSEL = NSSelectorFromString(setterForGetter(keyPath));
Method setterMethod = class_getInstanceMethod([self class], setterSEL);
const char *setterTypes = method_getTypeEncoding(setterMethod);
class_addMethod(newClass, setterSEL, (IMP)lg_setter, setterTypes);
return newClass;
}
复制代码
保存观察者
这步需要新建一个 LGKVOInfo
继承于 NSObject
,用来保存观察者信息,将多个LGKVOInfo
实例添加到数组中,再通过关联对象保存到self
中,进行相关的操作。
详细代码如下:
在 LGKVOInfo.h
中:
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
typedef NS_OPTIONS(NSUInteger, LGKeyValueObservingOptions) {
LGKeyValueObservingOptionNew = 0x01,
LGKeyValueObservingOptionOld = 0x02,
};
@interface LGKVOInfo : NSObject
@property (nonatomic, weak) NSObject *observer;
@property (nonatomic, copy) NSString *keyPath;
@property (nonatomic, assign) LGKeyValueObservingOptions options;
- (instancetype)initWitObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(LGKeyValueObservingOptions)options;
@end
NS_ASSUME_NONNULL_END
复制代码
在 LGKVOInfo.m
中:
#import "LGKVOInfo.h"
@implementation LGKVOInfo
- (instancetype)initWitObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(LGKeyValueObservingOptions)options{
self = [super init];
if (self) {
self.observer = observer;
self.keyPath = keyPath;
self.options = options;
}
return self;
}
@end
复制代码
实现子类方法
在动态生成子类时,会重写class
和setter
方法,它们的IMP
分别指向lg_class
和lg_setter
函数地址。通过关联对象保存到self
中,这个就和上篇在分析 KVO
时那样,使用中间类重写后的class
方法,获取的还是原始类对象,就好像KVO
所做的一切都不存在似的。
lg_class
Class lg_class(id self,SEL _cmd){
return class_getSuperclass(object_getClass(self));
}
复制代码
lg_setter
:
思路:
- ①、消息转发:转发给父类,改变父类的值
- ②、获取观察者
- ③、对新、旧值进行处理
- ④、发送消息给观察者
static void lg_setter(id self,SEL _cmd,id newValue){
NSLog(@"来了:%@",newValue);
// 1: 消息转发 : 转发给父类
// 改变父类的值 --- 可以强制类型转换
NSString *keyPath = getterForSetter(NSStringFromSelector(_cmd));
id oldValue = [self valueForKey:keyPath];
void (*lg_msgSendSuper)(void *,SEL , id) = (void *)objc_msgSendSuper;
// void /* struct objc_super *super, SEL op, ... */
struct objc_super superStruct = {
.receiver = self,
.super_class = class_getSuperclass(object_getClass(self)),
};
//objc_msgSendSuper(&superStruct,_cmd,newValue)
lg_msgSendSuper(&superStruct,_cmd,newValue);
// 2: 拿到观察者
NSMutableArray *observerArr = objc_getAssociatedObject(self, (__bridge const void * _Nonnull)(kLGKVOAssiociateKey));
for (LGKVOInfo *info in observerArr) {
if ([info.keyPath isEqualToString:keyPath]) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{NSMutableDictionary<NSKeyValueChangeKey,id> *change = [NSMutableDictionary dictionaryWithCapacity:1];
//3 对新旧值进行处理
if (info.options & LGKeyValueObservingOptionNew) {
[change setObject:newValue forKey:NSKeyValueChangeNewKey];
}
if (info.options & LGKeyValueObservingOptionOld) {
[change setObject:@"" forKey:NSKeyValueChangeOldKey];
if (oldValue) {
[change setObject:oldValue forKey:NSKeyValueChangeOldKey];
}
}
// 4: 消息发送给观察者
SEL observerSEL = @selector(lg_observeValueForKeyPath:ofObject:change:context:);
objc_msgSend(info.observer,observerSEL,keyPath,self,change,NULL);
});
}
}
}
复制代码
移除观察者
思路:
- 移除观察者;
isa
指回原始类对象
- (void)lg_removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath{
NSMutableArray *observerArr = objc_getAssociatedObject(self, (__bridge const void * _Nonnull)(kLGKVOAssiociateKey));
if (observerArr.count<=0) {
return;
}
for (LGKVOInfo *info in observerArr) {
if ([info.keyPath isEqualToString:keyPath]) {
[observerArr removeObject:info];
objc_setAssociatedObject(self, (__bridge const void * _Nonnull)(kLGKVOAssiociateKey), observerArr, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
break;
}
}
if (observerArr.count<=0) {
// 指回给父类
Class superClass = [self class];
object_setClass(self, superClass);
}
}
复制代码
那么到了这里,KVO
的自定义就完成了,那么接下来就使用下:
- (void)viewDidLoad {
[super viewDidLoad];
self.person = [[LGPerson alloc] init];
NSLog(@"注册观察者之前:%s",object_getClassName(self.person));
[self.person lg_addObserver:self forKeyPath:@"nickName" options:(LGKeyValueObservingOptionNew|LGKeyValueObservingOptionOld) context:NULL];
NSLog(@"注册观察者之后:%s",object_getClassName(self.person));
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
self.person.nickName = @"KC";
}
#pragma mark - KVO回调
- (void)lg_observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
NSLog(@"%@",change);
}
- (void)dealloc{
NSLog(@"移除观察者之前:%s",object_getClassName(self.person));
[self.person lg_removeObserver:self forKeyPath:@"nickName"];
NSLog(@"end");
NSLog(@"移除观察者之后:%s",object_getClassName(self.person));
}
复制代码
看下打印结果:
自定义 KVO
— 函数式
函数式编程是把运算过程写成一系列嵌套的函数,然后进行调用。函数式编程支持函数作为第一类对象,也可以被称为闭包或者仿函数(functor
)对象。
函数式编程的优点:
-
①、
代码简洁,开发速度快
:函数式编程大量使用函数,减少了代码的重复,因此程序比较短,开发速度较快; -
②、
接近编程自然语言,易于理解
:函数式编程的自由度很高,可以写出很接近自然语言的代码; -
③、
代码管理更方便
:函数式编程不依赖外界的状态,也不会改变外界的状态,只要给与指定的参数,那么返回的结果必定是相同的。因此,每一个函数都可以被看做独立单元,十分有利于单元测试(unit testing
)和bug
修改(debugging
),也十分便于模块化组合; -
④、
易于并发编程
:函数式编程不需要考虑死锁(deadlock
),因为它不修改变量,所以根本不存在锁线程的问题。不必担心一个线程的数据,被另一个线程修改,所以可以很放心地把工作分摊到多个线程,部署并发编程(concurrency
)。
那么自定义 KVO
,为什么要使用函数式编程了?
上文通过lg_observeValueForKeyPath:ofObject:change:context:
这种调用方式很不方便。所以,我们引入函数式思想,通过block
来实现监听的回调。接下来我们就进行优化。
在LGKVOInfo.h
中,添加 LGKVOBlock
:
@interface LGLKVOInfo : NSObject
@property (nonatomic, weak) NSObject *observer;
@property (nonatomic, copy) NSString *keyPath;
@property (nonatomic, copy) LGKVOBlock handleBlock;
@end
@implementation LGLKVOInfo
- (instancetype)initWitObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath handleBlock:(LGKVOBlock)block {
if (self=[super init]) {
_observer = observer;
_keyPath = keyPath;
_handleBlock = block;
}
return self;
}
@end
复制代码
在NSObject+LGKVO.h
中,lg_addObserver
方法也添加 block
:
typedef void(^LGKVOBlock)(id observer,NSString *keyPath,id oldValue,id newValue);
@interface NSObject (LGKVO)
- (void)lg_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath block:(LGKVOBlock)block;
- (void)lg_removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
@end
复制代码
在NSObject+LGKVO.m
中,lg_addObserver
方法调整:
- (void)lg_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath block:(LGKVOBlock)block{
// 1: 验证是否存在setter方法 : 不让实例进来
[self judgeSetterMethodFromKeyPath:keyPath];
// 2: 动态生成子类
Class newClass = [self createChildClassWithKeyPath:keyPath];
// 3: isa的指向 : LGKVONotifying_LGPerson
object_setClass(self, newClass);
// 4: 保存信息
LGKVOInfo *info = [[LGKVOInfo alloc] initWitObserver:observer forKeyPath:keyPath handleBlock:block];
NSMutableArray *mArray = objc_getAssociatedObject(self, (__bridge const void * _Nonnull)(kLGKVOAssiociateKey));
if (!mArray) {
mArray = [NSMutableArray arrayWithCapacity:1];
objc_setAssociatedObject(self, (__bridge const void * _Nonnull)(kLGKVOAssiociateKey), mArray, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
[mArray addObject:info];
}
复制代码
在NSObject+SSLKVO.m
中,lg_removeObserver
方法调整:
- (void)lg_removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath{
NSMutableArray *observerArr = objc_getAssociatedObject(self, (__bridge const void * _Nonnull)(kLGKVOAssiociateKey));
if (observerArr.count<=0) {
return;
}
for (LGKVOInfo *info in observerArr) {
if ([info.keyPath isEqualToString:keyPath]) {
[observerArr removeObject:info];
objc_setAssociatedObject(self, (__bridge const void * _Nonnull)(kLGKVOAssiociateKey), observerArr, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
break;
}
}
if (observerArr.count<=0) {
// 指回给父类
Class superClass = [self class];
object_setClass(self, superClass);
}
}
复制代码
在NSObject+LGKVO.m
中,lg_setter
方法调整,无需调用KVO
回调方法,改为调用info
中保存的block
即可:
static void lg_setter(id self,SEL _cmd,id newValue){
NSLog(@"来了:%@",newValue);
NSString *keyPath = getterForSetter(NSStringFromSelector(_cmd));
id oldValue = [self valueForKey:keyPath];
// 消息转发 : 转发给父类
// 改变父类的值 --- 可以强制类型转换
void (*lg_msgSendSuper)(void *,SEL , id) = (void *)objc_msgSendSuper;
// void /* struct objc_super *super, SEL op, ... */
struct objc_super superStruct = {
.receiver = self,
.super_class = class_getSuperclass(object_getClass(self)),
};
//objc_msgSendSuper(&superStruct,_cmd,newValue)
lg_msgSendSuper(&superStruct,_cmd,newValue);
// 信息数据回调
NSMutableArray *mArray = objc_getAssociatedObject(self, (__bridge const void * _Nonnull)(kLGKVOAssiociateKey));
for (LGKVOInfo *info in mArray) {
if ([info.keyPath isEqualToString:keyPath] && info.handleBlock) {
info.handleBlock(info.observer, keyPath, oldValue, newValue);
}
}
}
复制代码
优化后了,再在控制器里面调用,就会简洁很多,代码如下:
- (void)viewDidLoad {
[super viewDidLoad];
self.person = [[LGPerson alloc] init];
NSLog(@"注册观察者之前:%s",object_getClassName(self.person));
[self.person lg_addObserver:self forKeyPath:@"nickName" block:^(id _Nonnull observer, NSString * _Nonnull keyPath, id _Nonnull oldValue, id _Nonnull newValue) {
NSLog(@"回调方法:%@ - %@",oldValue,newValue);
}];
NSLog(@"注册观察者之后:%s",object_getClassName(self.person));
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
self.person.nickName = @"KC";
}
- (void)dealloc {
NSLog(@"移除观察者之前:%s",object_getClassName(self.person));
[self.person lg_removeObserver:self forKeyPath:@"nickName"];
NSLog(@"移除观察者之后:%s",object_getClassName(self.person));
}
复制代码
运行后打印结果:
自动销毁机制
上篇文章中,我们分析了,在使用KVO
之后,必须手动移除观察者,有时候可能会把这个环节给忽略掉,那么我们是否可以重写子类的dealloc
方法,在需要其销毁的时候,自动移除观察者了。
动态生成子类
:首先在createChildClassWithKeyPath
方法里面添加dealloc
:
- (Class)createChildClassWithKeyPath:(NSString *)keyPath{
NSString *oldClassName = NSStringFromClass([self class]);
NSString *newClassName = [NSString stringWithFormat:@"%@%@",kLGKVOPrefix,oldClassName];
Class newClass = NSClassFromString(newClassName);
// 防止重复创建生成新类
if (newClass) return newClass;
/**
* 如果内存不存在,创建生成
* 参数一: 父类
* 参数二: 新类的名字
* 参数三: 新类的开辟的额外空间
*/
// 2.1 : 申请类
newClass = objc_allocateClassPair([self class], newClassName.UTF8String, 0);
// 2.2 : 注册类
objc_registerClassPair(newClass);
// 2.3.1 : 添加class : class的指向是LGPerson
SEL classSEL = NSSelectorFromString(@"class");
Method classMethod = class_getInstanceMethod([self class], classSEL);
const char *classTypes = method_getTypeEncoding(classMethod);
class_addMethod(newClass, classSEL, (IMP)lg_class, classTypes);
// 2.3.2 : 添加setter
SEL setterSEL = NSSelectorFromString(setterForGetter(keyPath));
Method setterMethod = class_getInstanceMethod([self class], setterSEL);
const char *setterTypes = method_getTypeEncoding(setterMethod);
class_addMethod(newClass, setterSEL, (IMP)lg_setter, setterTypes);
// 2.3.3 : 添加dealloc
SEL deallocSEL = NSSelectorFromString(@"dealloc");
Method deallocMethod = class_getInstanceMethod([self class], deallocSEL);
const char *deallocTypes = method_getTypeEncoding(deallocMethod);
class_addMethod(newClass, deallocSEL, (IMP)lg_dealloc, deallocTypes);
return newClass;
}
复制代码
- 动态生成子类时,添加的
dealloc
方法,IMP
指向lg_dealloc
函数地址,在lg_dealloc
方法里面:
static void lg_dealloc(id self,SEL _cmd) {
NSLog(@"自动销毁之前:%s",object_getClassName(self));
Class superClass = [self class];
object_setClass(self, superClass);
NSLog(@"自动销毁之后:%s",object_getClassName(self));
}
复制代码
- 自动销毁机制的使用,直接在控制器里面调用
dealloc
方法:
- (void)dealloc{
NSLog(@"已经销毁了");
}
复制代码
运行打印结果:
FBKVOController
探索
FBKVOController
的基本使用
FBKVOController
是Facebook
开源的一个基于系统KVO
实现的框架。支持Objective-C
和Swift
语言。
在gitHub 的下载地址
FBKVOController
的优点:
- 不需要手动移除观察者;框架自动帮我们移除观察者
- 函数式编程,可以一行代码实现系统
KVO
的三个步骤。 - 实现
KVO
与事件发生处的代码上下文相同,不需要跨方法传参数; - 增加了
block
和SEL
自定义操作对NSKeyValueObserving
回调的处理支持,提升使用KVO
的体验; - 每一个
keyPath
会对应一个block
或者SEL
,不需要在block
中使用if
判断keyPath
,也就是说,不需要统一的observeValueForKeyPath
方法里写if
判断; - 可以同时对一个对象的多个属性进行监听,写法简洁。
- 线程安全。
我们先看看FBKVOController
的使用,代码如下:
#import "ViewController.h"
#import <FBKVOController.h>
#import "LGPerson.h"
@interface ViewController ()
@property (nonatomic, strong) FBKVOController *kvoCtrl;
@property (nonatomic, strong) LGPerson *person;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.person = [[LGPerson alloc] init];
[self.kvoCtrl observe:self.person keyPath:@"name" options:(NSKeyValueObservingOptionNew) block:^(id _Nullable observer, id _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) {
NSLog(@"****%@****",change);
}];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
self.person.name = @"cooci";
}
- (FBKVOController *)kvoCtrl{
if (!_kvoCtrl) {
_kvoCtrl = [FBKVOController controllerWithObserver:self];
}
return _kvoCtrl;
}
@end
复制代码
- 这里是使用的
block
回调:
[self.kvoCtrl observe:self.person keyPath:@"name" options:(NSKeyValueObservingOptionNew) block:^(id _Nullable observer, id _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) {
NSLog(@"****%@****",change);
}];
复制代码
除了 block
方式调用,还可以使用其他的方式实现:
- 使用
action
回调:
[self.kvoCtrl observe:self.person keyPath:@"age" options:NSKeyValueObservingOptionNew action:@selector(lg_observerAge)];
复制代码
- 对可变数组的监听
[self.kvoCtrl observe:self.person keyPath:@"mArray" options:(NSKeyValueObservingOptionNew) block:^(id _Nullable observer, id _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) {
NSLog(@"****%@****",change);
}];
复制代码
FBKVOController
源码解析
初始化
注册观察者
- 在
_FBKVOInfo
类中,存储了观察者信息,包含:FBKVOController
、keyPath
、options
、block
等; - 将
observe
和info
进行关联;
observe
和info
的关联详情
- 在
FBKVOController
初始化的时候,就持有NSMapTable
,使用NSMapTable
代替关联对象; - 然后把
object
作为key
,获取NSMutableSet
类型的value
,同时,NSMutableSet
中存储_FBKVOInfo
; - 如果
infos
为空,进行创建,并添加到NSMapTable
中; - 当
infos
不为空之后,将info
对象添加到NSMutableSet
类型的infos
中; - 中间者
_FBKVOSharedController
是单例模式,负责真正的KVO
操作;
中间者_FBKVOSharedController
分析
- 注册系统
KVO
- 传入的
object
为实例对象,调用系统KVO
的注册观察者,开始对属性监听; - 传入
addObserver
方法的self
为当前单例的中介者; - 中间者持有
NSHashTable
,以弱引用的方式存储_FBKVOInfo
; - 通过
_FBKVOInfo
的_state
成员变量,根据枚举值_FBKVOInfoStateInitial
、_FBKVOInfoStateObserving
、_FBKVOInfoStateNotObserving
决定新增或删除KVO
;
- 传入的
- 实现回调
- 通过
info
获取FBKVOController
; - 从
FBKVOController
中,获取observer
,也就是真正的VC
; - 通过
info
获取block
并调用,传入必要的参数;
- 通过
- 销毁
拷贝自身持有的NSMapTable
到临时表,然后将其清空,再遍历临时表,从单例的中介者中,取消实例对象和infos
的关联
- 移除系统
KVO
的监听- 调用系统
KVO
的removeObserver
方法,移除观察者 - 销毁流程:
VC
销毁 –>FBKVOController
销毁 –> 中间者的unobserve
方法 –> 移除观察者
- 调用系统