前言
很多時(shí)候,我們常常在使用數(shù)組的時(shí)候因?yàn)閿?shù)組越界而導(dǎo)致程序崩潰。我們通過(guò)runtime
中的特殊手段,實(shí)現(xiàn)在運(yùn)行時(shí)互換函數(shù),達(dá)到偷天換日效果。
Method Swizzling
Method Swizzling是發(fā)生在運(yùn)行時(shí)期的,主要是在運(yùn)行時(shí),將兩個(gè)Method交換。達(dá)到偷天換日的效果,Method Swizzling是面向切面編程的一種技術(shù)。
OBJC_EXPORT void method_exchangeImplementations(Method m1, Method m2)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
#import <Foundation/Foundation.h>
/**
* 不可變數(shù)組防越界崩潰處理
*/
@interface NSArray (AXKArray)
@end
#import "NSArray+AXKArray.h"
#import <objc/runtime.h>
@implementation NSArray (AXKArray)
+ (void)load
{
[super load];
Method originalMethod = class_getInstanceMethod(objc_getClass("__NSArrayI"), @selector(objectAtIndex:));
Method userMethod = class_getInstanceMethod(objc_getClass("__NSArrayI"), @selector(axk_objectAtIndex:));
if (!class_addMethod(objc_getClass("__NSArrayI"), @selector(objectAtIndex:), method_getImplementation(userMethod), method_getTypeEncoding(userMethod))) {
method_exchangeImplementations(originalMethod, userMethod);
}
}
- (id)axk_objectAtIndex:(NSUInteger)index
{
if (self.count - 1 < index) {
//異常處理,捕獲異常并拋出異
@try {
return [self axk_objectAtIndex:index];
}
@catch (NSException *exception) {
NSLog(@"不可變數(shù)組越界訪問(wèn)異常--%s--Crash Because Method--%s---以上異常", class_getName(self.class), __func__);
NSLog(@"異常下標(biāo)--%lu--", index);
NSLog(@"不可變數(shù)組越界訪問(wèn)異常日志%@", [exception callStackSymbols]);
return nil;
}
@finally {
}
} else {
return [self axk_objectAtIndex:index];
}
}
@end
類簇、替身、真身
在iOS中存在大量的有關(guān)類簇、真身、替身相關(guān)的類等
大家發(fā)現(xiàn)了嗎,__NSArrayI才是NSArray真正的類,而NSMutableArray又不一樣。我們可以通過(guò)runtime函數(shù)獲取真正的類:
objc_getClass("__NSArrayI")
下面我們列舉一些常用的類簇的“真身”:
類 | 真身 |
---|---|
NSArray | __NSArrayI |
NSMutableArray | __NSArrayM |
NSDictionary | __NSDictionaryI |
NSMutableDictionary | __NSDictionaryM |
Method Swizzling方法只能對(duì)替身的真身有效,對(duì)替身沒(méi)有效果。