ibireme / YYKit

A collection of iOS components.
MIT License
13.99k stars 3.69k forks source link

NSObject+YYAdd.m 中交换实例方法为什么还需要重新添加? #387

Open qwind365 opened 7 years ago

qwind365 commented 7 years ago

Method originalMethod = class_getInstanceMethod(self, originalSel); Method newMethod = class_getInstanceMethod(self, newSel); if (!originalMethod || !newMethod) return NO;

class_addMethod(self,
                originalSel,
                class_getMethodImplementation(self, originalSel),
                method_getTypeEncoding(originalMethod));
class_addMethod(self,
                newSel,
                class_getMethodImplementation(self, newSel),
                method_getTypeEncoding(newMethod));

method_exchangeImplementations(class_getInstanceMethod(self, originalSel),
                               class_getInstanceMethod(self, newSel));

上面已经取到对应的实例方法,之后为什么还需要调用addMethod 再进行添加一次?我测试发现不添加也可以交换成功。

NSaylor commented 7 years ago

要先尝试添加原 selector 是为了做一层保护,因为如果这个类没有实现 原始方法"originalSel" ,但其父类实现了,那 class_getInstanceMethod 会返回父类的方法。这样 method_exchangeImplementations 替换的是父类的那个方法,这当然不是你想要的。所以我们先尝试添加 originalSel ,如果已经存在,再用 method_exchangeImplementations 把原方法的实现跟新的方法实现给交换掉。

faimin commented 7 years ago

楼上正解,有文章分析过这个问题, @qwind365 可以了解下