標籤:swizzling objective ios
奇技淫巧 指過於奇巧而無益的技藝與製品.
IMS指的是 Instance Method Swizzling, 執行個體方法混淆.
下段代碼是一個Instance Method Swizzling和一個Method Swizzling的例子:
// Man.m- (void)run{ NSLog(@"%s, %@", __func__, _name);}- (void)jump{ NSLog(@"%s, %@", __func__, _name);}- (void)handsUp{ NSLog(@"%s, %@", __func__, _name);}- (void)handsDown{ NSLog(@"%s, %@", __func__, _name);}// ViewController.m- (void)viewDidLoad { ... Man *a = [Man manWithName:@"a"]; Man *b = [Man manWithName:@"b"]; [self swizzleInstanceMethodWithInstance:a originalSel:@selector(run) replacementSel:@selector(jump)]; [self swizzleInstanceMethodWithClass:[Man class] originalSel:@selector(handsUp) replacementSel:@selector(handsDown)]; [a run]; [b run]; [a handsUp]; [b handsUp];}// 輸出的結果是2015-03-14 23:53:39.832 testRuntime[2196:629365] -[Man jump], a2015-03-14 23:53:39.833 testRuntime[2196:629365] -[Man run], b2015-03-14 23:53:39.833 testRuntime[2196:629365] -[Man handsDown], a2015-03-14 23:53:39.833 testRuntime[2196:629365] -[Man handsDown], b
為什麼run方法是只有對象a被替換了,handsUp方法是都被替換了呢?
我們先來看下普通的Method Swizzling是如何?的
- (void)swizzleInstanceMethodWithClass:(Class)clazz originalSel:(SEL)original replacementSel:(SEL)replacement{ Method a = class_getInstanceMethod(clazz, original); Method b = class_getInstanceMethod(clazz, replacement); // class_addMethod 為該類增加一個新方法 if (class_addMethod(clazz, original, method_getImplementation(b), method_getTypeEncoding(b))) { // 替換類方法的實現指標 class_replaceMethod(clazz, replacement, method_getImplementation(a), method_getTypeEncoding(a)); } else { // 交換2個方法的實現指標 method_exchangeImplementations(a, b); }}
Instance Method Swizzling是用了類似KVO的辦法.
先動態添加一個類MySubclass繼承自原來的類,然後修改對象a的isa為新類,再替換掉新類的方法.
- (void)swizzleInstanceMethodWithInstance:(id)object originalSel:(SEL)original replacementSel:(SEL)replacement{ Class newClass = objc_allocateClassPair([object class], "MySubclass", 0); objc_registerClassPair(newClass); Method a = class_getInstanceMethod(newClass, original); Method b = class_getInstanceMethod([object class], replacement); if (class_addMethod(newClass, original, method_getImplementation(b), method_getTypeEncoding(b))) { class_replaceMethod(newClass, replacement, method_getImplementation(a), method_getTypeEncoding(a)); } else { method_exchangeImplementations(a, b); } object_setClass(object, newClass);}
Objective-C 奇巧淫技--IMS