iOS之UIApplicationDelegateMethod初探

写在前面

  我们在开发iOS应用中我们首先接触的应该就是这么一对文件AppDelegate的.h和.m那么,在它里面我们都能做哪些操作呢?下面让我带大家一起来解开AppDelegate的神秘面纱。

首先让我们呢先看一下AppDelegate.h里面有什么让我们值得一看的.

#import <UIKit/UIKit.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;
@end

首先呢,我们看到AppDelegate是继承自UIResponder的。具体UIResponder是什么鬼这个我会专门写一篇博客来讲述,这里不做过多介绍。

我们在创建工程的时候系统在AppDelegate.h这个文件里专门为我们建立了一个window 这个window就是我们的应用的main window,它的功能是我们的应用来管理控制设备上显示的视图。值得注意的是:

   Unless an app can display content on an external device screen, an app has only one window.

意思大概是这样:除非我们的应用可以在外部设备上来展示内容,那么我们的app只能有一个window.

他是遵循UIApplicationDelegate这个代理的。那么这个代理方法都有那些呢?这些代理方法我们什么时候才用呢?接下来让我们一起来看一下有哪些代理方法吧!

@protocol UIApplicationDelegate<NSObject>

@optional

- (void)applicationDidFinishLaunching:(UIApplication *)application;
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(nullable NSDictionary *)launchOptions NS_AVAILABLE_IOS(6_0);
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(nullable NSDictionary *)launchOptions NS_AVAILABLE_IOS(3_0);

- (void)applicationDidBecomeActive:(UIApplication *)application;
- (void)applicationWillResignActive:(UIApplication *)application;
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url NS_DEPRECATED_IOS(2_0, 9_0, "Please use application:openURL:options:") __TVOS_PROHIBITED;
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(nullable NSString *)sourceApplication annotation:(id)annotation NS_DEPRECATED_IOS(4_2, 9_0, "Please use application:openURL:options:") __TVOS_PROHIBITED;
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString*, id> *)options NS_AVAILABLE_IOS(9_0); // no equiv. notification. return NO if the application can't open for some reason

- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application;     
- (void)applicationWillTerminate:(UIApplication *)application;
- (void)applicationSignificantTimeChange:(UIApplication *)application; 

- (void)application:(UIApplication *)application willChangeStatusBarOrientation:(UIInterfaceOrientation)newStatusBarOrientation duration:(NSTimeInterval)duration __TVOS_PROHIBITED;
- (void)application:(UIApplication *)application didChangeStatusBarOrientation:(UIInterfaceOrientation)oldStatusBarOrientation __TVOS_PROHIBITED;

- (void)application:(UIApplication *)application willChangeStatusBarFrame:(CGRect)newStatusBarFrame __TVOS_PROHIBITED;  
- (void)application:(UIApplication *)application didChangeStatusBarFrame:(CGRect)oldStatusBarFrame __TVOS_PROHIBITED;

 - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings NS_AVAILABLE_IOS(8_0) __TVOS_PROHIBITED;

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken NS_AVAILABLE_IOS(3_0);

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error NS_AVAILABLE_IOS(3_0);

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo NS_AVAILABLE_IOS(3_0);

- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification NS_AVAILABLE_IOS(4_0) __TVOS_PROHIBITED;

- (void)application:(UIApplication *)application handleActionWithIdentifier:(nullable NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void(^)())completionHandler NS_AVAILABLE_IOS(8_0) __TVOS_PROHIBITED;
- (void)application:(UIApplication *)application handleActionWithIdentifier:(nullable NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void(^)())completionHandler NS_AVAILABLE_IOS(9_0) __TVOS_PROHIBITED;

- (void)application:(UIApplication *)application handleActionWithIdentifier:(nullable NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void(^)())completionHandler NS_AVAILABLE_IOS(8_0) __TVOS_PROHIBITED;
- (void)application:(UIApplication *)application handleActionWithIdentifier:(nullable NSString *)identifier forLocalNotification:(UILocalNotification *)notification withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void(^)())completionHandler NS_AVAILABLE_IOS(9_0) __TVOS_PROHIBITED;

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED;

- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED;

- (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void(^)(BOOL succeeded))completionHandler NS_AVAILABLE_IOS(9_0) __TVOS_PROHIBITED;

- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler NS_AVAILABLE_IOS(7_0);

- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(nullable NSDictionary *)userInfo reply:(void(^)(NSDictionary * __nullable replyInfo))reply NS_AVAILABLE_IOS(8_2);

- (void)applicationShouldRequestHealthAuthorization:(UIApplication *)application NS_AVAILABLE_IOS(9_0);

- (void)applicationDidEnterBackground:(UIApplication *)application NS_AVAILABLE_IOS(4_0);
- (void)applicationWillEnterForeground:(UIApplication *)application NS_AVAILABLE_IOS(4_0);

-(void)applicationProtectedDataWillBecomeUnavailable:(UIApplication *)application NS_AVAILABLE_IOS(4_0);

- (void)applicationProtectedDataDidBecomeAvailable:(UIApplication *)application    NS_AVAILABLE_IOS(4_0);

@property (nullable, nonatomic, strong) UIWindow *window NS_AVAILABLE_IOS(5_0);

- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(nullable UIWindow *)window  NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED;

- (BOOL)application:(UIApplication *)application shouldAllowExtensionPointIdentifier:(NSString *)extensionPointIdentifier NS_AVAILABLE_IOS(8_0);

#pragma mark -- State Restoration protocol adopted by UIApplication delegate --

- (nullable UIViewController *) application:(UIApplication *)application viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents coder:(NSCoder *)coder NS_AVAILABLE_IOS(6_0);
- (BOOL) application:(UIApplication *)application shouldSaveApplicationState:(NSCoder *)coder NS_AVAILABLE_IOS(6_0);
- (BOOL) application:(UIApplication *)application shouldRestoreApplicationState:(NSCoder *)coder NS_AVAILABLE_IOS(6_0);
- (void) application:(UIApplication *)application willEncodeRestorableStateWithCoder:(NSCoder *)coder NS_AVAILABLE_IOS(6_0);
- (void) application:(UIApplication *)application didDecodeRestorableStateWithCoder:(NSCoder *)coder NS_AVAILABLE_IOS(6_0);

#pragma mark -- User Activity Continuation protocol adopted by UIApplication delegate --

- (BOOL)application:(UIApplication *)application willContinueUserActivityWithType:(NSString *)userActivityType NS_AVAILABLE_IOS(8_0);


- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void(^)(NSArray * __nullable restorableObjects))restorationHandler NS_AVAILABLE_IOS(8_0);

- (void)application:(UIApplication *)application didFailToContinueUserActivityWithType:(NSString *)userActivityType error:(NSError *)error NS_AVAILABLE_IOS(8_0);

- (void)application:(UIApplication *)application didUpdateUserActivity:(NSUserActivity *)userActivity NS_AVAILABLE_IOS(8_0);
@end
大概呢也就上面你的一些方法,我们可以看到这些方法是optional的,也就是说我们可以根据自己的需要来选择使用哪些方法。

