6

我想为objective-c中的对象构建一个小型插件系统。

现在我被困在我想动态地(在运行时)向对象中可用的每个函数添加一行代码的地方。

我玩过运行时库,但没有找到解决方案。

到目前为止我尝试过的是:

        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);

我的问题是,当有多个参数时,我没有机会将它们传递给“func()”。AFAIK 这在 C 中是不可能的。

我想到的另一个解决方案是通过方法调配来做一些魔术。

在步骤:

  1. 创建一个“swizzle 方法”,它只调用我的自定义代码,然后调用原始方法(通过命名模式)
  2. 使用“swizzle Method”之一更改每个函数的 IMP
  3. 使用“旧”实现创建一个新方法,并将名称更改为类似于“___name”的模式

在这个解决方案中,我被困在第 3 点。我还没有设法动态创建一个完整的新方法。

有没有人可以帮助我解决上面的问题,或者有另一种“捕获所有方法功能”的解决方案。

最好的是类似 forwardInvocation 的东西,它也捕获已经定义的函数。

谢谢你的帮助!

4

2 回答 2

4

Lemme 将其分为两部分,因为我无法理解您的两个问题之间的联系。

I. 使用“旧”实现创建一个新方法,并将名称更改为类似于“___name”的模式

这相当容易,尽管我不明白这将如何解决您的问题。你仍然不能将可变参数函数参数传递给这样的方法(你是对的,这不能在 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;
}

二、如果你想在函数之间传递可变参数,你可能需要回退到大量的汇编hackage。幸运的是,一些聪明的人已经为你做到了。

要么使用NSInvocation 类,或者如果它还不够,那么libffi甚至更低级别。

于 2013-06-14T20:50:06.337 回答
2

对任意对象执行此操作将非常困难。看看AspectCocoa以了解这些方面的内容,但您会发现它的效果并不好,因此不建议在生产环境中使用。

但是对于一个插件系统,你最好只定义一个像 PluggableObject 类这样的东西,它是在设计时考虑到扩展的。忘记在任意方法中间运行任意块 - 相反,定义可以插入的特定“套接字”以及这些东西可以遵循的接口以获得您想要支持的功能。添加和修复东西会更加稳定和容易。

于 2013-06-14T20:48:38.433 回答