preface

The modularity of iOS can be traced back to BeeHive in 2016. BeeHive modularizes functions and constructs them in the form of module, responds module events in the form of performSelector:, and communicates between modules in the form of protocol. I can say I’m thinking very clearly. BeeHive is an elegant but still improving decoupling framework. BeeHive is an elegant but still improving decoupling framework. In fact, I don’t think BeeHive can really be used in our project. It does build modules, but the memory problems associated with module instances can be a headache. Personally, I think it’s perfectly possible to adapt the Module part of BeeHive to our AppDelegate. Let’s move on to the text.

directory

1. Module splitting

Module event response

3. Module management

  • 1. Module registration
  • 2. The trigger event
  • 3. Remove the module

Four,

1. Module splitting

Module1 through Module4 represent the business logic we need to handle in the Appdelegate, such as our database processing, sharing, pushing, and so on.

@protocol SHRMAppEventModuleProtocol <UIApplicationDelegate>

- (NSInteger)moduleLevel;
- (void)destroyModule;
- (NSString *)moduleID;

@end
Copy the code

ModuleLevel returns the priority of module execution, destroyModule releases modules, and moduleID returns the ID of the current module. The default implementation of interfaces is in BaseAppEventModule. BaseAppEventModule is the parent of all modules. Only modules that inherit BaseAppEventModule can be managed.

About BaseAppEventModule default implementation is also very simple, when to destroy the module USES SHRMAppEventModuleManager as below, the default priority of 100.

@interface SHRMBaseAppEventModule : NSObject <SHRMAppEventModuleProtocol>

@end


#define MODULE_LEVEL_DEFAULT 100
@implementation SHRMBaseAppEventModule

- (NSInteger)moduleLevel {
    return MODULE_LEVEL_DEFAULT;
}

- (void)destroyModule {
    [[SHRMAppEventModuleManager sharedInstance] removeModule:[self moduleID]];
    NSLog(@"%@ destroy",NSStringFromClass([self class]));
}

- (NSString *)moduleID {
    return NSStringFromClass([self class]);
}

@end
Copy the code

Module creation must inherit from SHRMBaseAppEventModule. Only modules that inherit from SHRMBaseAppEventModule will be managed. Because only SHRMBaseAppEventModule followed SHRMAppEventModuleProtocol agreement. About creating a Module:

@interface testMudule : SHRMBaseAppEventModule
@end

@implementation testMudule

- (NSInteger)moduleLevel {
    return 1;
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [self initMudule];
    [self destroyModule];
    return YES;
}

- (void)initMudule {
    NSLog(@"testMudule init");
}

@end
Copy the code

Application: didFinishLaunchingWithOptions: function implementation shows a module of the whole life cycle, from creation to destruction process, then the application: DidFinishLaunchingWithOptions: how response, actually did not teach him any interface module headers, here is to realize the function of the modular. So why did I get here, thanks to the powerful Runtime selector function performSelector: so now I’m going to talk about my handling of module event responses.

Module event response

Above or below the application: didFinishLaunchingWithOptions: function, for example, how did it come, obviously this is the inside of the AppDelegate APP lifecycle callback:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [[SHRMAppEventModuleManager sharedInstance] handleApplicationEvent:@selector(application:didFinishLaunchingWithOptions:)  Complete:^(id _Nonnull module, SEL _Nonnull sel) {#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
        [module performSelector:sel
                     withObject:application
                     withObject:launchOptions];
#pragma clang diagnostic pop
    }];
    return YES;
}
Copy the code

Not wrong, this make AppDelegate application: didFinishLaunchingWithOptions: with these, as a result, all realized the application: DidFinishLaunchingWithOptions: modlue can be invoked, call priority according to the moduleLevel interface definition is returned. At this point we’re done slimming down the AppDelegate, but the other callback handling in the AppDelegate is the same. Of course there is a very important didn’t say, what he did is SHRMAppEventModuleManager, through the above chart can see SHRMAppEventModuleManager is a middleware, used to dealing with the relationship between the module and AppDelegate. Now comes the third part, module management.

3. Module management

SHRMAppEventModuleManager provides a singleton, three interfaces:

/** Initialize all appdelegate-related Event Modules */ - (void)registedAllModules; @param eventSel AppDelegate callback message @param Complete Module Handle handle */ - (void)handleApplicationEvent:(SEL)eventSel Complete:(void(^)(id module,SEL sel))complete; @param moduleID moduleID */ - (void)removeModule:(NSString *)moduleID;Copy the code

1. Module registration

The idea of module registration is to follow the BeeHive idea completely, at compile time our module through the __attribute function registration. At runtime, we take out the registered module and instantiate it in registedAllModules, and store it in order according to the return value of Level. See my previous article to write a Hybrid framework that is easy to maintain, easy to use, and reliable for performance.

2. The trigger event

HandleApplicationEvent: Complete: as the core function of the module incident response:

- (void)handleApplicationEvent:(SEL)eventSel
                      Complete:(void(^)(id module,SEL sel))complete {
   
    NSMutableArray *tmpAppEventModules = [[NSMutableArray alloc] initWithArray:self.appEventModules];
    for (id<SHRMAppEventModuleProtocol>module in tmpAppEventModules)
    {
        if ([module conformsToProtocol:@protocol(SHRMAppEventModuleProtocol)])
        {
            if ([module respondsToSelector:eventSel]) {
                if (complete) {
                    complete(module,eventSel);
                }
            }
        }
    }
}
Copy the code

If ([module respondsToSelector: eventSel]) is executed will complete the module and sel returns, namely the AppDelegate inside, and then perform the sel function of the module, and transfer parameters in the past.

3. Remove the module

Module removal. In the AppDelegate, we manually remove functions that are no longer used after the application is started. Module removal is a bit more complicated, but in the AppDelegate, it’s perfectly possible to know which modules can be removed immediately after loading. Additionally, we only modularize in the AppDelegate. The number of module instances will be very small, so there is no need to worry about the memory overhead associated with the Module.

- (void)removeModule:(NSString *)moduleID {
    NSInteger index = NSNotFound;
    NSInteger resIndex = 0;
    for (id<SHRMAppEventModuleProtocol>module in self.appEventModules)
    {
        if ([[module moduleID] isEqualToString:moduleID])
        {
            index = resIndex;
            break;
        }
        resIndex++;
    }
    
    if (index != NSNotFound) {
        [self.appEventModules removeObjectAtIndex:index];
    }
}
Copy the code

conclusion

Finally sum up, about modularity, now generally more popular, there are a lot of introduction to modularity, componentization of the specific implementation of the road, are very good, but also worth learning. As for decoupling, I prefer the protocol approach, where the interface is protocolized and the code is readable and clear. I have read mrPeak’s article on componentization. The portal iOS componentization scheme, I think protocol+ Version scheme is very similar to BeeHive, protocol decoupling, version module version management. However, it still does not solve the memory overhead problem brought by module. Once module is refined, when to destroy it is also a headache for developers. So much for now, if you have any questions, please feel free to discuss them in the comments section.

Finally, add a portal: SHRMAppDelegate