处理系统valueForUndefinedKey:类型的crash报错

背景

最近上线项目中使用UIVisualEffectView(高斯模糊)出现[<__NSArrayI 0x17000b630> valueForUndefinedKey:]: this class is not key value coding-compliant for the key gaussianBlur.错误
初始化时出现下面错误:


错误日志.png

使用以下初始化方法:

- (UIVisualEffectView *)effectView{
    if(!_effectView){
        _effectView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]];
    }
    return _effectView;
}

该错误主要在ios8系统下才会出现的个别情况。查找了一些资料,该问题应该是系统bug. 那么就想如何避免该类型的报错导致crash.

处理方法

使用kvc和runtime机制防止程序出现意外的UnknownException类型的错误。(转移特定类型,如NSArray的valueForUndefinedKey: 和 setValue:forUndefinedKey:的具体实现)

实现

为NSObject添加分类:NSObject+VFUK.
在分类中实现自定义实现过程:
NSObject+VFUK.h

//
//  NSObject+VFUK.h
//  BlockRedpag
//
//  Created by 何其灿 on 2019/1/3.
//  Copyright © 2019 Lixiaoqian. All rights reserved.
//  处理系统 valueForUndefinedKey:错误

#import 

NS_ASSUME_NONNULL_BEGIN

@interface NSObject (VFUK)

///自定义valueForUndefinedKey:实现
+ (void)addCustomValueForUndefinedKeyImplementation:(IMP)handler;

@end

NS_ASSUME_NONNULL_END

NSObject+VFUK.m实现:

//
//  NSObject+VFUK.m
//  BlockRedpag
//
//  Created by 何其灿 on 2019/1/3.
//  Copyright © 2019 Lixiaoqian. All rights reserved.
//

#import "NSObject+VFUK.h"
#import 
#import 

@implementation NSObject (VFUK)

+ (void)addCustomValueForUndefinedKeyImplementation:(IMP)handler{
    Class clazz = self;
    if (clazz == nil) {
        return;
    }
    if (clazz == [NSObject class] || clazz == [NSManagedObject class])
  {
        return;
    }
    
    SEL vfuk = @selector(valueForUndefinedKey:);
    SEL svfuk = @selector(setValue:forUndefinedKey:);
    
    @synchronized([NSObject class]){
        Method nsoMethod = class_getInstanceMethod([NSObject class], vfuk);
        Method nsmoMethod = class_getInstanceMethod([NSManagedObject class], vfuk);
        Method origMethod = class_getInstanceMethod(clazz, vfuk);
        
        Method set_nsoMethod = class_getInstanceMethod([NSObject class], svfuk);
        Method set_nsmoMethod = class_getInstanceMethod([NSManagedObject class], svfuk);
        Method set_origMethod = class_getInstanceMethod(clazz, svfuk);
        
        
        if (set_origMethod != set_nsoMethod && set_origMethod != set_nsmoMethod) {
            return;
        }
        if (origMethod != nsoMethod && origMethod != nsmoMethod) {
            return;
        }
        
        if(!class_addMethod(clazz, svfuk, handler, method_getTypeEncoding(set_nsmoMethod))) {
        }
        
        if(!class_addMethod(clazz, vfuk, handler, method_getTypeEncoding(nsoMethod))) {
        }
    }
    
}

@end

实现以上类目后,在AppDelegate.m中对指定类型进行转移,如NSArray,NSString等。

static id UnknownExceptionKeyIMP(id self, SEL cmd, NSString* inKey)
{
    NSLog(@"exception key:%@,class:%@", inKey, [self class]);
    return nil;
}


@implementation AppDelegate

+ (void)initialize
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        [NSArray addCustomValueForUndefinedKeyImplementation: (IMP)UnknownExceptionKeyIMP];
        [NSString addCustomValueForUndefinedKeyImplementation: (IMP)UnknownExceptionKeyIMP];
        [NSDictionary addCustomValueForUndefinedKeyImplementation: (IMP)UnknownExceptionKeyIMP];
        [CALayer addCustomValueForUndefinedKeyImplementation: (IMP)UnknownExceptionKeyIMP];
    });
}

添加之后,如果项目中再使用一些非法的valueForKey或setValue:forKey:方法时,不至于崩溃闪退,从而可以避免一些系统NSUnknownException类型的报错。如下例子:

//不可变字典 进行setValue:ForKey:操作
    NSDictionary *dict = [NSDictionary dictionary];
    [dict setValue:@"heqican" forKey:@"name"];
//不可变数组进行setValue:forKey:操作
    NSArray *array = @[@"1",@"2"];
    [array setValue:@"松小宝" forKey:@"name"];

你可能感兴趣的:(处理系统valueForUndefinedKey:类型的crash报错)