我们在解释上面的方法使用之前我觉得很有必要申明一下程序的几种状态:

  • 第一种: Not running

    这种应该很容易理解:也就是说我们的程序处于没有启动的状态或者被杀死的状态,包括被用户或者系统 kill掉。

  • 第二种:Inactive

    这种指的是程序正在运行中,但是没有接收到事件,这时候它可能在处理其他的代码事件。一般我们的程序在这个状态的停留时间会很短。一旦我们的程序进入到这个状态,程序就会进入休眠期(不活跃状态),它的下一个状态可能是活跃状态或者进入到后台。唯一在此状态停留时间比较长的情况是:当用户锁屏时,或者系统提示用户去响应某些(诸如电话来电、有未读短信等)事件的时候。

  • 第三种:Active

    这种状态是我们的应用程序常处的一种状态,在这种状态下,应用程序接收各种事件,不会有那么多的限制,我们可以对应用程序进行操作,用户可以直观的看到自己操作对程序的影响。

  • 第四种:Background

    程序处于这种状态下,应用程序正在执行代码,但是处理的方式在我们所看不到的地方,当我们的用户退出应用程序的时候,应用程序在没有进入到休眠期的时候会引入到background状态,这个状态持续时间比较短。在其他的时候,系统可能会从后台来启动我们的程序,也可能程序从休眠状态下被唤醒,给他一定的时间来处理一些特殊的任务。比如说:系统可能被唤醒一个应用程序,它可以处理后台下载、 某些类型的位置事件(定位)、 远程通知和其他类型的事件。

    一个应用进入到后台状态要尽可能的执行较少的任务,应用程序需要时间来处理特定类型的事件应该处理这些事件,并将控制权返回尽可能快地回系统(做完这些后台就把处理事件的权利交给系统,让系统拥有话语权)。

  • 第五种:Suspended

    应用程序在内存中,但不执行的代码不处理事件。系统挂起的应用程序,并在后台中并没有任何挂起的任务要完成。系统可能在没有唤醒应用的情况下,会为其他应用程序腾出空间清除挂起的应用程序。换句话说:如果我们的应用程序一旦被挂起,并且在一段时间内没有被唤醒,那么我们的系统就会为前台正在运行的程序把应用从内存中移除,以保证前台运行的程序内存充足。

应用程序的五种状态讲完以后,下面让我们一一来看看UIApplicationDelegate的代理方法的使用吧.

- (void)applicationDidFinishLaunching:(UIApplication *)application {
// 
}

这个方法作用是创建我们的应用界面和初始化我们数据。功能和application:didFinishLaunchingWithOptions: 这个方法是类似的。 但是在官方文档中告诉我们:这个方法虽然没有被废弃,但是不建议我们使用这个方法 而是要使用application:willFinishLaunchingWithOptions: and application:didFinishLaunchingWithOptions: 这两个方法来替代。

- (BOOL)application:(UIApplication *)application
willFinishLaunchingWithOptions:(NSDictionary *)launchOptions{  
//

return  YES;  
}

使用此方法 (和相应的应用程序: didFinishLaunchingWithOptions: 方法) 来初始化我们的应用程序,并准备运行。当我们的程序已经启动,并且启动的storyboard和xib文件已经被加载的时候我们的这个方法就会调用,但是有一点需要我们注意:我们要在应用程序的状态被恢复之前调用此方法。当这个方法被调用的时候,应用程序处于非激活状态。

如果我们的应用程序被系统的一个特殊行为所唤醒,launchOptions 字典包含应用被启动的信息。对于更多的启动的原因,系统可能会调用您的应用程序代理的其他方法。例如,如果您的应用程序,旨在打开 URL,系统调用应用程序: openURL:options: 方法后应用程序完成初始化的本身。我们获得启动的keys携带了一些信息,这些信息给了我们机会去谋划一些事情。如果要打开的 URL是我们想要打开的文档,那么我们就要阻止应用状态的恢复。

当被询问是否打开URL的时候,从该方法返回的结果根据我们的应用程序: didFinishLaunchingWithOptions 的返回结果: 确定是否应处理 URL 的方法。如果某一个方法返回 NO,系统并不会唤醒应用的: openURL:options: 方法。如果你没有实现他们其中的任何一个方法,只有返回值才是决定我们最终的结果。意思就是说:如果我们没有对上面的任何一种方法进行操作那么决定应用处理的结果只能由最后的return结果决定的。

在某些情况下,用户启动我们的应用程序与首页屏幕交互。为了确保你正确处理这种情况,建议理解一下应用程序的 performActionForShortcutItem:completionHandler :方法。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
    self.window.backgroundColor = [UIColor whiteColor];
    self.window.rootViewController = [[ViewController alloc]init];
    [self.window makeKeyAndVisible];
    return YES;
}

我们在使用纯代码来自己设定ROOTVC的时候就是在这个方法中处理的(如上面的代码所示)。 在storyboard中我们需要做的就是设置ROOTVC 见下图 设置 initial view controller 设置要rootVC以后,我们的application:didFinishLaunchingWithOptions 就不用写其他代码了,只需要写上return YES 就行了。

