Application example of iOS message mechanism--Exception handling

Source: Internet
Author: User

Application example of iOS message mechanism--Exception handling

Recently found a common exception in the Project tool Nullsafe, analyzed its implementation principle, accidentally found a small bug, now share it, about this article demo has been uploaded to GitHub, read if there is harvest, welcome star, if there is doubt welcome issue, Everyone to study together. In iOS development, we may encounter the following scenario: The server returns us a field that is null, for example someValue:null , when we use a third-party tool to convert it, someValue = <null> this time if we judge the someValue type, we will see that it is: NSNull. So the question is, if the somevalue is to assign a value to the control, for example: This is the someLabel.text = someVlaue equivalent of someLabel.text = nil , obviously, there is no problem. but sometimes we may send a message to this seemingly nsstring object (because we define NSString * Somevalue in the model), such as: [someValue length] . This time because null this object does not have this method, that is to say: null 这个对象不能处理这个消息 all will be crash, let the program Flash back. So how do we deal with it to avoid this crash? How do we deal with the news?
First, let's look at NSObject.h a few of the ways we don't use them, and what they mean:

+ (BOOL) Resolveclassmethod: (SEL) sel;Determines if the method is found, if it is sent, adds it to the object, and returns Yes if no is returned. + (BOOL) Resolveinstancemethod: (SEL) sel;Similar to ditto-(ID) Forwardingtargetforselector: (SEL) Aselector;This method is used to specify an unrecognized message first to point to the Object + (Nsmethodsignature *) Instancemethodsignatureforselector: (SEL) Aselector;Iterate through an instance of a class the message is Nsmethodsignature, the return value contains a description of the method, and if the method cannot be found, then nil is returned. - (Nsmethodsignature *) Methodsignatureforselector: (SEL) Aselector;Iterate over an instance method or class method of a class to get the nsmethodsignature of this message-(void) Forwardinvocation: (Nsinvocation *) aninvocation;A subclass of NSObject can override this method in which messages are forwarded to other objects. When an object sends a message, but the object cannot respond to the message, runtime gives the object an opportunity to forward the message. This object is created by creating aThe Nsinvocation object invokes the Forwardinvocation method as a parameter, and the object calls this method to forward the message to other objects. This Nsinvocation object is actually obtained from the Nsmethodsignature returned in the previous method Methodsignatureforselector , So before we rewrite this method we have to rewrite the Methodsignatureforselector method. + (BOOL) Instancesrespondtoselector: (SEL) Aselector; //Does the instance of this class have the ability to do this selector, that is to say, this class has no such method-(IMP) Methodforselector: (SEL) Aselector; //Traverse an instance of a class method or a class method to get the IMP of this method (function pointer, point to the specific implementation of this method) + (IMP) Instancemethodforselector: (SEL) Aselector; //Traverse a list of instance methods of a class to get this method imp-(void) Doesnotrecognizeselector: (SEL) Aselector; if an object receives a message, but it cannot process the message, and the message is not forwarded, the system will call this method. At the same time, this method throws a nsinvalidargumentexception and throws an error.         

So how do these methods, in the system, call order? Let's see:


Process of message processing in iOS

It can be seen that when a message is sent to an object, if the object does not have a corresponding IML, then the object belongs to the class

+ (BOOL)resolveInstanceMethod:(SEL)sel

method, and then see if the SEL object can be executed, or if it cannot be executed, it will call the

(id)forwardingTargetForSelector:(SEL)aSelector

To find an object to handle this method (we can return an object that can handle this method), and if this method returns, it nil will call the object's

