Article Source: http://onevcat.com/2012/04/objective-c-runtime/
If reproduced please specify the source, the ultimate original copyright
In-depth objective-c dynamic characteristics
Objective-c has quite a lot of dynamic characteristics, basic, is also often mentioned and used in the dynamic type (dynamic typing), dynamically binding and dynamic loading.
These dynamic characteristics are very common language features in the development of cocoa programs, and after that, OC also provides quite rich runtime features at the bottom, such as enumeration class attribute method, acquisition method implementation and so on. Although these lower-level operating characteristics are not essential in the normal development of cocoa, in some cases it is often easier to do so if you know these features and use them wisely.
Fundamentals of Dynamic characteristics
1. Dynamic type
That is, the runtime then determines the type of the object. This type of dynamic is very common in everyday applications, simply to say ID type. The ID type is a generic object class, and any object can be referred to by the ID pointer, whereas in practice, introspection is often used to determine the actual class of the object that it belongs to:
ID obj = someinstance; if ([obj iskindofclass:someclass]) { *classspecifiedinstance = (SomeClass *) obj; // Do Something to classspecifiedinstance which are an instance of SomeClass // ...}
-isMemberOfClass:
Is NSObject
the method used to determine NSObject
whether an object is a member of a class. As it is, it -isKindOfClass:
can be used to determine whether an object is a member of a class or its subclasses. These two methods are typical of the introspection method. After you have determined that the object is a member of a class, you can safely cast and continue to work later.
2. Dynamic binding
Based on the dynamic type, the type is determined after an instance object is determined. The object corresponding to the property and the response message is also fully determined, which is dynamic binding. Before proceeding, you need to clarify the concept of the message in Objective-c. Due to the dynamic characteristics of OC, the concept of "function" is rarely mentioned in OC, the traditional function is usually compiled with the parameter information and function implementation into the compiled source code, and the most commonly used in OC is the message mechanism. The method of invoking an instance is to send a message to the instance's pointer, which, after receiving the message, looks for a way to respond to the message from its own implementation.
Dynamic binding is done by binding certain properties and corresponding methods to the instance after the class of the instance is determined. The properties and methods referred to here, of course, include the new implementations that were not implemented in the class, but that are required at run time. In the cocoa layer, we generally send-respondstoselector to a NSObject object: or-instancesrespondtoselector: etc. to determine whether an object can respond to an SEL, And before the OC message forwarding mechanism is triggered, the corresponding class of +resolveclassmethod: and +resolveinstancemethod: will be called, at this time there is a chance to dynamically add a new method to the class or instance, that is, the implementation of the class can be dynamically bound. An example:
void dynamicmethodimp (ID self , SEL _cmd) { // implementation .... }
//该方法在OC消息转发生效前被调用
+ (BOOL) Resolveinstancemethod: (SEL) asel{ if (Asel = = @selector ( resolvethismethoddynamically)) { // to the new implementation returned as void in [self class], the SEL name is Asel, The specific content of the implementation is Dynamicmethodimp Class_addmethod ([self class], Asel, (IMP) dynamicmethodimp, "[email protected]:"); return YES; } return [Super Resolveinstancemethod:asel];}
Of course, you can call it anywhere you want class_addMethod
or method_setImplementation
(the former adds the implementation, the latter replaces the implementation) to complete the requirement of dynamic binding.
3. Dynamic loading
It is easy to understand that the required resources are loaded on demand, which is basically adapted to different models for iOS development. The most classic example is the loading of @2x images on the retina device, and the loading of the original image on an older normal screen device. With the launch of the retina ipad and the advent of possible Retina Macs, this feature is believed to be increasingly being used.
Deep Run-time features
The basic dynamic characteristics are very common in general cocoa development, especially dynamic types and dynamic bindings. Since the cocoa program uses a large number of protocol-delegate design patterns, most of the delegate pointer types must be IDs to meet the dynamic substitution of runtime delegate (this design pattern in Java is called strategy?). Not very understanding of Java, to rectify). OBJECTIVE-C also has some advanced or lower-level runtime features that are rare in general cocoa development and are used to write OC and other language interfaces. But if it is understood and used properly, some tricky problems can often be solved easily in cocoa development.
Most of these runtime features are /usr/lib/libobjc.A.dylib
provided by this dynamic library, which includes many APIs for classes, instance members, member methods, and messages, including getting a list of class instance variables, replacing methods in classes, adding variables to class members, dynamically changing method implementations, and so on. A complete list of APIs and manuals can be found here. Although the documentation at the beginning indicates that it is appropriate for Mac OS X objective-c 2.0, because these are the underlying methods of OC, they are identical for iOS development.
A simple example, such as when developing a universal app or game, when using IB to build a large number of custom UIs, one of the important issues in the process of moving from iphone to ipad is how to load the interface from different nib. Before iOS5, all UIViewController
will go when loading (or) using the default init
interface initWithNibName:bundle:
-loadNibNamed:owner:options:
. And because -loadNibNamed:owner:options
of the implementations we can't get, overloading them is difficult and risky. So when it comes to making the ipad version of nib, one simple way is to unify all of the nib naming methods and then replace the original method with a new, similar method that you implement -loadNibNamed:owner:options
, while ensuring that the non-ipad device is still the same loadNibNamed:owner:options
way. This task can be accomplished more simply by using the OC Runtime features.
The code is called when the program runs +swizze
, swaps its own implementation loadPadNibNamed:owner:options
and system loadNibNamed:owner:options
, and all loadNibNamed:owner:options
messages are then sent to be loadPadNibNamed:owner:options
processed by their own code.
+(BOOL) swizze { = Class_getinstancemethod (self, @selector (loadNibNamed:owner:options:)); if (! Oldmethod) { return NO; } = Class_getinstancemethod (self, @selector (loadPadNibNamed:owner:options:)); if (! Newmethod) { return NO; } Method_exchangeimplementations (Oldmethod, Newmethod); return
loadPadNibNamed:owner:options
is implemented as follows, note that in the case where the loadPadNibNamed:owner:options
exchange has previously been made, it is actually sent as a system loadNibNamed:owner:options
. This completes the loading of the different resources.
-(Nsarray *) loadpadnibnamed: (NSString *) name owner: (ID) Owner options: (Nsdictionary *) Options {nsstring*newname = [name stringbyreplacingoccurrencesofstring:@"@pad"Withstring:@""]; NewName= [NewName Stringbyappendingformat:@"@pad"]; //determine if there isNsfilemanager *FM =[Nsfilemanager Defaultmanager]; NSString* filepath =[[NSBundle Mainbundle] pathforresource:newname oftype:@ "nib"]; //the loadPadNibNamed:owner:options called here: actually for the post-swap method, i.e. loadNibNamed:owner:options: if([FM Fileexistsatpath:filepath]) {return[self loadpadnibnamed:newname owner:owner options:options]; } Else { return[self loadpadnibnamed:name owner:owner options:options]; }}
< Span class= "hljs-built_in" >< Span class= "hljs-string" >< Span class= "hljs-built_in" >< Span class= "Hljs-keyword" >< Span class= "Hljs-keyword" >&NBSP;
This is, of course, a simple example, and this function can be done in other ways. For example, adding Uiviewcontroller classes to reload Init, but such overloads are dangerous, because your Uiviewcontroller implementation you do not fully know, so because of overloading may cause some of the original INIT code is not overwritten, resulting in a non- Predicted errors. Of course, there is no problem with overloading VC init in the example above (because the method for Vc,init is automatically forwarded to loadNibNamed:owner:options, so the Init method does not do anything more complicated, So as long as the VC is initialized with INIT, then there is no problem. However, it is not guaranteed that such overloads are feasible for other classes. Therefore, using the above run-time Exchange method is a good choice for implementing an unknown system approach.
In-depth objective-c dynamic characteristics