• 自定义KVO(三)


    下面来实现KVO自动销毁:(在合适的时候,自动移除观察者)

    @implementation NSObject (FXKVO)

    - (void)dealloc{

        //指回父类

        Class superClass = [self class];//KVOStudent

        object_setClass(self, superClass);

    }

     

    这里出现一个问题,就是VC在销毁时候dealloc方法不调用:

    原因是dealloc会被所有NSObject的对象调用,相当于修改了系统方法,所以这样写是不对的

    使用运行时替换方法

     

     

    - (void)fx_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(FXKeyValueObservingOptions)options context:(nullable void *)context handBlock:(FXKVOBlock)handBlock{

     

        //1. 验证set方法

     

            [self judgeSetterMethodFromKeyPath:keyPath];

     

            //2. 动态生成子类

     

            Class newClass = [self creatChildClass:keyPath];

     

            //3. 当前对象的类,isa指向newClass

     

            object_setClass(self, newClass);

     

            //4. 保存KVO信息

     

            //集合 --> add map

     

            FXKVOInfo *info = [[FXKVOInfo alloc] initWithObserver:observer forKeyPath:keyPath options:options handBlock:handBlock];

     

            NSMutableArray *infoArray = objc_getAssociatedObject(self, (__bridge const void * _Nonnull)(FXKVOAssiociateKey));

     

            if(!infoArray) {

     

              //数组 -> 成员 强引用

     

                //self(vc) -> person ISA -> 数组 -> info -/weak/-> self(VC) ?

     

                //self.person -> FXKVO -> //内存问题,这里为什么没有形成循环引用?

     

                infoArray = [NSMutableArray arrayWithCapacity:1];

     

                objc_setAssociatedObject(self, (__bridge const void * _Nonnull)(FXKVOAssiociateKey), infoArray, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

     

            }

     

            [infoArray addObject:info];

     

        

     

        static dispatch_once_t onceToken;

     

        dispatch_once(&onceToken, ^{

     

            Method m1 = class_getInstanceMethod([self class], NSSelectorFromString(@"dealloc"));

     

            Method m2 = class_getInstanceMethod([self class], @selector(fx_dealloc));

     

            method_exchangeImplementations(m1, m2);

     

        });

     

    }

     

     发现dealloc野指针崩溃,拿不到父类,原因是在交互dealloc函数的时候,

      static dispatch_once_t onceToken;

        dispatch_once(&onceToken, ^{

            Method m1 = class_getInstanceMethod([self class], NSSelectorFromString(@"dealloc"));

            Method m2 = class_getInstanceMethod([self class], @selector(fx_dealloc));

            method_exchangeImplementations(m1, m2);

        });

    [self class]父类(KVOPerson)里面是没有析构函数(dealloc)的,所以这里交换的还是NSObject里面的析构函数,和之前的问题一样,交互了系统类,出现了不可预见的崩溃。
    那么目前的想法就是给父类添加一个dealloc方法是否就可以了,这样的话是否每个子类都要手动添加dealloc方法,不是很方便,而且不符合KVO原来的设计思想,KVO的设计本来的目的是想不对原来的类做侵入,所以和最初的设计思想是相悖的。

    所以初步想法是在动态子类里面添加析构方法(dealloc),在动态子类的析构函数里面,释放数组和info,这也是为什么系统给KVO添加dealloc,对原类没有侵入性,非常的安全。下面尝试下:

     

    // 添加dealloc -- 为什么系统给KVO添加dealloc

        SEL deallocSEL = NSSelectorFromString(@"dealloc");

        Method deallocM = class_getInstanceMethod([self class], deallocSEL);

        const char *deallocType = method_getTypeEncoding(deallocM);

        class_addMethod(newClass, setterSEL, (IMP)fx_dealloc, deallocType);

     

    static void fx_dealloc(id self, SEL _cmd, id newValue){

        Class superClass = [self class];//KVOStudent

        object_setClass(self, superClass);

    }

     

    把原来的析构函数注释掉,解决了前面的崩溃问题。

     

  • 相关阅读:
    Python基础-----lambda匿名函数
    Python基础-----函数嵌套及作用域
    Python基础-----递归
    Python基础-----函数
    Python基础-----字符串格式化
    Python基础-----数据类型
    Python基础-----运算符
    Python基础-----while循环练习
    Python基础-----while循环语句
    Python基础-----条件语句与初识基本数据类型(二)
  • 原文地址:https://www.cnblogs.com/coolcold/p/12127659.html
Copyright © 2020-2023  润新知