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