method Swizzling実践--alloc hooker

2534 ワード

くだらないことはあまり言わないで、直接本題に入ります.今回出会った問題は主にプロジェクトに関わるいくつかのメモリの問題で、まずこのプロジェクトの全体の構造を言って、プラットフォームをまたぐことを実現するため、最上階でluaから関連する業務コードを編纂して、アンドロイドとiOS端の業務の急速な開発を実現して、中間は1層の統一的なc++インタフェースで、iOSとAndroidは、この統合されたc++インタフェースに基づいて、各プラットフォームの最下位の論理コードを実現します.例えば、Viewの場合、c++の統合インタフェースは次のようになります.
void *createView(const char *type)

次にviewを作成するのはiOSとアンドロイドがそれぞれ実現し、iOS側はc++とocの混合符号化を実現し、ocのコードを直接呼び出すことができ、luaがc++を呼び出してswigによって相互調整を実現することができ、これは自分で適切な方法を選ぶことができることが多い. 次にフレームワークで発生する問題について述べると,lua,c++とocの混合符号化に関与し,ocはmrc方式(プロジェクト開始時間が比較的早い)を用いるため,メモリ管理の問題が特に重要となる.通常の処理ロジックは、作成時にluaがc++を呼び出してocオブジェクトを除去することです.解放時、luaはc++の構造関数を呼び出し、構造関数でocオブジェクトの解放を完了します.そして、どのようにしてこれらのオブジェクトがこの論理に従って解放されたかを確認します.この問題について、私が取った戦略は、各オブジェクトが作成されたときに記録を作成し、オブジェクトが整理されたときに記録から削除し、最後に記録に残っているオブジェクトがあるかどうかを見てみましょう.これにより対象が解放されたかどうかを判断し(あるいは何か新しいアイデアが提案されてもよい)、これを実現するには2つのものを借りる必要がある:method SwizzzlingとNSHashTable,method Swizzlingは以前のブログを参考にすることができ、NSHashTableは主にweakタイプのメンバー変数を持つことができることを利用している.NSHashTable WeakMemoryは、hash tableに追加した場合、オブジェクトの参照技術を追加しないことを示し、追加したオブジェクトが外部で解放されると、tableは自動的に対応するオブジェクトを削除します.
NSHashTable *hashTable = [NSHashTable hashTableWithOptions: NSHashTableWeakMemory]; 

従って、method Swizzzlingによるhook nsobjectのinitメソッドを用いてNSHashTable WeakMemory型のNSHashTableに追加し、最後にこのtableにどのオブジェクトがあるかを見て、これらのオブジェクトがまだ解放されていないことを証明し、これによってオブジェクト全体の作成と解放ロジックが正しいかどうかを検出することができる.以下に、UIViewオブジェクトの作成と解放を記録するコードの例を示します.
static NSHashTable *hashTable;//       
@implementation UIView (AllocHook)

//method Swizzling   ,  hook   ,          NSHashTable 
-(instancetype)customInit
{
    if (!hashTable) {
        hashTable = [NSHashTable hashTableWithOptions:NSHashTableWeakMemory];
    }
    [hashTable addObject:self];
    return [self customInit];
}
@end

//  hook  ,    method Swizzling
@implementation ViewAllocHooker

-(void)startRecord
{
    Class class = [UIView class];
    
    SEL originalSelector = @selector(init);
    SEL swizzledSelector = @selector(customInit);
    
    Method originalMethod = class_getInstanceMethod(class, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
    //     init     customInit  
    method_exchangeImplementations(originalMethod, swizzledMethod);
}


これにより、initメソッドを呼び出して作成されたUIViewまたはそのサブクラスはNSHashTableに記録され、tableは追加オブジェクトの弱い参照を持っているだけであるため、フレームワークが正しいかどうかを確認するために、tableにどのオブジェクトがまだ解放されていないかを後で確認することができる.詳細な例コードはgithubを見ることができ、その中のViewAllocHookerは単例を採用することができ、例コードなので変更しないで、何か改善点があれば~を歓迎します.