美文网首页
AppDelegate 分层,实现解耦和瘦身

AppDelegate 分层,实现解耦和瘦身

作者: allenzhan | 来源:发表于2018-05-10 15:56 被阅读0次

    一个 iOS 应用可能集成了大量的服务,远程推送、本地推送、生命周期管理、第三方支付、第三方分享....。有没有觉得你的Appdelegate 太过庞大了,有没有想过将每个服务重Appdelegate中拆分出来单独管理。

    AppDelegate 做了太多事

    AppDelegate 并不遵循单一功能原则,它要负责处理很多事情,如应用生命周期回调、远程推送、本地推送、应用跳转(HandleOpenURL);如果集成了第三方服务,大多数还需要在应用启动时初始化,并且需要处理应用跳转,如果在 AppDelegate 中做这些事情,势必让它变得很庞大。

    不同服务的代码纠缠在一起,使得 AppDelegate 变得很难复用。而且如果你想要添加一个服务或者关闭一个服务,都需要去修改 AppDelegate。很多服务看起来互相独立,并不依赖其它服务,我们可以把它们拆分出来,放在单独的文件里。

    要实现的目标

    1.添加或者删除一个服务的时候,不需要更改 AppDelegate 中的任何一行代码。
    2.AppDelegate 不实现 UIApplicationDelegate 协议中的方法,由协议去实现

    如何实现

    下面就看下怎么实现Appdelegate的分成,下面以极光推送第三方为例

    一、首先创建服务类,服务类是对第三方服务的封装。第三方服务包括推送、支付、统计等

    JPushService 新创建的服务类需要添加 <UIApplicationDelegate> 协议

    //  JPushService.h
    //  ALDNews
    //
    //  Created by Allen on 2018/4/24.
    //  Copyright © 2018年 Aladdin. All rights reserved.
    //
    //JPush 极光推送服务类 服务类
    
    #import <Foundation/Foundation.h>
    #import "NSObject+performSelector.h"
    @interface JPushService : NSObject <UIApplicationDelegate>
    
    @end
    
    实现文件 (仅说明原理)
    //
    //  JPushService.m
    //  ALDNews
    //
    //  Created by Allen  on 2018/4/24.
    //  Copyright © 2018年 Aladdin. All rights reserved.
    //
    
    #import "JPushService.h"
    
    // 引入JPush功能所需头文件
    #import "JPush/JPushService.h"
    #import "HPNewsDetailsController.h"
    // iOS10注册APNs所需头文件
    #ifdef NSFoundationVersionNumber_iOS_9_x_Max
    #import <UserNotifications/UserNotifications.h>
    #endif
    
    #import "UUID.h"
    
    @interface JPushService() <JPUSHRegisterDelegate>
    
    @end
    
    @implementation JPushService
    {
        NSInteger _seq;
    }
    -(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
        LOG(@"JPushService didFinishLaunchingWithOptions");
        [application setApplicationIconBadgeNumber:0];
        [application cancelAllLocalNotifications];
        //Required
       
        // 初始化
        [JPUSHService setupWithOption:launchOptions appKey:[Config getJPushAppkey]
                              channel:@"App Store"
                     apsForProduction:[Config returnAPIType] == APITypeOnline?YES:NO
                advertisingIdentifier:nil];
        
        return YES;
    }
    
    
    
    //注册Token
    -(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
        /// Required - 注册 DeviceToken
        [JPUSHService registerDeviceToken:deviceToken];
        
        
        //设置别名 [UUID getUUID]
        NSString * uuidStr = [[UUID getUUID] stringByReplacingOccurrencesOfString:@"-" withString:@""];
        [JPUSHService setAlias:uuidStr  completion:^(NSInteger iResCode, NSString *iAlias, NSInteger seq) {
            _seq = seq;
        } seq:_seq];
    }
    
    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
        
        // Required, iOS 7 Support
        [JPUSHService handleRemoteNotification:userInfo];
        completionHandler(UIBackgroundFetchResultNewData);
    }
    
    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
        
        // Required,For systems with less than or equal to iOS6
        [JPUSHService handleRemoteNotification:userInfo];
    }
    
    - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
        //Optional
        LOG(@"did Fail To Register For Remote Notifications With Error: %@", error);
    }
    
    //进入后台
    - (void)applicationDidEnterBackground:(UIApplication *)application {
        
        [[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
        [JPUSHService setBadge:0];
        
    }
    @end
    
    
    二、SOAComponentAppDelegate.m实现

    在实现类中,需要引用并注册第三方的服务类。

    //
    //  SOAComponentAppDelegate.h
    //  ALDNews
    //
    //  Created by Allen on 2018/4/24.
    //  Copyright © 2018年 Aladdin. All rights reserved.
    //
    
    //第三方库 组件类
    
    #import <Foundation/Foundation.h>
    
    @interface SOAComponentAppDelegate : NSObject
    
    + (instancetype)instance;
    - (NSMutableArray *)services;
    
    @end
    
    实现类
    //
    //  SOAComponentAppDelegate.m
    //  ALDNews
    //
    //  Created by 占益民 on 2018/4/24.
    //  Copyright © 2018年 Aladdin. All rights reserved.
    //
    
    #import "SOAComponentAppDelegate.h"
    #import "JPushService.h"
    #import "VoiceService.h"
    
    @implementation SOAComponentAppDelegate
    {
        NSMutableArray * allServices;
    }
    
    
    #pragma mark - 服务静态注册
    
    //根据项目要求 添加相应的服务。现在只添加JPush
    - (void)registeServices{
        [self registeService:[[JPushService alloc] init]];
        [self registeService:[[VoiceService alloc] init]];
    }
    
    #pragma mark - 获取SOAComponent 单实例
    + (instancetype)instance{
        static SOAComponentAppDelegate * instance = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            instance = [[SOAComponentAppDelegate alloc] init];
        });
        return instance;
    }
    
    #pragma mark - 获取全部服务
    - (NSMutableArray *) services{
        if (!allServices) {
            allServices = [[NSMutableArray alloc] init];
            [self registeServices];
        }
        return allServices;
    }
    
    
    #pragma mark - 服务动态注册
    - (void)registeService:(id)service{
        if (![allServices containsObject:service]) {
            [allServices addObject:service];
        }
    }
    
    @end
    
    

    三、看下AppDelegate 上需要做哪些操作

    1.AppDelegate.h 不需要做任何修改
    2.AppDelegate.m 导入头文件SOAComponentAppDelegate 和JPushService

    #import "AppDelegate.h"  
    #import "SOAComponentAppDelegate.h"  
    #import "JPushService.h"  
      
    @interface AppDelegate ()  
      
    @end  
      
    @implementation AppDelegate  
      
      
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {  
          
        id<UIApplicationDelegate> service;  
        for(service in [[SOAComponentAppDelegate instance] services]){  
            if ([service respondsToSelector:@selector(application:didFinishLaunchingWithOptions:)]){  
                [service application:application didFinishLaunchingWithOptions:launchOptions];  
            }  
        }  
          
        return YES;  
    }  
      
    - (void)applicationWillResignActive:(UIApplication *)application {  
        id<UIApplicationDelegate> service;  
        for(service in [[SOAComponentAppDelegate instance] services]){  
            if ([service respondsToSelector:@selector(applicationWillResignActive:)]){  
                [service applicationWillResignActive:application];  
            }  
        }  
    }  
      
    - (void)applicationDidEnterBackground:(UIApplication *)application {  
        id<UIApplicationDelegate> service;  
        for(service in [[SOAComponentAppDelegate instance] services]){  
            if ([service respondsToSelector:@selector(applicationDidEnterBackground:)]){  
                [service applicationDidEnterBackground:application];  
            }  
        }  
    }  
      
    - (void)applicationWillEnterForeground:(UIApplication *)application {  
        id<UIApplicationDelegate> service;  
        for(service in [[SOAComponentAppDelegate instance] services]){  
            if ([service respondsToSelector:@selector(applicationWillEnterForeground:)]){  
                [service applicationWillEnterForeground:application];  
            }  
        }  
    }  
      
    - (void)applicationDidBecomeActive:(UIApplication *)application {  
        id<UIApplicationDelegate> service;  
        for(service in [[SOAComponentAppDelegate instance] services]){  
            if ([service respondsToSelector:@selector(applicationDidBecomeActive:)]){  
                [service applicationDidBecomeActive:application];  
            }  
        }  
    }  
      
    - (void)applicationWillTerminate:(UIApplication *)application {  
        id<UIApplicationDelegate> service;  
        for(service in [[SOAComponentAppDelegate instance] services]){  
            if ([service respondsToSelector:@selector(applicationWillTerminate:)]){  
                [service applicationWillTerminate:application];  
            }  
        }  
    }  
      
    @end  
    

    这样就可以完全独立的处理每个不同的第三方服务。

    四、优化

    当然这里还可以有优化的地方

    id<UIApplicationDelegate> service;  
        for(service in [[SOAComponentAppDelegate instance] services]){  
            if ([service respondsToSelector:@selector(applicationWillTerminate:)]){  
                [service applicationWillTerminate:application];  
            }  
        }  
    

    项目中很多地方用到了类似这种的代码。我们也可以将这个代码块做个统一的封装。由于时间关系,我并没有做。但是可以提供一点思路

    用下面的代码统一上面的代码块

    -(void)thirdSDKLifecycleManager:(NSString *)selectorStr withParameters:(NSArray *)params{
        SEL selector = NSSelectorFromString(selectorStr);
        NSObject <UIApplicationDelegate> *service;
        for(service in [[SOAComponentAppDelegate instance] services]){
            if ([service respondsToSelector:selector]){
                  //注意这里的performSelector这个是要自己写分类的(系统不带这个功能的)
                [service performSelector:selector withObjects:params];
            }
        }
    }
    
    
    后面每个生命周期函数只要调用一个方法就可以了,将相应的参数传过去就OK 了
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {  
          
         [self thirdSDKLifecycleManager:@"application:didFinishLaunchingWithOptions:" withParameters:@[application,launchOptions?launchOptions:@""]];
          
        return YES;  
    }  
    

    注意:

     [service performSelector:selector withObjects:params];
    

    这个方法是要自己重写NSObject分类的
    系统的只能带一个或两个参数

    相关文章

      网友评论

          本文标题:AppDelegate 分层,实现解耦和瘦身

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