这个方法是告诉代理我们的启动进程已经完毕,应用程序已经准备开始启动。如果应用程序不能处理 URL资源或继续用户活动,否则返回 YES。如果应用程序启动远程通知,则忽略返回值。其中参数launchOptions 这个字典中附带的信息是我们的应用启动的原因,可能为空。有关可能的key在这本字典和如何处理它们的信息,请参阅启动选项键。

- (void)applicationDidBecomeActive:(UIApplication *)application {

}

这个方法是我们的应用已经处于被激活的状态了。 触发这种状态改变的行为可能是用户或者系统触发。应用程序还可以返回到活动状态,如果用户选择忽略中断 (如电话来电或短信) 让我们的应用程序暂时处于非活动状态。

当我们的应用处于非激活状态的情况下,我们可以使用这个方法来重新启动任何任务的(处于暂停状态或尚未开始)。例如,你可以使用它来重新启动计时器或调节的 OpenGL ES 的帧速率。如果您的应用程序以前在背景中,也可以使用来刷新您的应用程序的用户界面

调用此方法后,应用程序会发送一个,UIApplicationDidBecomeActiveNotification 通知 给目标对象一个机会来响应出路程序的这种状态的改变。

- (void)applicationWillResignActive:(UIApplication *)application {

}

调用此方法标志着即将从活跃状态移动到非活动状态,导致这种状态转变的原因这可能有新来电或者有新消息。当用户退出应用程序,它就开始进入后台处理状态。在非激活状态的应用程序继续运行,但是不发事件的响应。 应使用此方法来暂停正在进行的任务,禁用计时器,并放慢 OpenGL ES 的帧速率。游戏应该使用这个方法来暂停游戏。处于非活动状态的应用程序应该尽可能少的做工作,并等待进入到激活或后台状态。

如果我们的应用程序有未保存的用户数据,我们可以在这里保存它确保信息不丢失。但是我们最好在在程序运行期间进行保存数据。例如,保存数据,当用户关闭数据输入屏幕。我们不应该依赖特定应用程序的状态转换,用来保存所有的应用程序的关键数据。 意思大概就是说我们 不能够仅仅靠这个方法来保存我们需要保存的个人数据,我们可以通过自己的操作来存储数据。

调用此方法后,应用程序同样会发送一个UIApplicationWillResignActiveNotification 通知给目标对象一个机会来响应出路程序的这种状态的改变。通过这个通知,我们的应用程序可以处理一些操作。

附:

1.UIApplication简单介绍

(1)UIApplication对象是应用程序的象征,一个UIApplication对象就代表一个应用程序。

(2)每一个应用都有自己的UIApplication对象,而且是单例的,如果试图在程序中新建一个UIApplication对象,那么将报错提示。

(3)通过[UIApplication sharedApplication]可以获得这个单例对象

(4) 一个iOS程序启动后创建的第一个对象就是UIApplication对象,且只有一个(通过代码获取两个UIApplication对象,打印地址可以看出地址是相同的)。

(5)利用UIApplication对象,能进行一些应用级别的操作

2.iOS程序启动原理

3.程序启动的完整过程

1.main函数

2.UIApplicationMain

  • 创建UIApplication对象

  • 创建UIApplication的delegate对象

3.delegate对象开始处理(监听)系统事件(没有storyboard)

  • 程序启动完毕的时候, 就会调用代理的application:didFinishLaunchingWithOptions:方法

  • 在application:didFinishLaunchingWithOptions:中创建UIWindow

  • 创建和设置UIWindow的rootViewController

  • 显示窗口

3.根据Info.plist获得最主要storyboard的文件名,加载最主要的storyboard(有storyboard)

  • 创建UIWindow

  • 创建和设置UIWindow的rootViewController

  • 显示窗口

    水平有限,写的有点仓促,写的还有很多不足之处,欢迎加群交流 QQ群:214541576

comments powered by Disqus