A while back, I saw an article about AppDelegate slimming: The AppDelegate Slimming Guide. Think of something you’ve done in this area and share it with us. I wrote a separate class library to handle this problem: MRAppDelegateComponents.
Use can be directly:
pod 'MRAppDelegateComponents'
Copy the code
I won’t go into the problem the AppDelegate ran into. The problem with The AppDelegate is that the AppDelegate is essentially a portal to the entire App, and it’s especially easy to load too much business logic and become a bloated class. The same problem applies to viewControllers. For now, let’s just focus on decoupling the AppDelegate. Decoupling problem about ViewController DZViewControllerLifeCircleAction can refer to my another library. Decoupling is the unbundling of different pieces of code into different units or modules (depending on the method of unbundling) according to their responsibilities.
After dismantling, the first thing to ensure is the smooth execution of the original business logic. And if there is interaction between the various business logic, it can be completed smoothly.
There are two main types of solutions we’ve seen before:
-
One group focuses on distribution, such as FRDModuleManager and JStherapist. Through some mechanism, Delegate is distributed to execute on the corresponding business unit. Execution between business units is not mutually exclusive. But using all the options, forwarding is a hassle.
-
One is Category. Although this can be disassembled, the same method cannot appear in different categories due to the technical limitations of categories. The result is mutual exclusion. In other words, you can only write one copy of the same method. Otherwise there will be problems.
When we take a closer look at the methods in the AppDelegate, we’ll see that some of them return values:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
Copy the code
And that naturally leads to the question, what do I do with this return value?
Such as the needs of application in multiple modules: didFinishLaunchingWithOptions: a certain action. Normally we discard the return value. Return YES; .
When the same function returns a certain value, we naturally think of a design pattern: the chain of responsibility pattern. All the same calls are in a chain, and the current processing unit does something based on the results of the previous processing unit, and can decide whether to continue processing.
Let’s clarify the solution here: decouple the AppDelegate calls into a chain of responsibilities model. And meet the following characteristics:
- Each module can implement the AppDelegate methods without limit.
- Each module will implement multiple AppDelegate functions to perform certain business logic, such as processing URLScheme.
- For functions that return values, the call relationship is converted into a chain of responsibilities. Enables callers to interact with each other based on the return value.
Let’s take a look at the solution. Here are the two logical units that are stripped out (the code can be found in the Demo from MRAppDelegateComponents). Once these classes are created, The key is to realize the agreement MRApplicationDelegateInjectionProtocol, the framework will automatically perform you overloaded methods:
#import <MRAppDelegateComponents/MRAppDelegateComponents.h>
@interface MRAppDelegateLogic1 :NSObject <UIApplicationDelegate, MRApplicationDelegateInjectionProtocol>
@end
@implementation MRAppDelegateLogic1
- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
SEL sel = @selector(application:didFinishLaunchingWithOptions:);
if (__MRSuperImplatationCurrentCMD__(sel)) {
MRPrepareSendSuper(BOOL, id, id);
MRSendSuperSelector(sel, application, launchOptions);
}
NSLog(@"MRAppDelegateLogic1 handle");
return YES;
}
@end
Copy the code
#import <MRAppDelegateComponents/MRAppDelegateComponents.h>
@interface MRAppDelegateLogic2 :NSObject <UIApplicationDelegate, MRApplicationDelegateInjectionProtocol>
@end
@implementation MRAppDelegateLogic2
- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
SEL sel = @selector(application:didFinishLaunchingWithOptions:);
if (__MRSuperImplatationCurrentCMD__(sel)) {
MRPrepareSendSuper(BOOL, id, id);
MRSendSuperSelector(sel, application, launchOptions);
}
NSLog(@"MRAppDelegate Logic2 handle magic");
return YES;
}
@end
Copy the code
We’ll explain the usage first, and then we’ll explain the implementation. Take MRAppDelegateLogic2 as an example. We can see, I opened a class MRAppDelegateLogic2 and reloading the application: didFinishLaunchingWithOptions: method. And then there are a couple of interesting things in the function implementation body.
I start by defining a variable for the current function. I then use a macro I wrote to see if its parent implements the method, and if it does, I call it, and if it doesn’t, I don’t. Then execute a piece of custom logic. The return value of the parent method is ignored here. Of course you can handle it.
When you run the Demo, you will see your logic output properly.
:MRAppDelegateLogic1 handle
:MRAppDelegate Logic2 handle magic
Copy the code
How does that work here? It uses MRLogicInjection, a basic class library that I wrote earlier.
- Hook the setDelegate method of UIApplication
- Search for all protocols that follow our custom (
MRApplicationDelegateInjectionProtocol
) the class - Inject the logic of a method of the same name into the previous class, generate a new metaclass, and repeat until all classes have been injected
- AppDeletge’s ISA pointer points to the new metaclass
This completes the dismantling of the class. At the same time, it has satisfied several demands that we said at the beginning. In MRLogicInjection I did some in-depth explanation of LogicInjection stuff. For additional details, refer to the ReadMe file for MRLogicInjection.
At the same time, we will find that. Such a processing strategy implements the ability to break a class into multiple classes and then merge them together. Of course this can be done using OC’s original inheritance strategy. But native inheritance can be awkward when dealing with a Delegate. UITextView delegate and there’s a UIScrollDelegate. Two delegates are rubbed together, and when you want to listen for a change in Scroll in another class, it affects the original delegate, because the delegate pointer only has one. You can also handle delegte of a UITextView using the same mechanism you just described.
In summary, MRAppDelegateComponents is an instance of a module that decouples and disassembles a delegate based on MRLogicInjection. You can solve the AppDeleagte problem by just using this library. If you want to handle other Delegate issues, you can refer to the implementation of this library.
Transmission speed optimization scheme