Joe Beuckman
Joe Beuckman

Reputation: 2296

How to implement protocol method for the UIApplicationDelegate?

I'm working in a class, call it Module, and I need to implement this method in the AppDelegate:

- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication
         annotation:(id)annotation
{
   ...
}

I know which class is the AppDelegate (call it App), but I do not have access to edit that class. How can I implement the delegate method from my Module?

I thought about using a category to extend App but this line in the category docs is a concern:

"you’ll need to import the category header file in any source code file where you wish to use the additional methods, otherwise you’ll run into compiler warnings and errors."

The question is, how can I implement the protocol method in my module in a way so that iOS knows to call my protocol method at the appropriate time?

Upvotes: 0

Views: 1145

Answers (1)

dcorbatta
dcorbatta

Reputation: 1889

Ok Joe... If you want to IMPLEMENT the application:openURL:sourceApplication:annotation: from another module, you can do it in runtime.

WE NEED TO ASSUME THAT THE AppDelegate HAVE TEH METHOD IMPLEMENTED

First you need to import the class:

#import <objc/runtime.h>

Then the you need to declare the struct of an object method:

struct objc_method {
    SEL method_name;
    char *method_types;
    IMP method_imp;
};

And finally you can change the implementation whit this:

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

BUT BE CAREFUL. If you look in my code, I'm calling the original implementation inside my implementation, so if I execute the code to change the implementation more than one, my implementation will be an inception (Like the film, my implementation inside my implementation, inside my implementation, inside my implementation and so on).

EDIT:

There is way to add your implementation to the class:

If class_getInstanceMethod return null you can alloc the memory for the method and add it to the class later:

//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;
    }

Adding the method to the class:

if (!existMethod) {
        class_addMethod([[[UIApplication sharedApplication] delegate] class], openURLMethod->method_name, openURLMethod->method_imp, openURLMethod->method_types);
    }

But the problem is, I suppose, that the Operative System are registering the method when the app start, so if when the app start the method don't exist the OS never will call your method.

I will research about how the OS are management that events. With the applicationDidEnterBackground, if you don't have the implementation on the AppDelegate and you add it in runtime, the OS never call your implementation. This is why I assume that the operating system is registering the events when the application starts.

Upvotes: 1

Related Questions