美文网首页
利用Runtime清空单例属性

利用Runtime清空单例属性

作者: YannChee | 来源:发表于2018-01-03 14:40 被阅读87次
    - (void)qy_clearPropertyValue {
            // 1.存储属性的个数
            unsigned int propertyCount = 0;
            // 2.通过运行时获取当前类的所有属性
            objc_property_t *properties = class_copyPropertyList([self class], &propertyCount);
            // 3.遍历属性
            for (int i = 0; i < propertyCount; i ++) {
                objc_property_t property = properties[i];
                NSString *propertyName = [NSString stringWithFormat:@"%s", property_getName(property)];
                // 4.利用KVC 设置属性nil
                [self setValue:nil forKey:propertyName];
            }
            // 释放指针
            free(properties);
    }
    

    但是上面代码有一个重大bug:

    当对象里面的属性不是对象属性时(例如NSInteger CGFloat等),程序会崩溃,控制台报错:could not set nil as the value for the key

    解决办法:

    • 第一种:重写setNilValueForKey:方法,逐个属性判断

    • 第二种:异常捕捉,统一处理

    - (void)setNilValueForKey:(NSString *)key {
        if ([key isEqualToString:@"属性名1"]) {
            _属性1 = 0;
        }  else if ([key isEqualToString:@"属性名2"]) {
            _属性1 = 0;
        }
        ...
        ...
        ...
      else {
            [super setNilValueForKey:key];
        }
    }
    

    最优雅的写法应该是:

    - (void)qy_clearPropertyValue {
            // 1.存储属性的个数
            unsigned int propertyCount = 0;
            // 2.通过运行时获取当前类的所有属性
            objc_property_t *properties = class_copyPropertyList([self class], &propertyCount);
            // 3.遍历属性
            for (int i = 0; i < propertyCount; i ++) {
                objc_property_t property = properties[i];
                NSString *propertyName = [NSString stringWithFormat:@"%s", property_getName(property)];
                // 4.利用KVC 设置属性nil
                @try {
                    [self setValue:nil forKey:propertyName];
                } @catch (NSException *exception) {
                    [self setValue:@0 forKey:propertyName];
                } @finally {
                    //
                }
                
            }
            // 释放指针
            free(properties);
    }
    

    PS:诡异的死锁Bug:

    #pragma mark - 退出登录
    - (void)loginOut {
        UIAlertController *alertVc = [UIAlertController alertControllerWithTitle:nil message:@"您真的要退出吗?" preferredStyle:UIAlertControllerStyleAlert];
        [alertVc addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDefault handler:nil]];
        [alertVc addAction:[UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
                
                //  下面👇 这一行执行会有死锁的bug, app会卡主,处于假死状态
                [[QYMyInfoModel sharedMyInfoModel] qy_clearPropertyValue];
    
        }]];
      
        [self presentViewController:alertVc animated:YES completion:nil];    
    }
    

    但是,把那句代码放到异步线程执行,就不会死锁,不知道什么原因,如果有人知道,麻烦告知一下

    #pragma mark - 退出登录
    - (void)loginOut {
        UIAlertController *alertVc = [UIAlertController alertControllerWithTitle:nil message:@"您真的要退出吗?" preferredStyle:UIAlertControllerStyleAlert];
        [alertVc addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDefault handler:nil]];
        [alertVc addAction:[UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
                
                //  下面👇 这一行执行会有死锁的bug, app会卡主,处于假死状态,所以在异步线程执行
                      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                [[QYMyInfoModel sharedMyInfoModel] qy_clearPropertyValue];
            });
    
        }]];
      
        [self presentViewController:alertVc animated:YES completion:nil];    
    }
    

    相关文章

      网友评论

          本文标题:利用Runtime清空单例属性

          本文链接:https://www.haomeiwen.com/subject/ghshnxtx.html