我在一个班级工作,称之为模块,我需要在AppDelegate中实现这个方法:
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation
{
...
}
我知道哪个类是AppDelegate(称之为App),但我无权编辑该类。如何从我的模块中实现委托方法?
我考虑使用类别来扩展App,但category docs中的这一行是一个问题:
“您需要在任何您希望使用其他方法的源代码文件中导入类别头文件,否则您将遇到编译器警告和错误。”
问题是,我如何以某种方式在我的模块中实现协议方法,以便iOS知道在适当的时候调用我的协议方法?
答案 0 :(得分:1)
Ok Joe ...如果你想从另一个模块中实现application:openURL:sourceApplication:annotation:
,你可以在运行时完成它。
我们需要确定AppDelegate是否实施了TEH方法
首先,您需要导入该类:
#import <objc/runtime.h>
然后你需要声明一个对象方法的结构:
struct objc_method {
SEL method_name;
char *method_types;
IMP method_imp;
};
最后你可以改变这个实现:
//Create the selector of the method.
NSString * openURL = @"application:openURL:sourceApplication:annotation:";
SEL selectorOpenURL = NSSelectorFromString(openURL);
//Get the method of the intance.
Method openURLMethod = class_getInstanceMethod([[[UIApplication sharedApplication] delegate] class], selectorOpenURL);
//Get the current implementation.
IMP openURLIMP = openURLMethod->method_imp;
//Create your own implementation.
IMP myOpenURLIMP = imp_implementationWithBlock(^BOOL(id _s, UIApplication * app,NSURL *url,NSString *sourceApplication,id annotation) {
//Call the original implementation.
openURLIMP(_s,selectorOpenURL,app,url,sourceApplication,annotation);
//Here your implementation code.
NSLog(@"Handling the URL");
return YES;
});
但要小心。如果你查看我的代码,我在我的实现中调用原始实现,所以如果我执行代码来改变实现不止一个,我的实现将是初始(就像电影,我的实现在我的实现中,在我的实现中,在我的实现内部等等)。
编辑:
有办法将您的实现添加到课程中:
如果class_getInstanceMethod
返回null,您可以为该方法分配内存并稍后将其添加到该类中:
//If the method dont exist. We need to create one.
if (!openURLMethod) {
existMethod = NO;
openURLMethod = malloc(sizeof(struct objc_method));
openURLMethod->method_types = "c24@0:4@8@12@16@20";
openURLMethod->method_name = selectorOpenURL;
}
将方法添加到课程中:
if (!existMethod) {
class_addMethod([[[UIApplication sharedApplication] delegate] class], openURLMethod->method_name, openURLMethod->method_imp, openURLMethod->method_types);
}
但问题是,我认为操作系统在应用程序启动时正在注册该方法,因此如果应用程序启动时该方法不存在,操作系统将永远不会调用您的方法。
我将研究操作系统如何管理事件。使用applicationDidEnterBackground
,如果您没有在AppDelegate上实现并在运行时添加它,则操作系统永远不会调用您的实现。这就是我假设操作系统在应用程序启动时注册事件的原因。