我想知道是否有办法将实例方法添加到类的“实例”中。
场景是我正在使用EKEventEditViewController,并且在此类中有一个UITableView,其中有一个名为“EKEventEditor”(非公开AFAIK)的委托(UITableViewDelegate)。它没有实现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?");
}
答案 0 :(得分:3)
这就是你想要的功能。这会将(实例)方法添加到类的所有实例。*无法将方法添加到一个特定实例。**
您可能希望使用Category,但 允许您扩展您无法控制@implementation
的类。这只有在你可以导入类的主要@interface
时才有效,但听起来可能并非如此。
*如果要添加类方法,可以使用元类作为第一个参数调用该函数。
**禁止覆盖forwardInvocation:
以及可能是libffi的一些技巧。我正在努力。
答案 1 :(得分: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…
}
];
答案 2 :(得分:2)
This is totally possible, and amazingly useful ...考虑改变实例的功能而不进行子类化等...
@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