IOS Runtime Utility Article---avoid common crashes

Source: Internet
Author: User
Tags reserved string format

This article is collected from: http://www.jianshu.com/p/5d625f86bd02

Source Code

Https://github.com/chenfanfang/AvoidCrash program Crash experience

In fact, very early to write this article, has been dragged until now. Program crashes experience 1 What our company does is stock software, but the integration is a third party static library (our company and third party company cooperate, they provide stock service, we pay money). Normal development test time is good, the results of a few days to find a crash problem, in fact, most of the responsibility in my body. My responsibility: Excessive reliance on documents, not fault-tolerant processing, that is, the data is not the corresponding judgement processing. The following code shows the cause of the crash

Data disruption from third-party companies sometimes causes crashes when a dictionary is created with individual value of nil

Macro #define CSTRINGTOOCSTRING (CSTR) [NSString stringwithcstring:cstr Encoding:gbk_encode]//save each set of data Nsmutablearray
*returnarray = [Nsmutablearray array]; for (int i = 0; i < Recordm.count i++) {Withdrawqry_entrust_record *record = (Withdrawqry_entrust_record *) alloca
    (sizeof (Withdrawqry_entrust_record));
    memset (record, 0x00, sizeof (Withdrawqry_entrust_record));


    [[RECORDM objectatindex:i] getvalue:record]; The reason for the crash when creating a dictionary, there is an individual value of nil (cstringtoocstring) nsdictionary *param = @{@ "Batch_no": cstringto Ocstring (RECORD-&GT;BATCH_NO),//Delegate Batch number @ "Entrust_no": cstringtoocstring (Record->entrust_no),//Delegate No. @ "Entru St_type ": @ (Record->entrust_type),//Delegate category 6 financing commissioned 7 bond and entrust_bs the formation of financing to buy, financing to sell, margin sold, Bond buy @" Entrust_bs ": @ (Rec ORD-&GT;ENTRUST_BS),//Trading logo @ "Stock_account": cstringtoocstring (Record->stock_account),//Securities account number @ "Gdcode":

 Cstringtoocstring (Record->gdcode), ........                             }; 
Solution, make a judgment in the macro, if value is nil, the direct assignment is @ ""
#define CSTRINGTOOCSTRING (CStr) [NSString stringwithcstring:cstr Encoding:gbk_encode]?
 [NSString stringwithcstring:cstr Encoding:gbk_encode]: @ ""
Program crashes Experience 2
Do not do too much elaboration, directly look at the code
    The date format returned by the server is 20160301
    //I want to convert the format to 2016-03-01

    /** delegate Date/
    nsmutablestring *DATESTRM = data returned by the server

    [ DATESTRM insertstring:@ "-" atindex:4];
    [Datestrm insertstring:@ "-" atindex:7];

The above code led to the crash of the online program, and I had an emergency on the second day of the launch of a version.
Why does it collapse? The reason is that the data returned by the server is out of date and returned 0. The length of the string is 1, but the insertion of the subscript 4 position, the program will inevitably crash. Later on the original code added a judgment, the following code:

  if (datestrm.length >= 8) {
      [Datestrm insertstring:@ "-" atindex:4];
      [Datestrm insertstring:@ "-" atindex:7];
   }
Wake up1, do not trust the data returned by the server will always be correct. 2, in the data processing, to carry out fault-tolerant processing, the corresponding judgement and then processing data, this is a good programming habit. thinking: How to prevent the collapse of a potential crash methodIt is well known that there are a number of commonly used methods in the foundation framework that lead to a potential risk of collapse. For a project that's nearly finished, what to do if you don't have a fault-tolerant approach at first. You don't have to do a line of code to check for fault-tolerant processing. --------don't tease, the boss urges you to go online tomorrow. Is there a way to do it once and for all? Can you solve a potential crash problem without moving the original code? Solution

Blocking methods that have potential crash hazards and handling them in a blocking way can prevent the method from collapsing

Step: 1, add a method to the class by category to replace the original potential crash method. 2, using the runtime Method Exchange technology, replace the system method with the new method we add to the class. 3, the use of abnormal capture to prevent the collapse of the program, and the corresponding processing. If you do not understand the exception nsexception, you can click to view NSException's introduction. Concrete Implementation

Create a tool class Avoidcrash to handle the exchange of methods, get the exact location that will cause the crash code, and output the wrong information in the console ... Knowledge points in code with regular expressions, friends who are unfamiliar with regular expressions dot me

AvoidCrash.h

AVOIDCRASH.H//Avoidcrash/////Created by Mac on 16/9/21. COPYRIGHT©2016 year Chenfanfang.
All rights reserved. #import the name of the <Foundation/Foundation.h> #import <objc/runtime.h>/notification, to obtain detailed crash information, listen for this notification #define Avoidcrashnotification @ "avoidcrashnotification" #define AVOIDCRASHDEFAULTRETURNNIL @ "This framework, default is to

return nil. "#define Avoidcrashdefaultignore @" The This framework, default is to ignore this operation to avoid crash. " @interface Avoidcrash:nsobject/** * become effective. The can call becomeeffective method in Appdelegate didfinishlaunchingwithoptions * is in effect. You can be in Appdelegate Didfinishla

The Unchingwithoptions method calls the Becomeeffective method */+ (void) becomeeffective;

+ (void) Exchangeclassmethod: (Class) Anclass Method1sel: (SEL) Method1sel Method2sel: (SEL) Method2sel;

+ (void) Exchangeinstancemethod: (Class) Anclass Method1sel: (SEL) Method1sel Method2sel: (SEL) Method2sel; + (NSString *) Getmaincallstacksymbolmessagewithcallstacksymbolstr: (Nsstring *) Callstacksymbolstr;

+ (void) Noteerrorwithexception: (NSException *) exception Defaulttodo: (NSString *) Defaulttodo; @end

AVOIDCRASH.M

AVOIDCRASH.M//Avoidcrash/////Created by Mac on 16/9/21. COPYRIGHT©2016 year Chenfanfang.
All rights reserved. #import "AVOIDCRASH.H"//category #import "nsarray+avoidcrash.h" #import "nsmutablearray+avoidcrash.h" #import "NSDI Ctionary+avoidcrash.h "#import" nsmutabledictionary+avoidcrash.h "#import" nsstring+avoidcrash.h "#import" NSMUTABLESTRING+AVOIDCRASH.H "#define Avoidcrashseparator @" ===================================================== =========== "#define Avoidcrashseparatorwithflag @" ========================avoidcrash log========================= = "#define Key_errorname @" ErrorName "#define Key_errorreason @" Errorreason "#define Key_errorplace @" E Rrorplace "#define Key_defaulttodo @ Defaulttodo" #define Key_callstacksymbols @ "Callstacksymbols" #define Key_except Ion @ "Exception" @implementation Avoidcrash/** * is in effect (exchange of methods)/+ (void) becomeeffective {static Dispa
    tch_once_t Oncetoken; Dispatch_once (&amP;oncetoken, ^{[Nsarray Avoidcrashexchangemethod];

        [Nsmutablearray Avoidcrashexchangemethod];
        [Nsdictionary Avoidcrashexchangemethod];

        [Nsmutabledictionary Avoidcrashexchangemethod];
        [NSString Avoidcrashexchangemethod];

    [Nsmutablestring Avoidcrashexchangemethod];
}); /** * Class Method Exchange * * @param anclass which class * @param Method1sel Method 1 * @param Method2sel Method 2 */+ (void) Exchangecla Ssmethod: (Class) Anclass Method1sel: (SEL) Method1sel Method2sel: (SEL) Method2sel {method method1 = Class_getclassmethod
    (Anclass, Method1sel);
    Method method2 = Class_getclassmethod (Anclass, Method2sel);
Method_exchangeimplementations (Method1, METHOD2); /** * Object Method Exchange * * @param anclass which class * @param Method1sel Method 1 * @param Method2sel Method 2 */+ (void) Exchangein Stancemethod: (Class) Anclass Method1sel: (SEL) Method1sel Method2sel: (SEL) Method2sel {method method1 = Class_getinstanc
    Emethod (Anclass, Method1sel); Method Method2 = Class_getinstancemethod (Anclass, Method2sel);
Method_exchangeimplementations (Method1, METHOD2); /** * Get stack main crash-lite information < match regular expression > * * @param callstacksymbolstr Stack main crash information * * @return Stack main crash Compact information * * * + (NSString *) Getmaincallstacksymbolmessagewithcallstacksymbolstr: (NSString *) callstacksymbolstr {//friends who are unfamiliar with regular expressions,
    I can see another article, link below//http://www.jianshu.com/p/b25b05ef170d//maincallstacksymbolmsg in the format of +[class name method name] or-[class name method name]

    __block nsstring *maincallstacksymbolmsg = nil;

    The matching format is the +[class name method name] or the-[class name Method name] NSString *regularexpstr = @ "[-\\+]\\[.+\\]"; Nsregularexpression *regularexp = [[Nsregularexpression alloc] initwithpattern:regularexpstr options:

    Nsregularexpressioncaseinsensitive Error:nil]; [Regularexp enumeratematchesinstring:callstacksymbolstr options:nsmatchingreportprogress range:NSMakeRange (0, Callstacksymbolstr.length) usingblock:^ (Nstextcheckingresult * _nullable result, nsmatchingflags flags, BOOL * _Nonnull
  Stop) {      if (result) {maincallstacksymbolmsg = [callstacksymbolstr substringWithRange:result.range];
        *stop = YES;



    }
    }];
return maincallstacksymbolmsg; /** * Hint crash information (console output, notification) * * @param exception caught exception * @param defaulttodo The default approach in this framework is * * + (void) noteerrorwithe Xception: (NSException *) exception Defaulttodo: (NSString *) Defaulttodo {//Stack data nsarray *callstacksymbolsarr = [NS

    Thread Callstacksymbols]; Gets the array string format instantiated in which method of the class-[class name method name] or +[class name Method name NSString *maincallstacksymbolmsg = [Avoidcrash getmaincallstacksym

    BOLMESSAGEWITHCALLSTACKSYMBOLSTR:CALLSTACKSYMBOLSARR[2]];

    if (maincallstacksymbolmsg = = nil) {maincallstacksymbolmsg = @ "Crash method location failed, please check the function call stack to troubleshoot the cause of the error";
    } nsstring *errorname = Exception.name;
    NSString *errorreason = Exception.reason;
    Errorreason may be-[__nscfconstantstring Avoidcrashcharacteratindex:]: Range or index out of bounds//Remove Avoidcrash Errorreason = [ErrorreaSon stringbyreplacingoccurrencesofstring:@ "Avoidcrash" withstring:@ ""];

    NSString *errorplace = [NSString stringwithformat:@ "Error place:%@", maincallstacksymbolmsg]; NSString *logerrormessage = [NSString stringwithformat:@ "\n\n%@\n\n%@\n%@\n%@\n%@\n\n%@\n\n",
    Avoidcrashseparatorwithflag, ErrorName, Errorreason, Errorplace, Defaulttodo, Avoidcrashseparator];

    NSLog (@ "%@", logerrormessage);
                                   Nsdictionary *errorinfodic = @{Key_errorname:errorname,
                                   Key_errorreason:errorreason, Key_errorplace:errorplace,        Key_defaulttodo:defaulttodo, Key_exception
                                   : Exception, Key_callstacksymbols:callstacksymbolsarr

    }; Put the error message in the dictionary and send it out in the form of a notification [[Nsnotificationcenter Defaultcenter] Postnotificationname:avOidcrashnotification Object:nil Userinfo:errorinfodic]; } @end

Create a nsdictionary category to prevent crashes caused by creating a dictionary.
Nsdictionary+avoidcrash.h

//  nsdictionary+avoidcrash.h
//  Avoidcrash////
Created by Mac on  16/9/21.  copyright©2016 year Chenfanfang. All rights reserved.

#import <Foundation/Foundation.h>

@interface nsdictionary (avoidcrash)

+ (void) Avoidcrashexchangemethod;

@end

Nsdictionary+avoidcrash.m
Here first to add a knowledge point: We usually use the quick way to create a dictionary @{key:value}; In fact, the method invoked is DictionaryWithObjects:forKeys:count: The method may cause a crash because the value in key or objects in the key array is null

NSDICTIONARY+AVOIDCRASH.M//Avoidcrash/////Created by Mac on 16/9/21. COPYRIGHT©2016 year Chenfanfang.
All rights reserved. #import "nsdictionary+avoidcrash.h" #import "AvoidCrash.h" @implementation nsdictionary (Avoidcrash) + (void) AVOIDC Rashexchangemethod {[Avoidcrash exchangeclassmethod:self Method1sel: @selector (dictionaryWithObjects:forKeys:count
:) Method2sel: @selector (avoidCrashDictionaryWithObjects:forKeys:count:)]; } + (Instancetype) Avoidcrashdictionarywithobjects: (const ID _nonnull __unsafe_unretained *) objects Forkeys: (const id& Lt

    nscopying> _nonnull __unsafe_unretained *) keys count: (Nsuinteger) cnt {id instance = nil;
    @try {instance = [self avoidcrashdictionarywithobjects:objects forkeys:keys count:cnt]; } @catch (NSException *exception) {nsstring *defaulttodo = @ "This framework, default is to remove nil Key-val
        UEs and instance a dictionary. "; [Avoidcrash noteerrorwithexception:exception Defaulttodo:Defaulttodo];
        Handle the wrong data, and then reinitialize a dictionary Nsuinteger index = 0;
        ID _nonnull __unsafe_unretained newobjects[cnt];

        ID _nonnull __unsafe_unretained newkeys[cnt]; for (int i = 0; i < cnt; i++) {if (Objects[i] && keys[i]) {Newobjects[index] = OB
                Jects[i];
                Newkeys[index] = keys[i];
            index++;
    } instance = [self avoidcrashdictionarywithobjects:newobjects forkeys:newkeys count:index];
    } @finally {return instance; }} @end
look at the effect of preventing collapseUnder normal circumstances, without our above processing, the following code can cause a crash
  NSString *nilstr = nil;
  Nsdictionary *dict = @{
                         @ "key": Nilstr
                         };

The crash screenshot is as follows:
Crash screenshots. PNG can avoid crashing if it is treated like this

[Avoidcrash becomeeffective];

The output screenshot of the console is as follows
Prevents information from crashing the console output. png If you want to get the details of the crash (we can listen for notifications, the notification name is: avoidcrashnotification): You can upload this information to our server, or customize the information in an SDK that integrates third parties to collect crash information, so that we can prevent the program from crashing and know which code is causing the crash.

Listening notification: avoidcrashnotification, get details of the crash log captured by Avoidcrash
 [[Nsnotificationcenter Defaultcenter] Addobserver: Self selector: @selector (dealwithcrashmessage:) name:avoidcrashnotification Object:nil];




-(void) Dealwithcrashmessage: (nsnotification *) Note {

    //NOTICE: All information is in userinfo
    //You can collect the corresponding crash information here to do the corresponding processing ( For example, upload to your own server)
    NSLog (@ "\ n" in the Appdelegate method: Dealwithcrashmessage print \n\n\n\n\n%@\n\n\n\n ", note.userinfo);
}

Attach a screenshot to see how the crash information is carried in the notification
Avoidcrashnotification notifications. PNG closing

The benefit of crashing a program is to get developers to quickly realize that their code is problematic, so that bugs can be fixed in a timely fashion, which is limited to the development phase. If an online app crashes, the problem is big (the boss is unhappy and the consequences are serious).

Personal advice: When you release the app, use the method described above to prevent the program from collapsing, preferably in the development phase.

Above just for example, more to prevent the collapse of the way to see GitHub source code Avoidcrash, this is my recently written a framework, you can integrate into your project, Call the method [Avoidcrash becomeeffective] in the didfinishlaunchingwithoptions of the appdelegate when the app is released, and to get the crash information, listen for the notification.

-(BOOL) Application: (UIApplication *) application didfinishlaunchingwithoptions: (Nsdictionary *) launchOptions {
    [Avoidcrash becomeeffective];

    Listening notification: avoidcrashnotification, get details of the crash log captured by Avoidcrash
    [[Nsnotificationcenter Defaultcenter] Addobserver: Self selector: @selector (dealwithcrashmessage:) name:avoidcrashnotification Object:nil];
    Return YES
}

-(void) Dealwithcrashmessage: (nsnotification *) Note {

    //NOTICE: All information is in userinfo
    //You can collect the corresponding crash information here to do the corresponding processing ( For example, upload to your own server)
    NSLog (@ "\ n" in the Appdelegate method: Dealwithcrashmessage print \n\n\n\n\n%@\n\n\n\n ", note.userinfo);
}


Wen/chenfanfang (author of Jane book)
Original link: http://www.jianshu.com/p/5d625f86bd02
Copyright belongs to the author, reproduced please contact the author to obtain authorization, and Mark "Jane book author
Thanks for sharing
Related Article

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.