Objective-C add functionality for each object method

I want to create a small plugin system for objects in objective-c.

Now I'm stuck at the point where I want to dynamically (at runtime) add a line of code for each function available in the object.

I played with the runtime library, but haven't decided yet.

What I have tried so far:

id (^impyBlock)(id, id, ... ) = ^(id self_, id arguments, ...) { // My custom code for every function here id (*func)(__strong id,SEL,...) = (id (*)(__strong id, SEL, ...))imp; return func(obj, s, arguments); }; id (*impyFunct)(id, SEL,...) = imp_implementationWithBlock(impyBlock); method_setImplementation(mList[i], impyFunct); 

My problem is that when there is more than one argument, I have no chance to pass them to "func ()". AFAIK is not possible in C.

Another solution that I thought of is magic using swizzling.

In steps:

  • Create a “swizzle method” that simply calls my own code and then calls the original method (using a naming scheme).
  • Change the IMP of each function using the "swizzle Method"
  • Create a new method with the "old" implementation and change the name to a schema such as "___ name"

In this solution, I was stuck at point 3. I was not able to dynamically create a complete new method.

Can someone help me with my problems above or have another solution for the "catch all functions" function.

Best would be something like forwardInvocation, which also catches already defined functions.

Thank you for your help!

+6
source share
2 answers

Lemme break this down into two, as I just can't get the connection between your two questions.

I am. Create a new method with the "old" implementation and change the name to a schema such as "___ name"

This is pretty easy, although I don’t understand how this could solve your problem. You still cannot pass arguments to the variational function for such a method (and you are right, this cannot be done in C).

 IMP swapImpForSelector(Class cls, SEL sel, IMP newImp) { Method m = class_getInstanceMethod(cls, sel); IMP oldImp = method_setImplementation(m, newImp); NSString *newSel = [NSString stringWithFormat:@"__prefixed_%@", NSStringFromSelector(sel)]; const char *type = method_getTypeEncoding(m); class_addMethod(cls, NSSelectorFromString(newSel), oldImp, type); return oldImp; } 

II. If you want to pass variable arguments between functions, you may need to revert to heavy hacking of the assembly. Fortunately, some smart people have already done this for you.

Use the NSInvocation class , or if that is not enough, then libffi is an even lower level.

+4
source

Doing this for arbitrary objects will be quite complicated. Look at AspectCocoa for something in this direction, but you will see that it doesn’t work so cool and is not recommended for use in a production environment.

But for a plug-in system, you would be better off just defining something like the PluggableObject class, which is designed with the extension in mind. Forget about starting arbitrary blocks in the middle of arbitrary methods - instead, define specific "sockets" where everything can connect and an interface that these things can follow to get the functionality you want to support. It will be much more stable and easier to add and fix things.

+2
source

Source: https://habr.com/ru/post/947338/


All Articles