Ios 如何在objective c中动态创建类别?
我正在从事objective-c库项目(“MyLib”)。 假设该库包含在“TestApp”中。现在,“TestApp”还包括另一个名为“Xlib”的库。这个Xlib有一个类C1,它有一个方法m1Ios 如何在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
//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是否真的知道他或她想大嚼特嚼,但这绝对是公认的术语。