ParkLU开发使用IOS黑魔法
ParkLU 开发
数据问题:(网络请求下的数据有坑,总是造成闪退)
1.关键字Key存在有时候不存在
2.关键字Key对应的value有时候有,有时候是“”、NULL、(null)或者干脆没有
解决方式:
使用RUNTIME,在运行时通过修改类的分发表中selector对应的函数,来修改方法的实现。简单来讲就是自己写方法替换系统方法的实现。
Method Swizzling简单介绍:
Method Swizzling是改变一个selector的实际实现的技术。通过这一技术,我们可以在运行时通过修改类的分发表中selector对应的函数,来修改方法的实现。
使用原因:
1.例如,我们想跟踪在程序中每一个view controller展示给用户的次数:当然,我们可以在每个viewcontroller的viewDidAppear中添加跟踪代码;但是这太过麻烦,需要在每个view controller中写重复的代码。创建一个子类可能是一种实现方式,但需要同时创建UIViewController, UITableViewController, UINavigationController及其它UIKit中view controller的子类,这同样会产生许多重复的代码。
2.iOS系统方法总是有可能因为越界而让程序崩溃(crash),我们这时可以考虑自己写方法替换系统的方法了。
3.字典的key-value,如果有nil也是崩溃的
刨根问底Objective-CRuntimehttp://www.cocoachina.com/ios/20141224/10740.html
MethodSwizzling
我们可以使用苹果的“黑魔法”Method Swizzling,Method Swizzling本质上就是对IMP和SEL进行交换。
MethodSwizzling原理
Method Swizzing是发生在运行时的,主要用于在运行时将两个Method进行交换,我们可以将Method Swizzling代码写到任何地方,但是只有在这段Method Swilzzling代码执行完毕之后互换才起作用。
而且Method Swizzling也是iOS中AOP(面相切面编程)的一种实现方式,我们可以利用苹果这一特性来实现AOP编程。
UIViewController+Extension.m 是一个controller的扩展,程序一旦启动绘画页面,这个.m离开会立刻编译
针对字典崩溃处理实现理解:
图1:
图2:
MethodSwizzling类簇
在我们项目开发过程中,经常因为NSArray数组越界或者NSDictionary的key或者value值为nil等问题导致的崩溃,对于这些问题苹果并不会报一个警告,而是直接崩溃,感觉苹果这样确实有点“太狠了”。
由此,我们可以根据上面所学,对NSArray、NSMutableArray、NSDictionary、NSMutableDictionary等类进行Method Swizzling,实现方式还是按照上面的例子来做。但是....你发现MethodSwizzling根本就不起作用,代码也没写错啊,到底是什么鬼?
这是因为Method Swizzling对NSArray这些的类簇是不起作用的。因为这些类簇类,其实是一种抽象工厂的设计模式。抽象工厂内部有很多其它继承自当前类的子类,抽象工厂类会根据不同情况,创建不同的抽象对象来进行使用。例如我们调用NSArray的objectAtIndex:方法,这个类会在方法内部判断,内部创建不同抽象类进行操作。
所以也就是我们对NSArray类进行操作其实只是对父类进行了操作,在NSArray内部会创建其他子类来执行操作,真正执行操作的并不是NSArray自身,所以我们应该对其“真身”进行操作。
1.通过runtime函数获取真正的类:
1.NSString *className = [NSString stringWithFormat:@"%@", [[NSMutableDictionarydictionaryWithObjectsAndKeys:@"parklu_yanggfDEV", @"key", nil] class]];
2. char name[100];
strcpy(name,(char *)[className UTF8String]);
3.Class class = objc_getClass(name);
这时class才是NSMutableDictionary真正的类
(同理: NSString *className = [NSString stringWithFormat:@"%@", [[NSDictionarydictionaryWithObjectsAndKeys:@"parklu_yanggfDEV", @"key", nil] class]];NSString *className = [NSStringstringWithFormat:@"%@", [[NSMutableString stringWithFormat:@"parklu_yanggfDEV"] class]];NSString *className = [NSStringstringWithFormat:@"%@", [@"parklu_yanggfDEV" class]]; NSString *className = [NSString stringWithFormat:@"%@", [[NSMutableArray arrayWithObjects:@"parklu_yanggfDEV", nil] class]];NSString *className = [NSStringstringWithFormat:@"%@", [[NSArray arrayWithObjects:@"parklu_yanggfDEV", nil] class]];)
2.方法覆盖:
[self swizzleInstanceMethod:class originSelector:@selector(objectForKey:)otherSelector:@selector(safe_YGF_mutable_objectForKey:)];
[self swizzleInstanceMethod:class originSelector:@selector(valueForKey:)otherSelector:@selector(safe_YGF_mutable_valueForKey:)];
[self swizzleInstanceMethod:class originSelector:@selector(setObject:forKey:)otherSelector:@selector(safe_YGF_mutable_setObjectForKey:forKey:)];
[self swizzleInstanceMethod:class originSelector:@selector(setValue:forKey:)otherSelector:@selector(safe_YGF_mutable_setValueForKey:forKey:)];
3.实现自定义的方法:
其他:
NSDictionary
NSMutableArray
介绍完毕