简体   繁体   中英

Objective-C - Is there a way for an Object to execute a method IMP directly as if it were its own?

Presume I have an Object, an instance of MyClass. In Objective-C one can ask the Object to "perform" a selector by either sending it a message or using NSObject's "perform".

This selector has to be defined at compile time as part of the Class definition, more precisely as an Instance method of that class OR with the help of the Obj-C Runtime, have the method added to the (entire) MyClass at runtime with class_addMethod.

My question is as follows:

Would it be possible to send an object the IMP and ask it to execute it on itself? Essentially I want Objects, different instances of MyClass to execute things on themselves without the entire MyClass knowing about it. Essentially I would call these "per Object methods", an Object1 gets this IMP executed on itself then another Object2 gets a different IMP, and so on. These IMPs are stored somewhere else and it's that Object that knows and decides where to send things.

yes that works

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

@interface DonorTemplateClass : NSObject
- (void)testMethod:(NSString*)aStringAsParameter;
@end
@implementation DonorTemplateClass
- (void) testMethod:(NSString*)aStringAsParameter {
    NSLog(@"%@ :: %@", self.class, aStringAsParameter);
}
@end

@interface AClass : NSObject
@end
@implementation AClass
@end

@interface AnotherClass : NSObject
@end
@implementation AnotherClass
@end

int main(int argc, char *argv[]) {
    @autoreleasepool {
        SEL justTheMethodSelector = @selector(testMethod:);
        IMP justTheMethodImplementation = class_getMethodImplementation([DonorTemplateClass class], justTheMethodSelector);

        AClass *anAClassInstance = [[AClass alloc] init];
        AnotherClass *anotherClassInstance = [[AnotherClass alloc] init];

        NSString *aString = @"Test1";

        typedef void (*MyTypeName)(id,SEL, NSString*); // more info about the block syntax on http://goshdarnblocksyntax.com scroll down to "typedef"
        MyTypeName blockName = (MyTypeName)justTheMethodImplementation;

        blockName(anAClassInstance, justTheMethodSelector, aString);
        blockName(anotherClassInstance, justTheMethodSelector, aString);
    }
}

NOTE that I cast my IMP to a typedef'd pointer type. it compiles fine when I just call I but objc_retain crashes then for me ... so I'd say you need to typedef your IMPs before using them but then you can execute them in the context of any suitable class

IMP is just a typedef for a regular C function pointer. It's meant to point to method implementations, which are C functions with first parameter being an object, and second parameter being a selector. And "an Object to execute an IMP" simply means to call the C function, passing the object as first argument, and a selector as second.

You said you want to be able to "send an object the IMP and ask it to execute it on itself" (ie call the IMP passing the object and a selector), yet you do not want "the entire MyClass knowing about it" (which I take to mean you do not want it as a method).

So basically, that sounds like you just want a bunch of standalone C functions, not methods, which you can call, passing various objects, as needed. And you can store these C function pointers as you like. Is that right?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM