[程序员日记]又见UIApplication

在开发过程中,我们很少真正研究过这个类,很多半路出家的程序员对于view的生命周期有所了解,但对UIApplication未深入研究。在开发过程中,相信我们都或多或少的使用了其中的很多功能,下面就来探讨和总结一下其中的内容,又见iOS,就让我们从main开始,重新进入iOS的新世界。

应用程序生命周期

简述UIApplication##

UIApplication的核心作用是提供了iOS程序运行期间的控制和协作工作。每一个程序在运行期必须有且仅有一个UIApplication(或则其子类)的一个实例。在程序开始运行的时候,UIApplicationMain函数是程序进入点,这个函数做了很多工作,其中一个重要的工作就是创建一个UIApplication单例实例。在你的代码中你,你可以通过调用[UIApplication sharedApplication]来得到这个单例实例的指针。

UIApplication的一个主要工作是处理用户事件,它会起一个队列,把所有用户事件都放入队列,逐个处理,在处理的时候,它会发送当前事件到一个合适的处理事件的目标控件。此外,UIApplication实例还维护一个在本应用中打开的window列表(UIWindow实例),这样它就可以接触应用中的任何一个UIView对象。UIApplication实例会被赋予一个代理对象,以处理应用程序的生命周期事件(比如程序启动和关闭)、系统事件(比如来电、记事项警告)等等。

新建一个任意类型的iOS应用工程,我们可以看到工程中生成一个类:
AppDelegate :UIResponder <UIApplicationDelegate>
这里这个类的基类是UIResponder(注:iOS 4.2以前生成的工程是不同的,以前是继承自NSObject)。不论如何,本类实现了一个名叫UIApplicationDelegate的接口,这个表明这个类就是这个工程中UIApplication实例的代理类。

main函数中,

int main(int argc, char * argv[]) {
  @autoreleasepool {
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
  }
}

这里传入了代理类到UIApplicationMain函数中,UIApplicationMain函数在生成唯一个UIApplication的时候就可以把代理类的实例指针告诉这个单例对象了。

[注]参数说明
argc:系统或者用户传入的参数
argv:系统或用户传入的实际参数
1.根据传入的第三个参数,创建UIApplication对象
2.根据传入的第四个产生创建UIApplication对象的代理
3.设置刚刚创建出来的代理对象为UIApplication的代理
4.开启一个事件循环(可以理解为里面是一个死循环)这个时间循环是一个队列(先进先出)先添加进去的先处理

UIApplication生命周期##

1、
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

说明:当应用程序正常启动时(不包括已在后台转到前台的情况),调用此回调。launchOptions是启动参数,假如用户通过点击push通知启动的应用,(这是非正常启动的情况,包括本地通知和远程通知),这个参数里会存储一些push通知的信息。

2、
- (void)applicationWillResignActive:(UIApplication *)application

说明:当应用程序将要入非活动状态执行,在此期间,应用程序不接收消息或事件,比如来电话了

3、
- (void)applicationDidBecomeActive:(UIApplication *)application

说明:当应用程序入活动状态执行,这个刚好跟上面那个方法相反

4、
- (void)applicationDidEnterBackground:(UIApplication *)application

说明:当程序被推送到后台的时候调用。所以要设置后台继续运行,则在这个函数里面设置即可

5、
- (void)applicationWillEnterForeground:(UIApplication *)application

说明:当程序从后台将要重新回到前台时候调用,这个刚好跟4相反。

6、
- (void)applicationWillTerminate:(UIApplication *)application

说明:当程序将要退出是被调用,通常是用来保存数据和一些退出前的清理工作。这个需要要设置UIApplicationExitsOnSuspend的键值。

7、
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application

说明:iPhone设备只有有限的内存,如果为应用程序分配了太多内存操作系统会终止应用程序的运行,在终止前会执行这个方法,通常可以在这里进行内存清理工作防止程序被终止

8、
- (void)applicationSignificantTimeChange:(UIApplication*)application

说明:当系统时间发生改变时执行

9、
- (void)applicationDidFinishLaunching:(UIApplication*)application

说明:当程序载入后执行

10、
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
说明:当客户端注册远程通知时,会回调的方法。
如果成功,则回调这个方法,客户端把deviceToken取出来发给服务端,push消息的时候要用。
如果失败了,则回调下面的方法,可以从error参数中看一下失败原因。

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error

11、
- (void)application:(UIApplication)application willChangeStatusBarFrame:(CGRect)newStatusBarFrame

说明:当StatusBar框将要变化时执行

- (void)application:(UIApplication*)application willChangeStatusBarOrientation:(UIInterfaceOrientation)newStatusBarOrientationduration:(NSTimeInterval)duration

说明:当StatusBar框方向将要变化时执行

- (void)application:(UIApplication *)application didChangeStatusBarOrientation:(UIInterfaceOrientation)oldStatusBarOrientation

说明:当StatusBar框方向变化完成后执行

- (void)application:(UIApplication*)application didChangeSetStatusBarFrame:(CGRect)oldStatusBarFrame

说明:当StatusBar框变化完成后执行

12、
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url

说明:当通过url执行

13、

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo

说明:当应用在前台运行中,收到远程通知时(不会弹出系统通知界面),会回调这个方法。
当应用在后台状态时,点击push消息启动应用,也会回调这个方法。
当应用完全没有启动时,点击push消息启动应用,就不会回调这个方法。

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo fetchCompletionHandler:(nonnull void (^)(UIBackgroundFetchResult))completionHandler

与上一方法相同,区别是在后台时亦可执行方法,但要开启相关权限。如图。


