Ios 如何在objective c中动态创建类别?

Ios 如何在objective c中动态创建类别?,ios,objective-c,swizzling,method-swizzling,objc-category,Ios,Objective C,Swizzling,Method Swizzling,Objc Category,我正在从事objective-c库项目(“MyLib”)。 假设该库包含在“TestApp”中。现在,“TestApp”还包括另一个名为“Xlib”的库。这个Xlib有一个类C1,它有一个方法m1 //C1.h is part of Xlib @interface C1 - (void) m1; @end 现在,每次调用m1时,MyLib都应该执行一段代码。 我的方法是,如果我在MyLib中创建一个类别: @interface C1 (mycat) @end @implementation

我正在从事objective-c库项目(“MyLib”)。 假设该库包含在“TestApp”中。现在,“TestApp”还包括另一个名为“Xlib”的库。这个Xlib有一个类C1,它有一个方法m1

//C1.h is part of Xlib
@interface C1
- (void) m1;
@end
现在,每次调用m1时,MyLib都应该执行一段代码。 我的方法是,如果我在MyLib中创建一个类别:

@interface C1 (mycat)
@end

@implementation C1 (mycat)
+ (void) load{
    //code to swizzle method in class C1 from: @selector(m1) to: @selector(mycat_m1)
}
- (void) mycat_m1{
    /*
      insert code that I want to execute
    */
     [self mycat_m1]; //calling the original m1 implementation
}
@end
问题: MyLib没有C1类。所以我无法构建MyLib,因为我试图在一个不存在的类上创建一个类别。因此,存在编译错误

因此,我尝试将上面的代码封装在其中:

#if defined(__has_include)
#if __has_include("C1.h")
    /* above category code */
#endif
#endif
MyLib现在编译和构建都很好,但由于MyLib中不存在C1.h,因此MyLib.framework不会有这个类别

现在,我有两个选择: 1.动态创建此类别,以便在应用程序中包含库后,以及应用程序运行时,将根据TestApp是否包含Xlib创建此类别。 2.从编译源代码中删除包含此类别代码的文件,然后在我的框架中将该文件公开给TestApp

我无法解决这两个选项中的任何一个。对现有的方案有什么想法吗?或者有什么新的选择


编辑:添加了详细信息,因为问题不太具有解释性

此代码不需要在类别中

在滑动时经常使用类别,因为大多数情况下,人们试图在特定类中用自己的行为“包装”函数。Swizzling通常在
+load
类方法中完成。类别上的load类方法是将其组织起来的好地方,因为您知道主类的
+load
方法刚刚被调用

在你的情况下,大口大口喝仍然是很有可能的。使用
+load
方法在框架中实现一个类。swizzling代码将像往常一样发送到那里。您只需要查找您想要swizzle的类,而不是假设目标引用是对
self
的引用,就像它在类别中一样。也就是说,如果你正在引用一篇博客文章,或者使用一种最喜欢的技巧来引用
self
,那么要知道它可能不会被引用。确保你当心你想上/下哪个班

我过去也曾做过类似的事情。在我的例子中,我必须从一个框架中查找实现AppDelegate协议的类的实例。在这种情况下,触发swizzling的代码不是从
+load
调用的(因为AppDelegate类可能没有加载,AppDelgate类的实例肯定没有实例化)。在这种情况下,我从类的
-init
方法调用了代码,并对其进行了保护,使其不能被调用两次。然而,我被保证能够从应用程序代码中实例化我的类,所以这项技术是有效的;我不是100%确定你的用例。发布您尝试过的代码不会有什么坏处

更新:具体示例

这是我随身携带的刷牙方法

+ (void)swizzleSelector:(SEL)sel1 onClass:(Class)class1 withSelector:(SEL)sel2 fromClass:(Class)class2
{
    Method method1 = class_getInstanceMethod(class1, sel1);
    Method method2 = class_getInstanceMethod(class2, sel2);

    // Make sure that both methods are on the target class (the one to swizzle likely already is).
    class_addMethod(class1,
                    sel1,
                    method_getImplementation(method1),
                    method_getTypeEncoding(method1));
    class_addMethod(class1, // The swizzling is 'on' the first class, so it's the target here, not class2.
                    sel2,
                    method_getImplementation(method2),
                    method_getTypeEncoding(method2));

    // Once they are both added to the class, exchange the implementations of the methods.
    method_exchangeImplementations(class_getInstanceMethod(class1,sel1),
                                   class_getInstanceMethod(class1,sel2));
}
正如我所说,您需要以某种方式查找目标的类,但假设您是从具有替换方法的类中调用它,并且假设
m1:
是您尝试swizzle的目标选择器,您可能会这样调用:

Class class = NSClassFromString(@"C1");
// Check that `class` is not `nil`

[self swizzleSelector:@selector(m1)
              onClass:class
         withSelector:@selector(my_m1)
            fromClass:self];

我希望这有助于澄清您可以如何使用swizzling。千分之999,你可能不需要喝。您的用例听起来像是一种可能,您可能不得不这样做。

“swizzle”?你想要什么?目的是什么?类c1中有一个方法m1,它可能存在于应用程序中。每次在应用程序中调用m1时,我的库都应该执行一段代码。因此,这是一场恶作剧。你能解释一下投票结果吗?这个问题的框架是否正确,或者我是否遗漏了一些明显的东西?我没有投反对票,所以不要为此责备我。查看关于如何正确提问的帖子,因为很难理解您在这里要问什么。也许您可以使用@protocol来代替?@Simon“swizzling”是使用Objective-C运行时交换方法的非正式官方术语。我不确定OP是否真的知道他或她想大嚼特嚼,但这绝对是公认的术语。