上篇如何把业务逻辑从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的讨论。
总之我们要学会用好这把锋利的刀,而不是弃用。
网友评论
为什么这个方法会swizzing不过来。。。。
同时,在博主最后给的 Stack Overflow 中有提到: 『Method Swizzling is not atomic』
所以在使用的时候一定要慎重。
如果是我的话,公司代码我是会尽量避免使用 Method Swizzling 来对代码瘦身的。