2012-04-28 7 views
2

ヘッダーファイルにアクセスできないクラスにカテゴリを追加する方法はありますか?"隠し"クラスにカテゴリを追加する方法

テスト目的のために、私はUITableViewCellDeleteConfirmationControlにカテゴリを追加したいと思いますが、そのクラスはプライベートフレームワークの一部です(私が知る限り)。

どうすればいいですか?私は確認ボタンをタップシミュレートするために、フランク・テスト・フレームワークを拡張しようとしています

(大きな赤いボタンを「削除」)削除しようとすると表示されます。


推敲(mihiriosの要求あたり) UITableViewCell。 FrankはUIControltapメソッドを追加します。なんらかの理由で、フランクのコントロールをタップする通常の方法は、UITableViewCellDeleteConfirmationControlクラス(サブクラスUIControl)では機能しません。

回避策を作成しました。次の方法で、UITableViewCellにカテゴリを追加しました。

- (BOOL)confirmDeletion { 
    if (![self showingDeleteConfirmation]) { 
     return NO; 
    } 
    UITableView *tableView = (UITableView *)[self superview]; 
    id <UITableViewDataSource> dataSource = [tableView dataSource]; 
    NSIndexPath *indexPath = [tableView indexPathForCell:self]; 
    [dataSource tableView:tableView 
     commitEditingStyle:UITableViewCellEditingStyleDelete 
     forRowAtIndexPath:indexPath]; 
    return YES; 
} 

これは、テーブルのデータソースを検索し、ユーザが確認ボタンをタップしたとき、システムが何をするかである(UITableViewのマニュアルに従って)そのtableView:commitEditingStyle:forRowAtIndexPath:メソッドを呼び出します。

これは機能しますが、tapメソッドを追加して、UITableViewCellDeleteConfirmationControlをタップ可能なボタンに見せて、Frankのデフォルトの設定を無効にすることをお勧めします。 tapメソッドは、確認ボタンを含むセルを見つけ、[cell confirmDeletion]を呼び出します。

UITableViewCellDeleteConfirmationControlのカテゴリを宣言しようとすると、コンパイラは「インターフェイス 'UITableViewCellDeleteConfirmationControl'を解決できません」という文句を言います。

誰かがclass-dumpを使用して生成したヘッダーファイルを使用しようとすると、_OBJC_CLASS _ $ _ UITableViewCellDeleteConfirmationControlというシンボルが見つからないとリンカが文句を言います。

+0

質問を詳しくお聞かせください。 – iMash

答えて

2

テスト目的のために、いつでもNSClassFromStringを使用してクラスオブジェクトを取得し、class_replaceMethodランタイムメソッドを使用して、必要な処理を行うことができます。詳細は、Objective-C Runtime Referenceを参照してください。

+0

ありがとう!それは清潔で(比較的)簡単です。私の実装は次のとおりです:https://github.com/dhemery/vigor/blob/master/vigor/categories/FEXTappableConfirmationButton.m –

0

コンパイラが(最終的に)問題のクラスにリンクできる限り、そのカテゴリを作成することができます。より重要な質問は、元のクラスのソースにアクセスできないので、カテゴリをどのように設計するかです。

+0

カテゴリを作成するクラスのソースにアクセスする必要はありません... –

+1

まあ、*どのように*カテゴリを作成しますか?単純な '@interface Foo(Bar)'を使うと、コンパイラは 'Foo'のインタフェース宣言をしていないと不満を持ちます。 – zoul

2

あなたがカテゴリを使用することはできませんが、実行時に手動でメソッドを追加することができます。

可能な方法は、新しいクラスを作成し、必要なメソッドを実装し、適切なobjc-runtime関数を使用してこのメ​​ソッドをUITableViewCellDeleteConfirmationControlに送信することです。オーバーライドの際に後で使用するための元の関数を保存するようなものもあれば、あなたがsuperを呼びたいときに注意しなければならない 'カテゴリ'クラスでも、これはうまくいきません。代わりにobjc-runtime関数objc_msgSendSuperを使用します。

限り、あなたはスーパー、これは問題ないでしょう呼び出す必要はありませんよう:メソッドを呼び出すため

#import <objc/runtime.h> 
#import <objc/message.h> 

void implementInstanceMethods(Class src, Class dest) { 
    unsigned int count; 
    Method *methods = class_copyMethodList(src, &count); 

    for (int i = 0; i < count; ++i) { 
     IMP imp = method_getImplementation(methods[i]); 
     SEL selector = method_getName(methods[i]); 
     NSString *selectorName = NSStringFromSelector(selector); 
     const char *types = method_getTypeEncoding(methods[i]); 

    class_replaceMethod(dest, selector, imp, types);   
    } 
    free(methods); 
} 

良い点は、例えば、main.mである:

@autoreleasepool { 
     implementInstanceMethods([MyCategory class], NSClassFromString(@"UITableViewCellDeleteConfirmationControl")); 
     return UIApplicationMain(argc, argv, nil, NSStringFromClass([YourAppDelegate class])); 
} 

しかし、コントローラクラスで確認処理を移さないだけではわかりません。

+0

これをコントローラクラスに入れないのはなぜですか?これは汎用のテストフレームワーク用です特定のアプリケーションについて何も知らない –

関連する問題