Adding a method to an instance of the objective-c class at run time

I am wondering if there is a way to add an instance method to the "instance" of the class.

The scenario is that I am using an EKEventEditViewController, and in this class there is a UITableView with a delegate (UITableViewDelegate) called "EKEventEditor" (non-state AFAIK). It does not implement the tableView: willDisplayCell: forRowAtIndexPath: method, which I am trying to use to disconnect some cell.

So, I'm trying to add a method to an instance, but all I can find in the Obj-C runtime is the call to class_addMethod, which adds the method to the class, but not the instance. If "EKEventEditor" is private, I cannot just expand it and add this method myself.

Any clues?

Here is the code I'm using, the function I'm trying to add (willDisplayCell_) does not receive the call.

- (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
source share
3 answers

This is entirely possible and surprisingly useful ... Think about changing instance functionality without a subclass, etc.

 @interface NSObject (AZOverride) /** Dynamically overrides the specified method on this particular instance. * The block 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 type to (__bridge void *), eg: * * [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 
+2
source

That you want. This will add a method (instance) to all instances of the class. * There is no way to add a method to only one specific instance. **

You might want to explore Category , which allows you to extend a class whose @implementation you do not control. This will only work if you can import the main @interface class, and it looks like it might not be.


* If you want to add a class method, you must call a function with a metaclass as the first argument.

** Prevent some cheating with overriding forwardInvocation: and possibly the libffi I'm working on.

+3
source

Here is REKit for you. This gives you the ability to add / override the method at the instance level.

With REKit, you can add a method to eventTableView.delegate , as shown below:

 [eventTableView.delegate respondsToSelector:@selector(tableView:willDisplayCell:forRowAtIndexPath:) withKey:nil usingBlock:^(id receiver, UITableView *tableView, UITableViewCell *cell, NSIndexPath *indexPath) { // Do something… } ]; 
+2
source

All Articles