开启权限
-  (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification

说明:当应用收到本地通知时会调这个方法,同上面一个方法类似。
如果在前台运行状态直接调用
如果在后台状态,点击通知启动时,也会回调这个方法
当应用完全没有启动时,点击push消息启动应用,就不会回调这个方法。

[补充]1.iPhone中的应用程序很容易受到打扰,比如一个来电可能导致应用程序失去焦点,如果这个时候接听了电话,那么应用程序会转到后台运行。还有很多其它类似的事件会导致iPhone应用程序失去焦点,在应用程序失去焦点前会调用委托类的applicationWillResignActive()方法,而应用程序再次获取到焦点的时候会调用applicationDidBecomeActive()方法。比如在运行应用程序的时候锁屏会调用委托类的applicationWillResignActive()方法,而当屏幕被解锁的时候,又会调用applicationDidBecomeActive()方法。

2.另外一个非常重要的方法就是applicationDidReceiveMemoryWarning(),因为iPhone设备只有有限的内存,如果为应用程序分配了太多内存操作系统会终止应用程序的运行,但在终止之前操作系统会通过先调用委托类的applicationDidReceiveMemoryWarning()方法警告应用程序,在UIApplication接收到这个事件后它会传递给委托类的applicationDidReceiveMemoryWarning()方法,委托类在这个方法内可以进行释放内存的操作以防止操作系统强制终止应用程序的运行。

UIApplication部分常用功能##

1.设置icon上的数字图标,缺省为0

[UIApplication sharedApplication].applicationIconBadgeNumber = 1;

2.设置摇动手势的时候,是否支持redo,undo操作,缺省YES

[UIApplication sharedApplication].applicationSupportsShakeToEdit =YES;

3.判断程序运行状态

typedef NS_ENUM(NSInteger, UIApplicationState) {
    UIApplicationStateActive, 
    UIApplicationStateInactive,
    UIApplicationStateBackground
} NS_ENUM_AVAILABLE_IOS(4_0);

if([UIApplicationsharedApplication].applicationState ==UIApplicationStateInactive){
    NSLog(@"程序在运行状态");
 }

4.阻止屏幕变暗进入休眠状态,缺省为no

 [UIApplication sharedApplication].idleTimerDisabled =YES;

[注意⚠️]除视频播放等需要常亮等功能外,慎重使用本功能,因为非常耗电

5.显示联网状态动画

[UIApplication sharedApplication].networkActivityIndicatorVisible =YES;

6.设置状态栏的样式

typedef NS_ENUM(NSInteger, UIStatusBarStyle) {
    UIStatusBarStyleDefault   = 0, // 默认样式,黑字,适用于浅色背景(iOS6及以下系统状态栏为黑底白字)
    UIStatusBarStyleLightContent     NS_ENUM_AVAILABLE_IOS(7_0) = 1, // 白字,适用于深色背景
    UIStatusBarStyleBlackTranslucent NS_ENUM_DEPRECATED_IOS(2_0, 7_0, "Use UIStatusBarStyleLightContent") = 1,// 白字(iOS6及以下系统在启动界面为灰底白字,iOS7及以上系统与UIStatusBarStyleBlackOpaque效果一样)
    UIStatusBarStyleBlackOpaque      NS_ENUM_DEPRECATED_IOS(2_0, 7_0, "Use UIStatusBarStyleLightContent") = 2,// 白字,适用于深色背景(iOS6及以下系统状态栏为黑底白字)
} __TVOS_PROHIBITED;

[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent animated:YES];

隐藏状态栏

[UIApplication sharedApplication].statusBarHidden = YES;

7.调用系统功能
openURL是UIApplication中一个非常强大的方法,使用其可以调用系统相关功能。其方法有

 - (BOOL)openURL:(NSURL*)url ;
 - (BOOL)canOpenURL:(NSURL *)url ;

[注]在iOS10后新增- (void)openURL:(NSURL*)url options:(NSDictionary<NSString *, id> *)options completionHandler:(void (^ __nullable)(BOOL success))completion方法

常用方法有:

(1)发送电子邮件

 NSString *recipients =@"mailto:first@example.com?cc=second@example.com,third@example.com&subject=Hello from California!";
 NSString *body =@"&body=It is raining in sunny California!";
 NSString *email = [NSString  stringWithFormat:@"%@%@", recipients, body];
 email = [email stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[[UIApplication sharedApplication]openURL:[NSURL URLWithString:email]];

(2)打电话

[[UIApplication sharedApplication]openURL:[NSURL URLWithString:@"tel://1234567890"]];

(3)发送短信

[[UIApplication sharedApplication]openURL:[NSURL URLWithString:@"sms://466453"]];

(4)打开一个网址

[[UIApplication sharedApplication]openURL:[NSURL URLWithString:@"http://itunesconnect.apple.com"]];

[补充] 打开网址的操作通常用于跳转app store,iOS给好评时一般会直接打开app store应用详情界面,其实也可以直接跳转到评论页面,更有利于引导用户打分和评论。(将下面id改成自己的app id即可)

[[UIApplication sharedApplication]openURL:[NSURL URLWithString:@"http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?id=id1128294199&pageNumber=0&sortOrdering=2&type=Purple+Software&mt=8"]];

直接跳转到详情

https://itunes.apple.com/cn/app/jia-zhang-mu-ke/id1128294199?mt=8

8.推送相关
注册推送

 [[UIApplication sharedApplication]registerUserNotificationSettings:setting];

移除推送

 [[UIApplication sharedApplication] cancelAllLocalNotifications];

添加推送

 [[UIApplication sharedApplication]  scheduleLocalNotification:notification];

更多内容会陆续补充,欢迎参考指正。

文章参考:
1.UIApplication深入研究-博客园
2.iOS开发UI篇—程序启动原理-博客园

文章优先发表于:http://keyliu.com
转载请注明出处。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,497评论 18 139
  • 写作原因:网上看了很多推送文章都没有完美的解答我的疑惑;主要有以下两点,1:推送来了我点击应用图标进入应用怎么取到...
    Thebloodelves阅读 4,480评论 26 71
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,051评论 25 707
  • 阅读 能营造一种安稳的气氛,对于我这种 喜爱逃避现实的人来说如同氧气一样重要。 中产阶级 的认知中理论的地位高于实...
    卡拉马佐夫阅读 356评论 0 0
  • 《外科风云》终于大结局了,故事结局以皆大欢喜收场。这部剧里触动我的两个角色不是男主庄恕大夫和女主陆晨曦大夫,而是...
    林恩慈Karen阅读 1,109评论 0 3