method swizzlingからcrash分析と解決へ

3676 ワード

引用文
以前の開発でAndroidがCrashに遭遇したことを知り、フレームワークを利用して前のページに戻ることができ、フラッシュではなく前のページに戻ることができ、iOSのCrash率をどのように下げるかを考えていました.もちろん、最も主要な方法は根源からつかみ、コードロジックの完成性、コードの規範性、多くのテストに注意することです.
後でRuntimeの方法で置き換え方を交換できることが分かったので,その際にNSArray,NSDictionaryのいくつかの挿入方法を置き換え,空の値を挿入しないように判断することができる.
本文を通じて何を学ぶことができますか.
  • 簡単な方法交換とメッセージ転送はcrash率
  • を低減する.
  • crashに遭遇した
  • の迅速な位置決めと解決方法
    1.簡単な方法で交換とメッセージ転送してcrash率を下げる
    まず、一目で位置決めできる異常、配列の境界を越え、空の値を挿入するなど、分類を使用してシステムを交換する方法でCrashを避けることができます.原理は簡単です.コードを参照してください.
    @implementation NSArray (XQAdd)
    
    + (void)load {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
        [objc_getClass("__NSArrayI") swizzleInstanceMethod:@selector(objectAtIndex:) with:@selector(xq_objectAtIndex:)];
            // [@"1"]
    }
    
    - (id)xq_objectAtIndex:(NSInteger)index {
        if (index >= self.count || index < 0 || !self.count) {
            return nil;
        }
        return [self xq_objectAtIndex:index];
    }
    

    同様に、NSMutableArrayの挿入方法、NSDictionaryの挿入方法などを交換することもできますが、私が書いたコードの例を見ることができます.
    また、ネットワークデータを取得した場合、直接辞書で値を取ると、あるkeyが格納している値がNSNumberなのかNSStringなのか分からないが、伝達値の大部分がNSStringで行われるのが習慣であるため、NSNumberがNSStringで使用されるとクラッシュする可能性があると遭遇した場合、メッセージ転送-forwardingTargetForSelector:を利用してNSNumberが直接NSStringとして使用されてクラッシュしないことを実現する.主なコードは次のとおりです.
    @implementation NSNumber (avoidCrash)
    
    + (void)load {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            [self swizzleInstanceMethod:@selector(respondsToSelector:) with:@selector(swizzle_respondsToSelector:)];
            [self swizzleInstanceMethod:@selector(forwardingTargetForSelector:) with:@selector(swizzle_forwardingTargetForSelector:)];
        });
    }
    - (BOOL)swizzle_respondsToSelector:(SEL)aSelector {
        if ([self swizzle_respondsToSelector:aSelector]) {
            return YES;
        }
        if ([__checkString respondsToSelector:aSelector]) {
            return YES;
        }
        return [super respondsToSelector:aSelector];
    }
    
    - (id)swizzle_forwardingTargetForSelector:(SEL)aSelector {
        // whether NSString respondsToSelector
        if ([__checkString respondsToSelector:aSelector]) {
            return [NSString stringWithFormat:@"%@", self];
        }
        // Returns the object to which unrecognized messages should first be directed
        return [super forwardingTargetForSelector:aSelector];
    }
    

    実はRuntimeはクールに走るのと似ていて、うまくいかないと転んでしまうので、この方法を吟味して使うと、自分のコードロジックを書くのが一番です.
    2.crashに遭遇した場合、どのように迅速に位置決めし、解決するか
    ここで1篇の文章を推薦します@念茜漫談iOS Crashはフレームワークを収集して、読むことを推薦します
    よくあるEXC_BAD_のエラーの原因を補足します
    1)EXC_BAD_ACCESSこのタイプのExcpetionは、通常、アクセスを変更しないメモリにアクセスするために使用される最も長いCrashです.一般EXC_BAD_ACCESSの後ろにある「()」には補足情報も付きます.SIGSEGV:は、通常、オブジェクトの解放が繰り返されるため、このタイプはARCが切り替えられた後にはあまり見られないはずである.SIGABRT: Abort信号を受信して終了します.通常、Foundationライブラリ内のコンテナは、正常な状態を保護するためにいくつかの検出を行います.たとえば、nilを配列に挿入するなど、このようなエラーが発生します.SEGV:(Segmentation Violation)は、空のポインタ、初期化されていないポインタ、スタックオーバーフローなどの無効なメモリアドレスを表す.SIGBUS:バスエラー.SIGSEGVとは異なり、SIGSEGVアクセスは無効なアドレスであり、SIGBUSアクセスは有効なアドレスであるが、バスアクセス異常(アドレス整列の問題など)SIGILL:不正な命令の実行を試みるが、認識されないか、権限がない可能性がある.
    2)EXC_BAD_INSTRUCTIONこのような異常は、通常、スレッドが不正な命令を実行したことに起因する.
    1.storyboardとoutletの対応関係をコードで変更しましたが、storyboardが更新されていない場合に発生しました.
    2.このcrashは、サードパーティ製ライブラリのメソッドと競合したときに発生しました.
    3.システムメソッドを呼び出すときに不適切なポインタタイプが入力されました.
    3)EXC_ARITHMETICコードで除算すると分母がゼロになるという問題が発生する.
    2つのオープンソースのCrashライブラリを推奨
    plcrashreporter:これは比較的早いCrash収集処理ライブラリで、支付宝のオープンソースプロトコルにこのライブラリがあります.アプリに登録し、Crashファイルを収集し、アップロードするのが大まかな流れです.更にKSCrashを推薦して、このメンテナンスの更新の比較的に多くて、少し理解することができます