前情提要
在iOS8版本的系统以后,需要实现高斯模糊的效果,通常我们的实现方法是如下代码实现的
#define OS_VERSION_8_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
if (OS_VERSION_8_LATER) {
UIBlurEffect *blur = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
_visualView = [[UIVisualEffectView alloc] initWithEffect:blur];
}
遇到的问题
参考如下问题:
- SVProgressHUD Crash
- 在iOS8下的NSUnknownKeyException
解决问题
为了防止程序在出现意外的NSUnknownKeyException
类型的crashlog信息,可以使用oc
特有的kvc特性和runtime机制进行解决
思路
通过转移特定类型,例如CALayer
的valueForUndefinedKey:
和setValue:forUndefinedKey:
的实现过程
实现方案
- 添加
NSObject
类型的类目NSObject+VFUK
类目 - 在类目文件
NSObject+VFUK.h
中添加+ (void)addCustomValueForUndefinedKeyImplementation: (IMP)handler;
- 添加实现过程
+ (void)addCustomValueForUndefinedKeyImplementation: (IMP)handler
{
Class clazz = self;
if (clazz == nil)
return;
if (clazz == [NSObject class] || clazz == [NSManagedObject class])
{
NSLog(@"不要为%@类添加自定义的valueForUndefinedKey:或setValue:forUndefinedKey:方法", NSStringFromClass(clazz));
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)
{
NSLog(@"%@已经自定义过%@名字的方法实现.",NSStringFromClass(clazz), NSStringFromSelector(svfuk));
return;
}
if (origMethod != nsoMethod && origMethod != nsmoMethod)
{
NSLog(@"%@已经自定义过%@名字的方法实现.",NSStringFromClass(clazz), NSStringFromSelector(vfuk));
return;
}
if(!class_addMethod(clazz, svfuk, handler, method_getTypeEncoding(set_nsmoMethod)))
{
NSLog(@"为%@类添加%@方法失败", NSStringFromClass(clazz),NSStringFromSelector(svfuk));
}
if(!class_addMethod(clazz, vfuk, handler, method_getTypeEncoding(nsoMethod)))
{
NSLog(@"为%@类添加%@方法失败", NSStringFromClass(clazz),NSStringFromSelector(vfuk));
}
}
}
测试代码
AppDelegate.m
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];
});
}
@end
ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSArray *array = @[@"1",@"2"];
[array setValue:@"xiaohao" forKey:@"name"];
NSLog(@"%@",[array valueForKey:@"name"]);
NSLog(@"可以相应该方法:%d",[@"xiaohao" respondsToSelector:@selector(name)]);
}
输出结果
exception key:xiaohao,class:__NSCFConstantString
exception key:xiaohao,class:__NSCFConstantString
exception key:name,class:__NSCFConstantString
exception key:name,class:__NSCFConstantString
(
"",
""
)
可以相应该方法:0
由此,我们便可以针对性的解决由于系统sdk原因导致的莫名NSUnknownException