将新类添加到运行时是否可以获得通知? (目标C)

时间:2015-09-02 12:21:19

标签: ios objective-c objective-c-runtime

Objective-C运行时允许分别使用objc_allocateClassPairobjc_registerClassPair动态创建和注册类对。将新类添加到运行时是否可以获得通知? (我只关注已注册的Objective-C课程,如果有帮助,未注册的课程将是奖金。)

如果无法收到通知,那么下一个最有效的方法是什么?大多数iOS设备都有严格的计算限制,因此我的选择有限。如果可以的话,我会对运行时的hackery开放。我意识到我可以挂钩+load,但这只适用于NSObject子类,而不是纯粹的Swift类。

" Pure Swift课程?但纯Swift类不是Objective C类!"你说?再想想。尝试使用运行时内省一个纯粹的Swift类,你会发现它有更多的东西而不是眼睛! "如何最终动态添加Swift类?"好吧,我可以加载一个使用Swift的动态框架!

由于@SpaceDog问道,这是我正在开发的开发人员实用程序。有关进一步说明:我自己不知道何时调用objc_allocateClassPairobjc_registerClassPair,因为我的项目是一个库。

1 个答案:

答案 0 :(得分:3)

简答:否。

答案很长:排序。

有两种方法可以解决这个问题。遗憾的是,这两者都需要看门狗线程和民意调查。

在没有重写符号的情况下,没有同步回调可以背负。
(当然,如果这是一个选项,你有很多其他的解决方案)

  1. 第一个选项,仅使用公共API:您可以随时查看objc_getClassList的计数是否会发生变化。

    此解决方案的问题在于它会将可能只是加载到共享DYLD缓存中的所有类强制加载到用户空间中。这只会发生一次,但这样做会有相当大的性能影响。当然不适合冷启动时间。

    注意:objc_getClassList的排序顺序没有明确定义(内部依赖于不稳定的哈希表),因此没有好办法(例如,存储/时间小于O(N))确定具体添加了哪个类。

    1. 第二个选项,也许是更可行的选项,是(ab)使用调试器特定的API gdb_objc_realized_classes

      这是类名(NXMapTable)到类指针(又名。const char *)的objc_class(在objective-c运行时内部使用的超老哈希表实现)。

      注意:NXMapTable已不再位于公共标题中,因为它是一个非常旧版本的OSX(10.4?),因此您需要从Apple Open Source获取最新版本的maptable.h

      使用示例:

      #import "maptable.h"
      
      extern NXMapTable *gdb_objc_realized_classes;
      
      int main() {
          printf("Realized classes: %d\n", NXCountMapTable(gdb_objc_realized_classes));
      
          Class superClass = [NSObject class];
          Class myKls = objc_allocateClassPair(superClass, "TestClass", 0);
          objc_registerClassPair(myKls);
      
          printf("Realized classes: %d\n", NXCountMapTable(gdb_objc_realized_classes));
      }
      

      另请注意:gdb_objc_realized_classes具有线程安全保证,因此如果您有多个线程可能注册类,则可能会遇到问题。

    2. 这些解决方案可让您在添加类时了解,但不一定是已添加的特定类。

      最后,如果您担心内存(因为您可能应该考虑单独使用Foundation框架中有1500个类),一个选项可能是保持数据结构类似于已知注册的bloom filter类,然后,当objc_getClassList的结果发生变化时,找出哪个类没有通过那个布隆过滤器并且你有最新的注册类。

      但是,作为概率数据结构,您将有误报 - 例如如果您的指针/名称哈希值不够好,某些类可能会破裂。

      祝你好运。