Method and related Method Analysis
Reprinted please note source http://blog.csdn.net/uxyheaven
This article will explore how Methods functions are implemented in objc.
First, let's take a look at the definition of the method. method is an objc_method struct.
Objc_method
Objc_method is the description of a class method.
The definition is as follows:
Method class_getinstancemethod (class CLs, Sel SEL) {If (! CLS |! Sel) return NULL; return look_up_method (CLS, Sel, yes/* cache */, yes/* resolver */);} static method look_up_method (class CLs, Sel, bool withcache, bool withresolver) {method meth = NULL; // 1. if (withcache) {meth = _ cache_getmethod (CLS, Sel, & _ objc_msgforward_internal); If (meth = (method) 1) {// cache contains forward ::. stop searching. return NULL;} // 2. find your own if (! Meth) meth = _ class_getmethod (CLS, Sel); // 3. forward if (! Meth & withresolver) meth = _ class_resolvemethod (CLS, Sel); Return meth ;}IMP class_getmethodimplementation (class CLs, Sel name)
Return the call address of the CLS name method.
The definition is as follows:
Bool class_addmethod (class CLs, Sel name, IMP imp, const char * types) {If (! CLs) return no; rwlock_write (& runtimelock); imp old = addmethod (newcls (CLS), name, IMP, types?: "", No); rwlock_unlock_write (& runtimelock); return old? No: Yes;} static imp addmethod (class_t * CLs, Sel name, IMP imp, const char * types, bool replace) {imp result = NULL; rwlock_assert_writing (& runtimelock ); assert (types); Assert (isrealized (CLS); method_t * m; // 1. find the method if (M = getmethodnosuper_nolock (CLS, name) in the method list of your class {// already exists if (! Replace) {// do not replace, return M-> imp result = _ method_getimplementation (m);} else {// replace, set the m method of Cls to IMP result = _ method_setimplementation (CLS, M, IMP);} else {// fixme optimize // 2. create a method_list_t node method_list_t * newlist; newlist = (method_list_t *) _ calloc_internal (sizeof (* newlist), 1); newlist-> values = (uint32_t) sizeof (method_t) | fixed_up_method_list; newlist-> COUNT = 1; ne Wlist-> first. Name = Name; newlist-> first. types = strdup (types); If (! Ignoreselector (name) {newlist-> first. IMP = imp;} else {newlist-> first. IMP = (IMP) & _ objc_ignored_method;} // 3. add newlist to the CLS method list bool vtablesaffected = no; attachmethodlists (CLS, & newlist, 1, no, & vtablesaffected); // 4. refresh the CLS cache flushcaches (CLS); If (vtablesaffected) flushvtables (CLS); Result = NULL;} return result ;}
When class_addmethod is used, replace = No, so the CLS fails to be added when this method already exists.
IMP class_replacemethod (class CLs, Sel name, IMP imp, const char * types)
Replace the CLS name pointer
Void method_exchangeimplementations (method m1_gen, method m2_gen) {method_t * m1 = newmethod (m1_gen); method_t * M2 = newmethod (m2_gen); If (! M1 |! M2) return; rwlock_write (& runtimelock); If (ignoreselector (M1-> name) | ignoreselector (m2-> name) {// ignored Methods stay ignored. now they're both ignored. m1-> imp = (IMP) & _ objc_ignored_method; M2-> imp = (IMP) & _ objc_ignored_method; rwlock_unlock_write (& runtimelock); return ;} // The implementation pointer imp m1_imp = m1-> IMP; M1-> imp = m2-> IMP; M2-> imp = m1_imp; if (vtable_containsselector (M1-> name) | vtable _ Containsselector (m2-> name) {// don't know the class-will be slow if vtables are affected // fixme build list of classes whose methods are known externally? Flushvtables (null);} // fixme catch nsobject changing to custom RR // CLS-> setcustomrr (); // fixme update monomorphism if necessary rwlock_unlock_write (& runtimelock );}
Actually, there is a pitfall here. How does the method come from? Through class_getinstancemethod, if the subclass does not exist, the method of the parent class will be returned. If method_exchangeimplementations is used at this time, will replace the method for replacing the parent class, which is obviously not what we want. so, this is what we usually write.
IMP method_getImplementation(Method m){ return _method_getImplementation(newmethod(m));}static IMP _method_getImplementation(method_t *m){ if (!m) return NULL; return m->imp;}IMP method_setimplementation (method, IMP)
Set the new implementation pointer of the method and return the old implementation pointer.
const char *method_getTypeEncoding(Method m){ if (!m) return NULL; return newmethod(m)->types;}
Method and related Method Analysis