miknonny
miknonny

Reputation: 131

How do i fix duplicate declaration of method with out breaking code

I am trying to include Google signin SDK to my AppDelegate.m file and it throw this error.

Its like I can only define one instance of the method.

// Facebook SDK
- (void)applicationDidBecomeActive:(UIApplication *)application {
  [FBSDKAppEvents activateApp];
}

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
  return [[FBSDKApplicationDelegate sharedInstance] application:application
                                                        openURL:url
                                              sourceApplication:sourceApplication
                                                     annotation:annotation];
}

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

  return [RNGoogleSignin application:application openURL:url sourceApplication:sourceApplication annotation:annotation];
}

@end

Upvotes: 3

Views: 2583

Answers (2)

MANIAK_dobrii
MANIAK_dobrii

Reputation: 6032

I guess the answer could be quite simple:

- (BOOL)application:(UIApplication *)application 
            openURL:(NSURL *)url 
  sourceApplication:(NSString *)sourceApplication 
         annotation:(id)annotation 
{
    if([[FBSDKApplicationDelegate sharedInstance] application:application
                                                      openURL:url
                                            sourceApplication:sourceApplication
                                                   annotation:annotation])
    {
        return YES;
    }

    return [RNGoogleSignin application:application 
                               openURL:url
                     sourceApplication:sourceApplication 
                            annotation:annotation];
}

If you add more, return YES when any of the agents handles the openURL. Order is irrelevant. Also this method is deprecated (use -application:openURL:options: instead), so you need to avoid using -application:openURL:sourceApplication:annotation: if you want your app to survive future changes.

UPD: Use my solution if you "want it now", there's good points in gaussblurinc's solution as well, so if you want something for a long run - derive something from it for sure.

Upvotes: 9

gaussblurinc
gaussblurinc

Reputation: 3692

@interface Services : NSObject<UIApplicationDelegate> // or ApplicationDelegateServices?

@property (strong, nonatomic, readonly) NSArray <id<UIApplicationDelegate>> *services;

@end

@interface Services()

@property (strong, nonatomic, readwrite) NSArray <id<UIApplicationDelegate>> *services;

@end
@class RNGoogleSignin;
@class FBSDKApplicationDelegate;
@implementation Services

- (void)setup {
    // put all items inside here
    //
    id<UIApplicationDelegate> googleApplicationDelegate = (<UIApplicationDelegate>)[RNGoogleSignin class];
    id<UIApplicationDelegate> facebookApplicationDelegate = (<UIApplicationDelegate>)[FBSDKApplicationDelegate sharedInstance];
    self.services = @[facebookApplicationDelegate, googleApplicationDelegate];

}
// services - create chain of responsibility for openURL scheme
// they only need to adopt to protocol canOpenURL and openURL
// each service is <UIApplicationDelegate>
- (NSArray <id<UIApplicationDelegate>>*) chainForSelector:(SEL)selector {
    return [self.services filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id<UIApplicationDelegate>  _Nonnull evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
        return [evaluatedObject respondsToSelector:selector];
    }]];
}

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
    // find all that responds to selector
    // filteredArrayUsingPredicate
    NSArray *chain = [self chainForSelector:_cmd];
    // or put your custom logic here, because all items in delegate are good enough to perform selector
    for (id<UIApplicationDelegate> delegate in chain) {
        if([delegate application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation]) {
            return YES;
        }
    }
    return NO;
}

@end

@interface AppDelegate<UIApplicationDelegate>

@property (nonatomic, weak) id<UIApplicationDelegate> services;

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
    // check that services responds to delegate method
    // if ([services respondsToSelector:...])
    if ([self.services respondsToSelector:_cmd]) {
        return [self.services application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation];
    }

    return NO/YES; // your choice
}

@end

After all

You can delegate all AppDelegate methods to external classes.

Your trouble was 'extensive usage of appDelegate methods'.

It seems that nobody wants to cleanup app delegate in apps because 'it just works'. I just show you ( bad or good? don't know ) an example of chain of responsibility pattern and simple delegation.

Remember, you can delegate most of your AppDelegate methods to other objects/classes, for example, you can provide smart 'PushNotificationsRouter' that will handle all push notification-related methods.

Upvotes: 1

Related Questions