AppDelegate解耦
说到AppDelegate
,大家想必都不陌生,它作为应用(UIApplication
)的委托对象,在UIApplicationMain
方法中被创建,当发生应用相关事件时,提供开发者响应的机会。
1 2 3 4 5
| int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } }
|
AppDelegate
是UIResponder
的子类,应用将AppDelegate
加入响应链中。UIApplication
作为响应链中的最上层,当UIApplication
任然无法处理特定事件时,会将事件转发给AppDelegate
来处理。
当然,AppDelegate
的主要职责还是响应应用事件,它满足UIApplicationDelegate
协议,UIApplicationDelegate
协议包含大量的委托方法,包括处理应用状态、状态恢复、后台下载数据、通知、URL Route等很多方面,这就会导致,随着程序的开发,AppDelegate
将变得越来越臃肿,为了解决该问题,就需要进行解耦。
JSDecoupledAppDelegate
JSDecoupledAppDelegate的目的就是进行AppDelegate
的解耦,接下来,将讲述一下实现原理。
首先为了实现解耦,需要将AppDelegate
替换为定义好的JSDecoupledAppDelegate
类(该类为单例模式),其相当于一个Proxy
代理类,负责管理分发到不同的协议对象。JSDecoupledAppDelegate
将UIApplicationDelegate
协议进行了分类拆分,生成如下的多个协议,针对每个协议,JSDecoupledAppDelegate
都有一个满足该协议的属性,如@property (strong, nonatomic, nullable) id<JSApplicationStateDelegate> appStateDelegate;
,appStateDelegate
用来存储满足JSApplicationStateDelegate
协议的对象,当该协议定义的方法被调用时,将转发给委托对象进行处理。
1 2 3 4 5 6 7 8 9 10 11 12 13
| @protocol JSApplicationStateDelegate; @protocol JSApplicationDefaultOrientationDelegate; @protocol JSApplicationBackgroundFetchDelegate; @protocol JSApplicationRemoteNotificationsDelegate; @protocol JSApplicationLocalNotificationsDelegate; @protocol JSApplicationStateRestorationDelegate; @protocol JSApplicationURLResourceOpeningDelegate; @protocol JSApplicationShortcutItemDelegate; @protocol JSApplicationHealthDelegate; @protocol JSApplicationProtectedDataDelegate; @protocol JSApplicationWatchInteractionDelegate; @protocol JSApplicationExtensionDelegate; @protocol JSApplicationActivityContinuationDelegate;
|
比如,我们需要处理应用状态相关事件,新建一个处理对象,满足JSApplicationStateDelegate
协议,在对象中定义+load
方法,将JSDecoupledAppDelegate
的appStateDelegate
属性赋给自己,如下所示,再在对象中实现JSApplicationStateDelegate
方法,这样,当应用状态相关事件产生时,该对象就能收到相关事件。
1 2 3 4
| + (void)load { [JSDecoupledAppDelegate sharedAppDelegate].appStateDelegate = [[self alloc] init]; }
|
这样,就实现了AppDelegate
的解耦,针对不同的应用事件类别,由不同的对象进行处理。
有的人就好奇了,JSDecoupledAppDelegate
是怎么实现事件分发的呢?
JSDecoupledAppDelegate
重载了- (BOOL)respondsToSelector:(SEL)aSelector
方法,为什么会选择重载这个方法呢,我们再来思考一下,平时我们实现Delegate
委托方式时,当我们需调用委托对象的某个方法时,首先需要做的就是判断一下委托对象是否实现了该方法,即使用respondsToSelector:
(如果不进行提前判断,当委托对象没有实现该方法时,将导致Crash
),这也就不难解释为什么选择重载该方法了。
直接show code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| - (BOOL)respondsToSelector:(SEL)aSelector { //获取委托属性名,每个协议对应一个属性,如appStateDelegate NSArray *delegateProperties = JSApplicationDelegateProperties();
// 1. 获取定义了aSelector的协议 __block BOOL protocolFound = NO; __block BOOL delegateRespondsToSelector = NO;
[JSApplicationDelegateSubprotocols() enumerateObjectsUsingBlock:^(NSString *protocolName, NSUInteger idx, BOOL *stop) { //获取协议定义的方法 NSSet *protocolMethods = JSSelectorListInProtocol(NSProtocolFromString(protocolName));
const BOOL methodCorrespondsToThisProtocol = [protocolMethods containsObject:NSStringFromSelector(aSelector)];
if (methodCorrespondsToThisProtocol) { protocolFound = YES;
// 2. 获取协议委托对象,如appStateDelegate属性 id delegateObjectForProtocol = [self valueForKey:delegateProperties[idx]]; //判断委托对象是否实现了该方法 delegateRespondsToSelector = [delegateObjectForProtocol respondsToSelector:aSelector];
*stop = YES; } }];
if (protocolFound) { // 3. 返回委托对象是否能响应该方法 return delegateRespondsToSelector; } else { // 4. 如不能响应,走缺省方法处理 return [super respondsToSelector:aSelector]; } }
|
终