(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector

This method, if this method is called, still does not find the corresponding NSMethodSignature , then will call

(void)doesNotRecognizeSelector:(SEL)aSelector

This method, and throws an exception, if this time returns a valid one NSMethodSignature , then calls the

(void)forwardInvocation:(NSInvocation *)anInvocation

To the end of the processing of the message here.
So how do we get a Nsnull object to handle a message that it can't handle? At this point, we will certainly think of passing this message to other objects that can be processed. So here's the question: how can we find such an object? At this time we think of RunTime, using RunTime the objc_getClassList method, we can get all the classes registered in the entire project (as long as the project to add the class file, regardless of whether the class is used), we can filter out the use of the parent class, In order to save the number of cycles, because the subclass has inherited the method of the parent class, so have the ability to handle the message , and then first use the above mentioned instancesRespondToSelector to determine whether the class can respond to this message, if you can respond, you can use the above mentioned instanceMethodSignatureForSelector to get this NSMethodSignature , and returns. Through the above analysis, the system will call this forwardInvocation , this is the time we call Nsinvocation this invokeWithTarget method to send this message to nil, in OC to send any message to nil will not cause the program crash, At this point, a crash caused by the server's return data exception was resolved. This obviously increases the fault tolerance of the system, in the project debugging phase, may be due to the data is imperfect, so you can use this method to circumvent crash, but after the basic improvement of the data, we can remove this method so that we in the program crash, timely remind the backstage staff to improve the data.

Attached: Nullsafe implementation of the detailed:
@implementationNSNull (Nullsafe)-(Nsmethodsignature *) Methodsignatureforselector: (SEL) selector{@synchronized ([SelfClass]) {Find method signatureNsmethodsignature *signature = [Super Methodsignatureforselector:selector];if (!signature) {The message cannot be processed by nsnull, so we are looking for other classes that can be processed.StaticNsmutableset *classlist =NilStaticNsmutabledictionary *signaturecache =NilCache this found method signature so that the next searchif (Signaturecache = =Nil) {classlist = [[Nsmutableset alloc] init]; Signaturecache = [[Nsmutabledictionary alloc] init];Gets all the classes in the project, and removes classes that have subclasses.Objc_getclasslist: This method caches all classes, as well as the number of these classes. We need to provide a large enough cache to store them, so we have to call this function two times. The first time to determine the size of the buffer, the second time to fill this buffer.int numclasses = Objc_getclasslist (Null0); Class *classes = (class *) malloc (sizeof (Class) * (UnsignedLong) numclasses); Numclasses = Objc_getclasslist (classes, numclasses);Nsmutableset *excluded = [Nsmutableset set];for (int i =0; i < numclasses; i++) {Class SomeClass = classes[i];Filter out classes containing subclasses, add: Excluded class superclass = Class_getsuperclass (SomeClass);while (superclass) {if (superclass = = [NSObjectClass])If the parent class is nsobject, jump out of the loop and join Classlist {All classes used in the system are added to the classlist [Classlist Addobject:someclass];Break }The parent class is not nsobject, and its parent class is added to excluded [excluded Addobject:superclass]; Superclass = Class_getsuperclass (superclass); } }Delete all classes that contain subclassesfor (Class SomeClassIn excluded) {[Classlist removeobject:someclass];}Release memory free (classes); }First detect if the cache has this implementationNSString *selectorstring =Nsstringfromselector (selector); Signature = signaturecache[selectorstring];if (!signature) {Find the implementation of the methodfor (Class SomeClassin classlist) {if ([SomeClass instancesrespondtoselector:selector]) {signature = [SomeClass Instancemethodsignatureforselector:selector]; break;} } //cache for next use signaturecache[selectorstring] = signature?: [ NSNull NULL]; } else if ([Signature Iskindofclass:[ NSNull class]] {signature = nil;}} return signature;} }-(void) forwardinvocation: (nsinvocation *) Invocation { Span class= "hljs-comment" >//let nil deal with this invocation [invocation invokewithtarget:nil];} Span class= "Hljs-keyword" > @end            

In the original text, the author writes: [Excluded Addobject:nsstringfromclass (superclass)];
In this case classlist is stored in class, and the excluded is stored in a string, will lose its role in filtering out unnecessary classes, so I changed it to: [Excluded Addobject:superclass]; I do not know whether the author has considered other issues, but also may be due to their carelessness.



Strokes Xiangjiang River
Links: http://www.jianshu.com/p/b1de9404d7d9
Source: Pinterest
Copyright belongs to the author. Commercial reprint please contact the author for authorization, non-commercial reprint please specify the source.

Application example of iOS message mechanism--Exception handling

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.