一.创建一个继承自NSObject的类目GXJKVO,在.h文件中添加两个方法
//添加观察者
- (void)addObserver:(NSObject *)observer forKey:(NSString *)key withBlock:(void(^)(id observed, NSString *key, id oldValue, id newValue))block;
//删除观察者
- (void)removeObserver:(NSObject *)observer forKey:(NSString *)key;
二.在.m中实现这两个方法
1.首先声明两个唯一的key
NSString *const kClassPrefix = @"GXJKVOClassPrefix";
NSString *const kGXJKVOAssociateKey = @“GXJKVOObserverArrayKey";
2.添加一个新类的延展
@interface ObserveInfo : NSObject
@property (strong, nonatomic) id observer;
@property (copy , nonatomic) NSString * key;
@property (copy , nonatomic) void(^observerBlock) (id observerObject, NSString * key, id oldValue, id newValue);
+(id)instanceWithObserver:(id)observer forKey:(NSString *)key block:(void (^)(id, NSString *, id, id))block;
@end
@implementation ObserveInfo
+(id)instanceWithObserver:(id)observer forKey:(NSString *)key block:(void (^)(id, NSString *, id, id))block
{
ObserveInfo *observerInfo = [[ObserveInfo alloc]init];
if (observerInfo) {
observerInfo.observer = observer;
observerInfo.key = key;
observerInfo.observerBlock = block;
}
return observer;
}
@end
3.实现添加观察者、删除观察者方法
//函数 通过key获得setter方法名
NSString *getSetterName(NSString *key) {
NSString *firstCharacter = [key substringFromIndex:1];
return [NSString stringWithFormat:@"set%@%@",[firstCharacter uppercaseString],[key substringFromIndex:1]];
}
//函数 实现通过setter方法名取出key
NSString *getKey(NSString *setName) {
//去掉冒号
NSString *preName = [setName substringToIndex:setName.length - 1];
//去掉set
NSString * name = [preName substringFromIndex:3];
//获得首字母
NSString * firstCharacter = [name substringToIndex:1];
//返回字符串
return [NSString stringWithFormat:@"%@%@",[firstCharacter lowercaseString],[name substringFromIndex:1]];
}
//生成衍生类方法
- (Class)makeKVOClass:(Class)originClass
{
NSString *className = NSStringFromClass(originClass);
NSString *kvoClassName = [NSString stringWithFormat:@"%@%@",kClassPrefix,className];
Class kvoClass = objc_allocateClassPair(object_getClass(self), kvoClassName.UTF8String, 0);
objc_registerClassPair(kvoClass);
return kvoClass;
}
//判断衍生类是否已经实现当前key所对应的setter方法
- (BOOL)hasSelector:(SEL)aSelector
{
//获取方法链表并遍历
unsigned int methodCount = 0;
//获取方法链表
Method *methodArray = class_copyMethodList(object_getClass(self), &methodCount);
//遍历每个方法名
for (int i = 0; i < methodCount; i++) {
Method m = methodArray[i];
if (method_getName(m) == aSelector) {
free(methodArray);
return YES;
}
}
//否则返回NO
free(methodArray);
return NO;
}
//gxj_kvoSetter完成两个功能,1通过向父类发消息完成set本来的赋值功能,2并行调用观察者方法
void gxj_kvoSetter(id objc_self, SEL objc_cmd, id newValue) {
//获取当前的setter方法名
NSString *setterName = NSStringFromSelector(objc_cmd);
//获得key
NSString *key = getKey(setterName);
//获得oldValue
id oldValue = [objc_self valueForKey:key];
//objc_msgSendSuper()函数的参数是父类结构体,需要手动创建
struct objc_super selfSuper = {
.receiver = objc_self,
.super_class = class_getSuperclass(object_getClass(objc_self))
};
objc_msgSendSuper(&selfSuper, objc_cmd,newValue);
//并行回调观察者block
NSMutableArray *observeArray = objc_getAssociatedObject(objc_self, (__bridge const void *)kGXJKVOAssociateKey);
//遍历数组进行回调
for (ObserveInfo *info in observeArray) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
info.observerBlock(objc_self, key, oldValue, newValue);
});
}
}
//添加观察者
- (void)addObserver:(NSObject *)observer forKey:(NSString *)key withBlock:(void(^)(id observed, NSString *key, id oldValue, id newValue))block
{
//判断能否进行KVO,是否存在此key对应的属性setter方法
NSString *setterName = getSetterName(key);
Method setMethod = class_getInstanceMethod(object_getClass(self), NSSelectorFromString(setterName));
if (!setMethod) {
NSLog(@"无法KVO");
return;
}
//是否已经生成衍生类
NSString *className = NSStringFromClass(object_getClass(self));
Class kvoClass = object_getClass(self);
if (![className hasPrefix:kClassPrefix]) {
//生成当前类的衍生类
kvoClass = [self makeKVOClass:object_getClass(self)];
//生成衍生类后,改变当前的类的类标识,使self变成kvoClass的实例
object_setClass(self, kvoClass);
}
//判断衍生类是否已经实现当前key所对应的setter方法
if (![self hasSelector:NSSelectorFromString(setterName)]) {
//若未实现setter方法,则添加我们实现的kvoSetter
}
//完成以上,就可以将观察者添加到关联数组中
NSMutableArray *observerArray = objc_getAssociatedObject(self, (__bridge const void *)kGXJKVOAssociateKey);
ObserveInfo *observerInfo = [ObserveInfo instanceWithObserver:observer forKey:key block:block];
if (!observerArray) {
observerArray = [NSMutableArray array];
objc_setAssociatedObject(self, (__bridge const void *)(kGXJKVOAssociateKey), observerArray, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
[observerArray addObject:observerInfo];
}
//删除观察者
- (void)removeObserver:(NSObject *)observer forKey:(NSString *)key
{
NSMutableArray *observerArray = objc_getAssociatedObject(self, (__bridge const void *)kGXJKVOAssociateKey);
for (ObserveInfo * observerInfo in observerArray) {
if (observerInfo.observer == observer && [observerInfo.key isEqualToString:key]) {
[observerArray removeObject:observerInfo];
}
}
}
三.在ViewController中调用添加观察者方法
//创建一个model,添加一个name属性
Company *p1 = [Company new];
[p1 addObserver:self forKey:@"name" withBlock:^(id observed, NSString *key, id oldValue, id newValue) {
NSLog(@"object = %@, key = %@, oldValue = %@, newValue = %@",observed,key,oldValue,newValue);
}];
p1.name = @"Baidu";
p1.name = @"Tencent";
p1.name = @“Google";
当p1的属性name被修改时,会提示被修改。