iOS-UIApplication详解iOS-UIApplication详解

iOS-UIApplication详解

✨建议收藏,用到时候一查就明白了 xx_cc

UIApplication简介

  1. UIApplication对象是应用程序的象征。
  2. 每一个应用程序都有自己的UIApplication对象,而且是单例。
  3. 一个iOS程序启动后创建的第一个对象就是UIApplication对象。
  4. 通过UIApplication *app = [UIApplication sharedApplication];可以获得这个单例对象。
  5. 利用UIApplication对象能进行一些应用级别的操作。

UIApplication单例实现原理

首先我们知道UIApplication对象是单例创建的,也就是说程序中UIApplication对象只创建一次,我们不能再新建UIApplicaiton对象。 那么当我们尝试新建一个UIApplicaiton对象时, UIApplication *app = [[UIApplication alloc]init]; 程序会报错,我们来看一下错误信息

'NSInternalInconsistencyException', reason: 'There can only be one UIApplication instance.'

这里我们发现系统的做法是抛出一个异常,告诉我们UIApplicaiton对象只能有一个。 这时我们基本可以理清,苹果内部如何实现UIApplication单例。

1.不能外界调用alloc,一调用就崩掉,抛出异常,(第一次调用alloc就不崩溃,其他都崩溃) 2.提供一个方法给外界获取单例(shareApplication) 3.程序启动的时候内部创建一次单例

下面我们来模仿一下系统单例的实现 创建Person类 Person.h

#import <Foundation/Foundation.h>

@interface Person : NSObject
//注:一般我们写单例的时候,也用shared开头,这是命名规范
+(instancetype)sharePerson;

@end

Person.m

#import "Person.h"

@implementation Person
//静态变量
static Person *_person = nil;
//类加载:每次程序一启动就会把所有类加载进内存
+(void)load
{
    _person = [[Person alloc]init];
}

+(instancetype)sharePerson
{
    return _person;
}

+(instancetype)alloc
{
    if (_person) {
        // _person有值标示已经分配好了,就不允许外界在分配内存
        // 抛异常,告诉外界不允许分配
     
        // 创建异常类
        // name:异常的名称
        // reson:异常的原因
        // userInfo:异常的信息
        NSException *excp = [NSException exceptionWithName:@"NSInternalInconsistencyException" reason:@"There can only be one Person instance." userInfo:nil];
        
        // 抛异常
        [excp raise]; 
    }
    return [super alloc];
}
@end

此时单例Person类就实现了,当我们alloc Person实例化对象的时候就会抛出异常。

一个iOS程序启动后创建的第一个对象就是UIApplication对象

那么UIApplication对象是什么时候被创建的呢?这时我们找到程序的入口main.m

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

我们发现程序一开始返回了UIApplicationMain方法,并且还有4个参数 我们来看一下这些参数的介绍 argc

The count of arguments in argv; this usually is the corresponding parameter to main.

argv

A variable list of arguments; this usually is the corresponding parameter to main.

principalClassName

The name of the UIApplication class or subclass. If you specify nil, UIApplication is assumed.

delegateClassName

The name of the class from which the application delegate is instantiated. If principalClassName designates a subclass of UIApplication, you may designate the subclass as the delegate; the subclass instance receives the application-delegate messages. Specify nil if you load the delegate object from your application’s main nib file.

argc:系统或者用户传入的参数 argv:系统或用户传入的实际参数

重点放在第三、四个参数

第三个参数 nil:代表UIApplication类名或者子类名称,nil 相当于 @"UIApplicaiton"; 第四个参数 :代表UIApplicaiton的代理名称 NSStringFromClass([AppDelegate class] 相当于 @"AppDelegate";

此时我们可以根据UIApplicationMain函数了解程序启动的过程

  1. 根据传递的类名创建UIApplication对象,这是第一个对象
  2. 创建UIApplication代理对象,并给UIApplicaiton对象设置代理
  3. 开启主运行循环 main events loop处理事件,保持程序一直运行
  4. 加载info.plist,判断是否指定mian(xib 或者 storyboard)如果指定就去加载

利用UIApplication对象能进行一些应用级别的操作。

  • 设置应用程序图标右上角的红色提醒数字 @property(nonatomic) NSInteger applicationIconBadgeNumber; 代码实现和效果:
UIApplication *app = [UIApplication sharedApplication];
app.applicationIconBadgeNumber = 10;
// 创建通知对象
UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge categories:nil];
// 注册用户通知
[app registerUserNotificationSettings:setting];

