如何给你的AppDelegate瘦身

作者: 槛内浊物 | 来源:发表于2016-01-28 21:52 被阅读2776次

    上篇如何把业务逻辑从ViewController中拆分出来讲了给ViewController瘦身,这篇继续讲给AppDelegate瘦身。

    我见过这样的代码

    Appdelegate.m
    
    [UMSocialData setAppKey:UMENG_APPKEY];
    //打开调试log的开关
    [UMSocialData openLog:YES];
    //向微信注册
    [WXApi registerApp:WXAppId];
    //设置微信AppId,设置分享url,默认使用友盟的网址
    [UMSocialWechatHandler setWXAppId:WXAppId appSecret:WXAppSecret url:UMSocialShareUrl];
    [UMSocialQQHandler setQQWithAppId:WXQQId appKey:WXQQKey url:UMSocialShareUrl];
    // 新浪微博
    [UMSocialSinaHandler openSSOWithRedirectURL:SinaRedirectURL];
    //设置支持没有客户端情况下使用SSO授权
    [UMSocialQQHandler setSupportWebView:YES];
    
    基础数据
    。。。
    。。。
    
    Push
    
    ......
    ......    
    
    数据库
    
    ....
    等等。。。。
    

    App delegate里面一堆东西,自己看着都头疼。
    因为刚开始的时候可能只是加了一个友盟分享,后来公司要加Jpush,然后继续在Appdelegate里面加,再后来......
    无穷无尽的需求,然后Appdelegate不忍直视。

    通过单例给AppDelegate瘦身

    既然ViewController可以通过一个manager类来瘦身,是否能够运用到Appdelegate里面呢,当然可以。
    类似于友盟的初始化,我们可以这么做

    - (void)launchApp:(UIApplication *)application withOptions:(NSDictionary *)launchOptions {
    
         [UMManager getInstance];
    }
    

    然后再写一个UMManager的单例,把上面Appdelegate里面的那些友盟统计的代码在UMManager里面实现。

    @implementation UMManager
    
    + (UMManager *)getInstance{
        static UMManager *sharedInstance;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            sharedInstance = [[self alloc] init];
        });
        return sharedInstance;
    }
    
    - (id)init{
        if (self = [super init]) {
            [self setUM];
        }
        return self;
    }
    
    - (void)setUM
    {
        [UMSocialData setAppKey:UMENG_APPKEY];
        //打开调试log的开关
        [UMSocialData openLog:YES];
        //向微信注册
        [WXApi registerApp:WXAppId];
        //设置微信AppId,设置分享url,默认使用友盟的网址
        [UMSocialWechatHandler setWXAppId:WXAppId appSecret:WXAppSecret url:UMSocialShareUrl];
        [UMSocialQQHandler setQQWithAppId:WXQQId appKey:WXQQKey url:UMSocialShareUrl];
        // 新浪微博
        [UMSocialSinaHandler openSSOWithRedirectURL:SinaRedirectURL];
        //设置支持没有客户端情况下使用SSO授权
        [UMSocialQQHandler setSupportWebView:YES];
    }
    @end
    

    这样AppDelegate看起来就干净多了。除此之外还有更重要的,通过Method Swizzing来给AppDelegate瘦身

    通过Method Swizzing给AppDelegate瘦身

    关于MethodSwizzing这里有几篇文章
    Objective-C Runtime 运行时之四:Method Swizzling
    Objective-C Method Swizzling 的最佳实践

    @implementation AppDelegate (PushManager)
    
    + (void)load
    {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            Class class = [self class];
            swizzleMethod(class, @selector(application:didFinishLaunchingWithOptions:),
                          @selector(aop_application:didFinishLaunchingWithOptions:));
            swizzleMethod(class, @selector(application:didRegisterForRemoteNotificationsWithDeviceToken:),
                          @selector(aop_application:didRegisterForRemoteNotificationsWithDeviceToken:));
            swizzleMethod(class, @selector(application:didFailToRegisterForRemoteNotificationsWithError:),
                          @selector(aop_application:didFailToRegisterForRemoteNotificationsWithError:));
            swizzleMethod(class, @selector(application:didReceiveRemoteNotification:),
                          @selector(aop_application:didReceiveRemoteNotification:));
            swizzleMethod(class, @selector(application:didReceiveRemoteNotification:fetchCompletionHandler:),
                          @selector(aop_application:didReceiveRemoteNotification:fetchCompletionHandler:));
        });
    }
    
    
    static inline void swizzleMethod(Class class, SEL originalSelector, SEL swizzledSelector)   {
        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
        BOOL didAddMethod =
        class_addMethod(class,
                        originalSelector,
                        method_getImplementation(swizzledMethod),
                        method_getTypeEncoding(swizzledMethod));
    
        if (didAddMethod) {
            class_replaceMethod(class,
                                swizzledSelector,
                                method_getImplementation(originalMethod),
                                method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    }
    
    - (BOOL)aop_application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        [self setUpJPushManagerWithOptions:launchOptions];
    
        BOOL result = [self aop_application:application didFinishLaunchingWithOptions:launchOptions];
    
        NSDictionary *userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
        if(userInfo)
        {
            //分发
            [self pushDispatch:userInfo];
        }
        return result;
    }
    
    // push注册成功
    - (void)aop_application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
    {
        [self aop_application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
    
        NSUserDefaults *ud = [NSUserDefaults  standardUserDefaults];
        NSString *tokenStr = [NSString stringWithFormat:@"%@",deviceToken];
        [ud setObject:tokenStr forKey:@"deviceToken"];
        [ud synchronize];
    
        UI_LOG(@"deviceToken = %@", tokenStr);
    
        // Required
        [APService registerDeviceToken:deviceToken];
    }
    
    // push注册失败
    - (void)aop_application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
    {
        [self aop_application:application didFailToRegisterForRemoteNotificationsWithError:error];
    }
    
    // iOS7
    - (void)aop_application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
    {
        [self aop_application:application didReceiveRemoteNotification:userInfo];
    }
    
    // iOS8及以上
    - (void)aop_application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
    {  
         [self aop_application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
    }
    
    ......
    ......
    

    有人说MethodSwzzing用起来爽,用不好的话会出问题,而且很难排查。我曾经在网上看到过这么一段话,觉着很经典。拿来分享给大家:

    Method Swzzing就像是一把锋利的刀,用锋利的刀切菜固然很爽,但是容易把手切破。你不能因为刀锋利,就不用吧。相反你用钝刀风险可能更大。就像单例设计模式一样,饱受争议,但依然有很多人用它。

    这里有一些StackOverFlow关于Method Swzzing的讨论。

    What are the Dangers of Method Swizzling in Objective C?

    总之我们要学会用好这把锋利的刀,而不是弃用。

    相关文章

      网友评论

      • 绍清_shao:写的还可以
      • d9557f883fd8:application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
        为什么这个方法会swizzing不过来。。。。
      • Boolean93:Method Swizzling 这种运行时的黑魔法会躲过编译时对类型的检查,同时也会让代码变得不是那么容易理解。
        同时,在博主最后给的 Stack Overflow 中有提到: 『Method Swizzling is not atomic』
        所以在使用的时候一定要慎重。
        如果是我的话,公司代码我是会尽量避免使用 Method Swizzling 来对代码瘦身的。
        槛内浊物:@Boolean93 嗯,只要不滥用就好。
      • leftwater:good
        槛内浊物:@leftwater :relaxed:

      本文标题:如何给你的AppDelegate瘦身

      本文链接:https://www.haomeiwen.com/subject/qmdjkttx.html