背景
最近上線項(xiàng)目中使用UIVisualEffectView(高斯模糊)出現(xiàn)[<__NSArrayI 0x17000b630> valueForUndefinedKey:]: this class is not key value coding-compliant for the key gaussianBlur.錯(cuò)誤
初始化時(shí)出現(xiàn)下面錯(cuò)誤:
使用以下初始化方法:
- (UIVisualEffectView *)effectView{
if(!_effectView){
_effectView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]];
}
return _effectView;
}
該錯(cuò)誤主要在ios8系統(tǒng)下才會(huì)出現(xiàn)的個(gè)別情況。查找了一些資料,該問題應(yīng)該是系統(tǒng)bug. 那么就想如何避免該類型的報(bào)錯(cuò)導(dǎo)致crash.
處理方法
使用kvc和runtime機(jī)制防止程序出現(xiàn)意外的UnknownException類型的錯(cuò)誤。(轉(zhuǎn)移特定類型,如NSArray的valueForUndefinedKey: 和 setValue:forUndefinedKey:的具體實(shí)現(xiàn))
實(shí)現(xiàn)
為NSObject添加分類:NSObject+VFUK.
在分類中實(shí)現(xiàn)自定義實(shí)現(xiàn)過程:
NSObject+VFUK.h
//
// NSObject+VFUK.h
// BlockRedpag
//
// Created by 何其燦 on 2019/1/3.
// Copyright ? 2019 Lixiaoqian. All rights reserved.
// 處理系統(tǒng) valueForUndefinedKey:錯(cuò)誤
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSObject (VFUK)
///自定義valueForUndefinedKey:實(shí)現(xiàn)
+ (void)addCustomValueForUndefinedKeyImplementation:(IMP)handler;
@end
NS_ASSUME_NONNULL_END
NSObject+VFUK.m實(shí)現(xiàn):
//
// 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
實(shí)現(xiàn)以上類目后,在AppDelegate.m中對指定類型進(jìn)行轉(zhuǎn)移,如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];
});
}
添加之后,如果項(xiàng)目中再使用一些非法的valueForKey或setValue:forKey:方法時(shí),不至于崩潰閃退,從而可以避免一些系統(tǒng)NSUnknownException類型的報(bào)錯(cuò)。如下例子:
//不可變字典 進(jìn)行setValue:ForKey:操作
NSDictionary *dict = [NSDictionary dictionary];
[dict setValue:@"heqican" forKey:@"name"];
//不可變數(shù)組進(jìn)行setValue:forKey:操作
NSArray *array = @[@"1",@"2"];
[array setValue:@"松小寶" forKey:@"name"];