注:苹果为了增强用户体验,在iOS8以后我们需要创建通知才能实现图标右上角提醒,iOS8之前直接设置applicationIconBadgeNumber的值即可。

提醒效果图

  • 设置联网指示器的可见性 @property(nonatomic,getter=isNetworkActivityIndicatorVisible) BOOL networkActivityIndicatorVisible; 代码实现和效果:
app.networkActivityIndicatorVisible= YES;

联网指示器显示效果图

  • 管理状态栏 从iOS7开始,系统提供了2种管理状态栏的方式 a.通过UIViewController管理(每一个UIViewController都可以拥有自己不同的状态栏)在iOS7中,默认情况下,状态栏都是由UIViewController管理的,UIViewController实现下列方法就可以轻松管理状态栏的可见性和样式 状态栏的样式   - (UIStatusBarStyle)preferredStatusBarStyle; 状态栏的可见性  -(BOOL)prefersStatusBarHidden;
#pragma mark-设置状态栏的样式
-(UIStatusBarStyle)preferredStatusBarStyle
{
    //设置为白色
    //return UIStatusBarStyleLightContent;
    //默认为黑色
     return UIStatusBarStyleDefault;
}
#pragma mark-设置状态栏是否隐藏(否)
-(BOOL)prefersStatusBarHidden
{
    return NO;
}

b.通过UIApplication管理(一个应用程序的状态栏都由它统一管理)如果想利用UIApplication来管理状态栏,首先得修改Info.plist的设置,添加选中行,并设置为NO即可,这篇文章中有详细介绍iOS中用application 来管理电池栏状态

Info.plist的设置

代码:

//通过sharedApplication获取该程序的UIApplication对象
UIApplication *app=[UIApplication sharedApplication];
//设置状态栏的样式
//app.statusBarStyle=UIStatusBarStyleDefault;//默认(黑色)
//设置为白色+动画效果
[app setStatusBarStyle:UIStatusBarStyleLightContent animated:YES];
//设置状态栏是否隐藏
app.statusBarHidden=YES;
//设置状态栏是否隐藏+动画效果
[app setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade];

c.总结

如果状态栏的样式只设置一次,那就用UIApplication来进行管理,并且UIApplication可以提供动画效果; 如果状态栏是否隐藏,样式不一那就用每个控制器对自己的状态栏进行管理。

  • openURL:方法 UIApplication有个功能十分强大的openURL:方法 - (BOOL)openURL:(NSURL*)url; openURL:方法的部分功能有
UIApplication *app = [UIApplicationsharedApplication];
打电话  [app openURL:[NSURLURLWithString:@"tel://110"]];
发短信  [app openURL:[NSURLURLWithString:@"sms://10086"]];
发邮件  [app openURL:[NSURLURLWithString:@"mailto://xxcc@fox.com"]];
打开一个网页资源 [app openURL:[NSURL URLWithString:@"http://www.baidu.com"]];
打开其他app程序   openURL方法,可以打开其他APP。

系统内部根据不同的头标示来做出不同的相应。

  • 判断程序运行状态
    //判断程序运行状态
    /*
     UIApplicationStateActive, 
     UIApplicationStateInactive, 
     UIApplicationStateBackground
     */
 UIApplication *app = [UIApplication sharedApplication];
 if(app.applicationState ==UIApplicationStateInactive){
        NSLog(@"程序在运行状态");
    }
  • 阻止屏幕变暗进入休眠状态
    //阻止屏幕变暗,慎重使用本功能,因为非常耗电。
   UIApplication *app = [UIApplication sharedApplication];
   app.idleTimerDisabled =YES;

