0x600000220fa0>
现在color和number属性都不被观察了。
看一下实际的效果:
我们可以看到,现在color和number都不变了,验证此移除方法正确。
OK,现在知道了怎么用SJKVOController,我下面给大家看一下代码:
SJKVOController代码解析
先大致讲解一下SJKVOController的实现思路:
1.为了减少侵入性,SJKVOController被设计为NSObject的一个分类。
2.SJKVOController仿照了KVO的实现思路,在添加观察以后在运行时动态生成当前类的子类,给这个子类添加被观察的属性的set方法并使用isaswizzle的方式将当前对象转换为当前类的子类的实现。
3.同时,这个子类还使用了关联对象来保存一个“观察项”的set,每一个观察项封装了一次观察的行为(有去重机制):
包括观察自己的对象,自己被观察的属性,以及传进来的block。
4.在当前类,也就是子类的set方法被调用的时候做三件事情:
-第一件事情是使用KVC来找出当前属性的旧值。
-第二件事情是调用父类(原来的类)的set方法(设新值)。
-第三件事是根据当前的观察对象和key,在观察项set里面找出对应的block并调用。
再来看一下这个小轮子的几个类:
SJKVOController:
实现KVO主要功能的类。
SJKVOObserverItem:
封装观察项的类。
SJKVOTool:
setter和getter的相互转换和相关运行时查询方法等。
SJKVOError:
封装错误类型。
SJKVOHeader:
引用了运行时的头文件。
下面开始一个一个来讲解每个类的源码:
SJKVOController
再看一下头文件:
#import
#import"SJKVOHeader.h"
@interfaceNSObject(SJKVOController)
//==============addobserver===============//
-(void)sj_addObserver:
(NSObject*)observerforKeys:
(NSArray*)keyswithBlock:
(SJKVOBlock)block;
-(void)sj_addObserver:
(NSObject*)observerforKey:
(NSString*)keywithBlock:
(SJKVOBlock)block;
//=============removeobserver=============//
-(void)sj_removeObserver:
(NSObject*)observerforKeys:
(NSArray*)keys;
-(void)sj_removeObserver:
(NSObject*)observerforKey:
(NSString*)key;
-(void)sj_removeObserver:
(NSObject*)observer;
-(void)sj_removeAllObservers;
//=============listobservers===============//
-(void)sj_listAllObservers;
@end
每个方法的意思相信读者已经能看懂了,现在讲一下具体的实现。
从sj_addObserver:
forKeywithBlock:
开始:
sj_addObserver:
forKeywithBlock:
方法:
除去一些错误的判断,该方法作了下面几件事情:
1.判断当前被观察的类是否存在与传入key对应的setter方法:
SELsetterSelector=NSSelectorFromString([SJKVOToolsetterFromGetter:
key]);
MethodsetterMethod=[SJKVOToolobjc_methodFromClass:
[selfclass]selector:
setterSelector];
//error:
nocorrespondingsettermothod
if(!
setterMethod){
SJLog(@"%@",[SJKVOErrorerrorNoMatchingSetterForKey:
key]);
return;
}
2.如果有,判断当前被观察到类是否已经是KVO类(在KVO机制中,如果某个对象一旦被观察,则这个对象就变成了带有包含KVO前缀的类的实例)。
如果已经是KVO类,则将当前实例的isa指针指向其父类(最开始被观察的类):
//getoriginalclass(currentclass,maybeKVOclass)
NSString*originalClassName=NSStringFromClass(OriginalClass);
//如果当前的类是带有KVO前缀的类(也就是已经被观察到类),则需要将KVO前缀的类删除,并讲
if([originalClassNamehasPrefix:
SJKVOClassPrefix]){
//now,theOriginalClassisKVOclass,weshoulddestroyitandmakenewone
ClassCurrentKVOClass=OriginalClass;
object_setClass(self,class_getSuperclass(OriginalClass));
objc_disposeClassPair(CurrentKVOClass);
originalClassName=[originalClassNamesubstringFromIndex:
(SJKVOClassPrefix.length)];
}
3.如果不是KVO类(说明当前实例没有被观察),则创建一个带有KVO前缀的类,并将当前实例的isa指针指向这个新建的类:
//createaKVOclass
ClassKVOClass=[selfcreateKVOClassFromOriginalClassName:
originalClassName];
//swizzleisafromselftoKVOclass
object_setClass(self,KVOClass);
看一下如何新建一个新的类:
-(Class)createKVOClassFromOriginalClassName:
(NSString*)originalClassName
{
NSString*kvoClassName=[SJKVOClassPrefixstringByAppendingString:
originalClassName];
ClassKVOClass=NSClassFromString(kvoClassName);
//KVOclassalreadyexists
if(KVOClass){
returnKVOClass;
}
//ifthereisnoKVOclass,thencreateone
KVOClass=objc_allocateClassPair(OriginalClass,kvoClassName.UTF8String,0);//OriginalClassissuperclass
//pretendingtobetheoriginalclass:
returnthesuperclassinclassmethod
MethodclazzMethod=class_getInstanceMethod(OriginalClass,@selector(class));
class_addMethod(KVOClass,@selector(class),(IMP)return_original_class,method_getTypeEncoding(clazzMethod));
//finally,registerthisnewKVOclass
objc_registerClassPair(KVOClass);
returnKVOClass;
}
4.查看观察项set,如果这个set里面有已经保存的观察项,则需要新建一个空的观察项set,将已经保存的观察项放入这个新建的set里面:
//ifwealreadyhavesomehistoryobserveritems,weshouldaddthemintonewKVOclass
NSMutableSet*observers=objc_getAssociatedObject(self,&SJKVOObservers);
if(observers.count>0){
NSMutableSet*newObservers=[[NSMutableSetalloc]initWithCapacity:
5];
objc_setAssociatedObject(self,&SJKVOObservers,newObservers,OBJC_ASSOCIATION_RETAIN_NONATOMIC);
for(SJKVOObserverItem*iteminobservers){
[selfKVOConfigurationWithObserver:
item.observerkey:
item.keyblock:
item.blockkvoClass:
KVOClasssetterSelector:
item.setterSelectorsetterMethod:
setterMethod];
}
}
看一下如何保存观察项的:
-(void)KVOConfigurationWithObserver:
(NSObject*)observerkey:
(NSString*)keyblock:
(SJKVOBlock)blockkvoClass:
(Class)kvoClasssetterSelector:
(SEL)setterSelectorsetterMethod:
(Method)setterMethod
{
//addsettermethodinKVOClass
if(!
[SJKVOTooldetectClass:
OriginalClasshasSelector:
setterSelector]){
class_addMethod(kvoClass,setterSelector,(IMP)kvo_setter_implementation,method_getTypeEncoding(setterMethod));
}
//additemofthisobserver&&keypair
[selfaddObserverItem:
observerkey:
keysetterSelector:
setterSelectorsetterMethod:
setterMethodblock:
block];
}
这里首先给KVO类增加了setter方法:
//implementationofKVOsettermethod
voidkvo_setter_implementation(idself,SEL_cmd,idnewValue)
{
NSString*setterName=NSStringFromSelector(_cmd);
NSString*getterName=[SJKVOToolgetterFromSetter:
setterName];
if(!
getterName){
SJLog(@"%@",[SJKVOErrorerrorTransferSetterToGetterFaildedWithSetterName:
setterName]);
return;
}
//createasuperclassofaspecificinstance
Classsuperclass=class_getSuperclass(OriginalClass);
structobjc_supersuperclass_to_call={
.super_class=superclass,//superclass