Calling process
Pit point
1. The user manually calling Load causes Swzzling to swap back on
Swzzling only gets called once with dispatch_once_t
2. If a subclass does not implement a superclass method, swapping the method of that subclass will cause the superclass method to change. In this case, if the method of the parent class is called, the parent class cannot find the method, resulting in a crash
Try adding the method to swap first, and then swap again. So it’s better not to use swzlling.
3. None of the subclass parents implement this method.
If you use logic of two, it will result in infinite recursion. You need to determine whether the original method exists. Add an empty method if none exists.
implementation
#import "SQRuntimeTool.h"
#import <objc/runtime.h>
@implementation SQRuntimeTool
+ (void)sq_methodSwizzlingWithClass:(Class)cls oriSEL:(SEL)oriSEL swizzledSEL:(SEL)swizzledSEL{
if(! cls)NSLog(@" The exchange class passed in cannot be empty");
Method oriMethod = class_getInstanceMethod(cls, oriSEL);
Method swiMethod = class_getInstanceMethod(cls, swizzledSEL);
method_exchangeImplementations(oriMethod, swiMethod);
}
+ (void)sq_betterMethodSwizzlingWithClass:(Class)cls oriSEL:(SEL)oriSEL swizzledSEL:(SEL)swizzledSEL{
if(! cls)NSLog(@" The exchange class passed in cannot be empty");
Method oriMethod = class_getInstanceMethod(cls, oriSEL);
Method swiMethod = class_getInstanceMethod(cls, swizzledSEL);
// General exchange methods: Exchange methods you have -- go below because it means adding methods failed
// Exchange methods that you don't implement:
PersonInstanceMethod (SEL) -> swiMethod(IMP)
Swizzle personInstanceMethod(IMP) -> swizzledSEL
//oriSEL:personInstanceMethod
BOOL didAddMethod = class_addMethod(cls, oriSEL, method_getImplementation(swiMethod), method_getTypeEncoding(swiMethod));
if (didAddMethod) {
class_replaceMethod(cls, swizzledSEL, method_getImplementation(oriMethod), method_getTypeEncoding(oriMethod));
}else{ method_exchangeImplementations(oriMethod, swiMethod); }} + (void)sq_bestMethodSwizzlingWithClass:(Class)cls oriSEL:(SEL)oriSEL swizzledSEL:(SEL)swizzledSEL{
if(! cls)NSLog(@" The exchange class passed in cannot be empty");
Method oriMethod = class_getInstanceMethod(cls, oriSEL);
Method swiMethod = class_getInstanceMethod(cls, swizzledSEL);
if(! oriMethod) {// If oriMethod is nil, replace swizzledSEL with an empty implementation that does nothing as follows:
class_addMethod(cls, oriSEL, method_getImplementation(swiMethod), method_getTypeEncoding(swiMethod));
method_setImplementation(swiMethod, imp_implementationWithBlock(^(id self, SEL _cmd){ }));
}
// General exchange methods: Exchange methods you have -- go below because it means adding methods failed
// Exchange methods that you don't implement:
PersonInstanceMethod (SEL) -> swiMethod(IMP)
Swizzle personInstanceMethod(IMP) -> swizzledSEL
//oriSEL:personInstanceMethod
BOOL didAddMethod = class_addMethod(cls, oriSEL, method_getImplementation(swiMethod), method_getTypeEncoding(swiMethod));
if (didAddMethod) {
class_replaceMethod(cls, swizzledSEL, method_getImplementation(oriMethod), method_getTypeEncoding(oriMethod));
}else{ method_exchangeImplementations(oriMethod, swiMethod); }}@end
Copy the code
use
@implementation SQStudent (SQ)
// Add dispatch_once_t to prevent the user from calling the load method manually
+ (void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[SQRuntimeTool sq_betterMethodSwizzlingWithClass:self oriSEL:@selector(helloword) swizzledSEL:@selector(sq_studentInstanceMethod)];
});
}
- (void)sq_studentInstanceMethod{
NSLog(@"SQStudent class add SQobject method :%s",__func__);
[self sq_studentInstanceMethod];
}
@end
Copy the code