sel在method_排序是遞增排列的,eg:01,02,03,04,05,06,07,08。markdown
static NEVER_INLINE IMP
resolveMethod_locked(id inst, SEL sel, Class cls, int behavior)
{
runtimeLock.assertLocked();
ASSERT(cls->isRealized());
runtimeLock.unlock();
// 動態方法決議: 給一次機會 從新查詢
if (! cls->isMetaClass()) { // 對象 - 類
// try [cls resolveInstanceMethod:sel]
resolveInstanceMethod(inst, sel, cls);
}
else { // 類方法 - 元類
// try [nonMetaClass resolveClassMethod:sel]
// and [cls resolveInstanceMethod:sel]
resolveClassMethod(inst, sel, cls);
if (!lookUpImpOrNil(inst, sel, cls)) {
resolveInstanceMethod(inst, sel, cls);
}
}
// chances are that calling the resolver have populated the cache
// so attempt using it
return lookUpImpOrForward(inst, sel, cls, behavior | LOOKUP_CACHE);
}
複製代碼
代碼舉例:app
建立一個分類重寫resolveInstanceMethod方法oop
+ (BOOL)resolveInstanceMethod:(SEL)sel{
NSLog(@"%@ 來了",NSStringFromSelector(sel));
if (sel == @selector(say666)) {
NSLog(@"%@ 來了",NSStringFromSelector(sel));
IMP imp = class_getMethodImplementation(self, @selector(sayMaster));
Method sayMMethod = class_getInstanceMethod(self, @selector(sayMaster));
const char *type = method_getTypeEncoding(sayMMethod);
return class_addMethod(self, sel, imp, type);
}
else if (sel == @selector(sayNB)) {
IMP imp = class_getMethodImplementation(objc_getMetaClass("CFPerson"), @selector(cfClassMethod));
Method sayMMethod = class_getInstanceMethod(objc_getMetaClass("CFPerson"), @selector(cfClassMethod));
const char *type = method_getTypeEncoding(sayMMethod);
return class_addMethod(objc_getMetaClass("CFPerson"), sel, imp, type);
}
return NO;
}
複製代碼
bool objcMsgLogEnabled = false;
static int objcMsgLogFD = -1;
bool logMessageSend(bool isClassMethod,
const char *objectsClass,
const char *implementingClass,
SEL selector)
{
char buf[ 1024 ];
// Create/open the log file
if (objcMsgLogFD == (-1))
{
snprintf (buf, sizeof(buf), "/tmp/msgSends-%d", (int) getpid ());
objcMsgLogFD = secure_open (buf, O_WRONLY | O_CREAT, geteuid());
if (objcMsgLogFD < 0) {
// no log file - disable logging
objcMsgLogEnabled = false;
objcMsgLogFD = -1;
return true;
}
}
// Make the log entry
snprintf(buf, sizeof(buf), "%c %s %s %s\n",
isClassMethod ? '+' : '-',
objectsClass,
implementingClass,
sel_getName(selector));
objcMsgLogLock.lock();
write (objcMsgLogFD, buf, strlen(buf));
objcMsgLogLock.unlock();
// Tell caller to not cache the method
return false;
}
複製代碼
/temp/msgSends:運行時寫入的目錄路徑ui
該方法是監控objc底層消息發送spa
void instrumentObjcMessageSends(BOOL flag)
{
bool enable = flag;
// Shortcut NOP
if (objcMsgLogEnabled == enable) //objcMsgLogEnabled:控制開關
return;
// If enabling, flush all method caches so we get some traces
if (enable)
_objc_flush_caches(Nil);
// Sync our log file
if (objcMsgLogFD != -1)
fsync (objcMsgLogFD);
objcMsgLogEnabled = enable;
}
複製代碼
建立一個CFPerson類,並添加一個方法sayHellocode
直接運行會在調用方法處崩潰orm
此刻咱們嘗試一下用instrumentObjcMessageSends方法將其包裹一下對象
在.m文件裏添加實現方法排序
- (id)forwardingTargetForSelector:(SEL)aSelector{
NSLog(@"%s - %@",__func__,NSStringFromSelector(aSelector));
// runtime + aSelector + addMethod + imp
return [super forwardingTargetForSelector:aSelector];
}
複製代碼
forwardingTargetForSelector來自蘋果官方解釋:文檔
當一個對象發送一個消息沒有接收者的時候,則返回其第一接收者。
此時再建立一個CFStudnet接收類供接收
- (id)forwardingTargetForSelector:(SEL)aSelector{
NSLog(@"%s - %@",__func__,NSStringFromSelector(aSelector));
return [CFStudnet alloc];}
複製代碼
對沒有進行轉發處理的消息將會還調用methodSignatureForSelector方法,具體解釋見蘋果官方文檔
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
NSLog(@"%s - %@",__func__,NSStringFromSelector(aSelector));
return [NSMethodSignature signatureWithObjCTypes:@"v@:"];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation{
NSLog(@"%s - %@",__func__,anInvocation);
// GM sayHello - anInvocation - "拋出去" - anInvocation
anInvocation.target = [CFStudnet alloc];
// anInvocation 保存 - 方法
[anInvocation invoke];
}
複製代碼