4

クラスの「インスタンス」にインスタンス メソッドを追加する方法があるかどうか疑問に思っています。

シナリオは、私がEKEventEditViewControllerを使用しており、このクラス内に「EKEventEditor」(非公開AFAIK)と呼ばれるデリゲート(UITableViewDelegate)を持つUITableViewがあるということです。一部のセルを無効にするために使用しようとしている tableView:willDisplayCell:forRowAtIndexPath: メソッドを実装していません。

したがって、インスタンスにメソッドを追加しようとしていますが、Obj-C ランタイムで見つけることができるのは、インスタンスではなくクラスにメソッドを追加する class_addMethod 呼び出しだけです。「EKEventEditor」がプライベートであるため、それを拡張してそのメソッドを自分で追加することはできません。

ヒントはありますか?

これが私が使用しているコードです。追加しようとしている関数 (willDisplayCell_) が呼び出されていません。

- (void)navigationController:(UINavigationController *)navigationController 
  willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {

if ([navigationController isKindOfClass:[EKEventEditViewController class]]) {

UITableViewController *rootController = (UITableViewController*)[(UINavigationController*)navigationController visibleViewController];
if ([rootController isKindOfClass:[UITableViewController class]]) {
  UITableView *eventTableView = (UITableView*)[rootController view];

  class_addMethod([eventTableView.delegate class], 
                  @selector(tableView:willDisplayCell:forRowAtIndexPath:), 
                  (IMP)willDisplayCell_, "v@:@@@");
}}} 


void willDisplayCell_(id self, SEL cmd, UITableView *tableView, UITableViewCell *cell, NSIndexPath *indexPath) {
  NSLog(@"CALLED?");
}
4

3 に答える 3

3

それがあなたが望む機能です。これにより、(インスタンス) メソッドがクラスのすべてのインスタンスに追加されます。* 特定の 1 つのインスタンスだけにメソッドを追加する方法はありません。**

ただし、Categoryの使用を検討することをお勧めします。これにより、制御できないクラスを拡張できます。@implementationただし、これはクラスの primary をインポートできる場合にのみ機能しますが@interface、そうではない可能性があります。


※クラスメソッドを追加したい場合は、メタクラスを第一引数に関数を呼び出します。

forwardInvocation:**私が取り組んでいるオーバーライドと、おそらくlibffiによるいくつかのトリックを除いて。

于 2012-07-05T23:52:41.860 に答える
2

これがあなたのためのREKitです。インスタンスレベルでメソッドを追加/オーバーライドする機能を提供します。

REKitを使用すると、eventTableView.delegate以下のようにメソッドを追加できます。

[eventTableView.delegate
    respondsToSelector:@selector(tableView:willDisplayCell:forRowAtIndexPath:)
    withKey:nil
    usingBlock:^(id receiver, UITableView *tableView, UITableViewCell *cell, NSIndexPath *indexPath) {
        // Do something…
    }
];
于 2013-02-14T05:41:43.330 に答える
2

これは完全に可能であり、驚くほど便利です...サブクラス化せずにインスタンスの機能を変更することを考えてください...

@interface NSObject (AZOverride)
/** Dynamically overrides the specified method on this particular instance.
* The block's parameters and return type must match those of the method you 
* are overriding. However, the first parameter is always "id _self", which 
* points to the object itself.
* You do have to cast the block's type to (__bridge void *), e.g.:
*
*    [self az_overrideSelector:@selector(viewDidAppear:)
*            withBlock:(__bridge void *)^(id _self, BOOL animated) { ... }];
*/
- (BOOL)az_overrideSelector:(SEL)selector withBlock:(void *)block;
/** To call super from the overridden method, do the following:
*    SEL sel = @selector(viewDidAppear:);
*    void (*superIMP)(id, SEL, BOOL) = [_self az_superForSelector:sel];
*    superIMP(_self, sel, animated);
* This first gets a function pointer to the super method and then you call it.
*/
- (void *)az_superForSelector:(SEL)selector;
@end
于 2013-06-25T07:52:37.990 に答える