UIApplication Delegate

当app收到干扰,例如程序运行中来电等,就会产生一些系统事件,这时UIApplicaiton会通知它的代理delegate对象,让delegate代理来处理这些系统事件。 delegate可以处理的时间包括

1.应用程序的生命周期事件(如程序启动和关闭) 2.系统事件(如来电) 3.内存警告(用处较多)

每当我们创建项目时,程序中的AppDelegate文件就是UIAppliacation的代理,我们可以发现它已经遵守了UIApplicationDelegate。

@interface AppDelegate : UIResponder <UIApplicationDelegate> 下面我们来看一下AppDelegate的方法

// AppDelegate:监听应用程序的生命周期
// 以下方法就是应用程序的生命周期方法

// 应用程序启动完成的时候就会调用AppDelegate的方法
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    NSLog(@"%s",__func__);
    return YES;
}
// 当应用程序失去焦点的时候调用
- (void)applicationWillResignActive:(UIApplication *)application {
     NSLog(@"%s",__func__);
}
// 当应用程序进入后台的时候调用
- (void)applicationDidEnterBackground:(UIApplication *)application {
     NSLog(@"%s",__func__);
    // 保存一些信息
}
// 当应用程序进入前台的时候调用
- (void)applicationWillEnterForeground:(UIApplication *)application {
    NSLog(@"%s",__func__);
}
// 当应用程序完全获取焦点的时候调用
// 只有当应用程序完全获取焦点的时候,才能够与用户交互
- (void)applicationDidBecomeActive:(UIApplication *)application {
     NSLog(@"%s",__func__);
}
// 当应用程序关闭的时候
- (void)applicationWillTerminate:(UIApplication *)application {
    
}
//收到内存警告时调用
-(void)applicationDidReceiveMemoryWarning:(UIApplication *)application{

}

本文借鉴了很多前辈的文章,如果有不对的地方请指正,欢迎大家一起交流学习

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏非典型技术宅

iOS四大对象之UIWindow及四大对象之间的关系1. UIWindow/使用纯代码加载根控制器2. UIWindow的创建过程3. 四大对象之间的关系

17830
来自专栏Scott_Mr 个人专栏

两个App之间调起通信

39480
来自专栏進无尽的文章

实践-小细节 III

Title:nil message:nil 标题和信息都设为 nil 不能设置为 @“” 这样还是会出现空白的标题

10520
来自专栏谈补锅

UIApplication

1、UIApplication对象是应用程序的象征,每一个应用都有自己的UIApplication对象,而且是单列的

14130
来自专栏iOS开发攻城狮的集散地

Url Scheme实现APP间通信、分享

23550
来自专栏iOS开发攻城狮的集散地

Url Scheme实现APP间通信、分享

接下来就以我之前写的UIActivityViewController系统原生分享-仿简书分享和iOS开源小项目-WSL两个Demo为例,让我们看下怎么可以让UI...

28980
来自专栏Guangdong Qi

iOS 9 UIWebView不能加载百度和控制电池条字体颜色

今天写了一个UIWebView给H5的妹子测试,本来很简单的东西,不应该出错的,但是还是有错,而且还是两个

10120
来自专栏非典型技术宅

iOS四大对象之AppDelegate及UIApplicationMain函数/程序启动过程1. AppDelegate应用程序代理2. UIApplicationMain函数/程序启动过程

16750
来自专栏哈雷彗星撞地球

SDWebImageV3.7.5源码解析

SDWebImage更新到如今这个版本,过程做了许多改进,性能已经非常的好了。以前就粗略的看过SDWebImage的源码,但是未做记录整理。再次阅读还是受益良多...

10530
来自专栏哈雷彗星撞地球

(译)openURL 在 iOS10中已弃用

翻译自:openURL Deprecated in iOS10 译者:Haley_Wong

14210

扫码关注云+社区

领取腾讯云代金券