Small valley bottom exploration collection
-
Ah,, cause: I encountered a bug in the project these days, and my leader changed the code. I can’t say anything. The legendary black magic (ios-method swizzling) he can’t use, ready to write a little mocking him 😆.
-
There are many related articles on the net, but he does not check, this matter is troubled by ~~ (who let somebody else is a leader.
1. Method swizzling
Simple use of
-
- Common requirement: add dot statistics after coming into the page ~
At this point, of course, you can add them manually. But it will certainly add to your groan.
-
- Heh heh, the right time to introduce
Method swizzling
“, which is extremely comfortable
- Heh heh, the right time to introduce
-
- Simply write down the usage code
Guys, I’m just going to write the comments right in the code. (Today is mainly to analyze the source code with brothers ~)
// Let's create a category
#import #import
@implementation UIViewController (XG) only in load // Swizzling changes the global state. We want to make sure that swizzling executes once and is available on every thread. GCD singleton is perfect static dispatch_once_t onceToken; Dispatch_once (&onceToken, ^{dispatch_once(&onceToken, ^{)); // @selector SEL originalSeletor = @selector(viewDidAppear:); SEL swizzlingSelector = @selector(xg_textViewDidAppear:); //method Method originalMethod = class_getInstanceMethod(class, originalSeletor); Method swizzlingMethod = class_getInstanceMethod(class, swizzlingSelector); // Class class2 = object_getClass((id)self); // Method originalMethod2 = class_getClassMethod(class2, <#SEL _Nonnull name#>) // Method swizzlingMethod2 = class_getClassMethod(class2, BOOL didAddMethod = class_addMethod(class, originalSeletor, originalSeletor) method_getImplementation(swizzlingMethod), method_getTypeEncoding(swizzlingMethod)); If (didAddMethod) {// successful. Replace the class_replaceMethod(class, swizzlingSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)); } else{// Implementations(originalMethod, swizzlingMethod); }}); } - (void) xg_textViewDidAppear:(BOOL)animated{ [self xg_textViewDidAppear:animated]; NSLog(@"
xg_textViewDidAppear : %@",self); } @endCopy the code
This time when entering the interface will print ~
-
- Let’s just look at the output.
Method Swizzling is quite comfortable to use
2. Method swizzling
The source code
I was going to look at assembly calls, but when I saw the new objC4-818.2 source code, I did a project debugging on a sudden
2.1. Lock the source code
-
- Most brothers analyze problems by looking at source code. This approach is very 👍. (I am 😆, often under the guise of looking at the source water)
-
- Let’s analyze the source code ~
- 2.1 There are three main methods
class_addMethod
,class_replaceMethod
,method_exchangeImplementations
-
- Let’s analyze
class_addMethod
和class_replaceMethod
- Let’s analyze
Source code implementation ~
BOOL
class_addMethod(Class cls, SEL name, IMP imp, const char *types)
{
if(! cls)return NO;
mutex_locker_t lock(runtimeLock);
return! addMethod(cls, name, imp, types ? :"", NO);
}
IMP
class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)
{
if(! cls)return nil;
mutex_locker_t lock(runtimeLock);
returnaddMethod(cls, name, imp, types ? :"", YES);
}
Copy the code
-
- Analysis of difference ~
-
- Breakpoint debugging ~ (I create a new one
XGPerson
And then call the method)
- Breakpoint debugging ~ (I create a new one
They all end up with the addMethod method
2.2. Method swizzling
Source code analysis
-
addMethod
methods
static IMP
addMethod(Class cls, SEL name, IMP imp, const char *types, bool replace)
{
IMP result = nil;
runtimeLock.assertLocked();
checkIsKnownClass(cls);
ASSERT(types);
ASSERT(cls->isRealized());
method_t *m;
if ((m = getMethodNoSuper_nolock(cls, name))) {
// already exists
if(! replace) { result = m->imp(false);
} else{ result = _method_setImplementation(cls, m, imp); }}else {
// fixme optimize
method_list_t *newlist;
newlist = (method_list_t *)calloc(method_list_t::byteSize(method_t::bigSize, 1), 1);
newlist->entsizeAndFlags =
(uint32_t)sizeof(struct method_t::big) | fixed_up_method_list;
newlist->count = 1;
auto &first = newlist->begin()->big();
first.name = name;
first.types = strdupIfMutable(types);
first.imp = imp;
addMethods_finish(cls, newlist);
result = nil;
}
return result;
}
Copy the code
-
- Guys, I drew it
Mind mapping
Although the comparison of paintinglow
, ha ha
- Guys, I drew it
-
method_exchangeImplementations
Source code analysis
void method_exchangeImplementations(Method m1, Method m2)
{
if(! m1 || ! m2)return;
mutex_locker_t lock(runtimeLock);
IMP imp1 = m1->imp(false);
IMP imp2 = m2->imp(false);
SEL sel1 = m1->name();
SEL sel2 = m2->name();
m1->setImp(imp2);
m2->setImp(imp1);
// RR/AWZ updates are slow because class is unknown
// Cache updates are slow because class is unknown
// fixme build list of classes whose Methods are known externally?
flushCaches(nil, __func__, [sel1, sel2, imp1, imp2](Class c){
return c->cache.shouldFlush(sel1, imp1) || c->cache.shouldFlush(sel2, imp2);
});
adjustCustomFlagsForMethodChange(nil, m1);
adjustCustomFlagsForMethodChange(nil, m2);
}
Copy the code
This code is written clearly ~
And this is also very vivid description of SEL and IMP relationship.
3. The conclusion
- I hope this article will be helpful to you (I may not be qualified to say ~). More importantly, I hope this article will be seen by the leader ~😆