处理系统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 <Foundation/Foundation.h>

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 <CoreData/CoreData.h>
#import <objc/message.h>

@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"];
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • KVC KVC定义 KVC(Key-value coding)键值编码,就是指iOS的开发中,可以允许开发者通过K...
    暮年古稀ZC阅读 2,169评论 2 9
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,135评论 1 32
  • KVC(Key-value coding)键值编码,单看这个名字可能不太好理解。其实翻译一下就很简单了,就是指iO...
    我的梦工厂阅读 901评论 1 8
  • 1.设计模式是什么? 你知道哪些设计模式,并简要叙述?设计模式是一种编码经验,就是用比较成熟的逻辑去处理某一种类型...
    龍飝阅读 2,182评论 0 12
  • KVC(Key-valuecoding)键值编码,单看这个名字可能不太好理解。其实翻译一下就很简单了,就是指iOS...
    榕樹頭阅读 723评论 0 2