iOS-UIApplication详解

作者: xx_cc | 来源:发表于2016-07-23 23:16 被阅读7649次

    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对象,这是第一个对象
    1. 创建UIApplication代理对象,并给UIApplicaiton对象设置代理
    2. 开启主运行循环 main events loop处理事件,保持程序一直运行
    3. 加载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{
    
    }
    

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

    相关文章

      网友评论

      • 一抹淡季:棒棒哒,写的挺好的
        一抹淡季:@xx_cc 属于夜猫子型:smile:
        xx_cc:@一抹淡季 谢谢,这么晚了还没睡。
      • cd3e3b7d861f:方案B 不是NO改为YES 是选择NO (已测试)
        xx_cc:@HoweelZhang 恩恩 是我的疏忽写错了 谢谢指正
        cd3e3b7d861f:隐藏 statusBar
      • HoyaWhite:请教 修改Window就能修改程序了吗 自定义代理 在代理里面的运行顺序 作者能指导一下不
        HoyaWhite:@xx_cc 我想把项目A整合进项目B 实现在项目B中点击按钮 实现项目A中的功能 然后我仅仅切换window 实现不了A的功能 A的window和B的window是不一样的window 我不知道底层做了一些事情是我漏掉了 或者是我哪里少了什么东西
        xx_cc:@WhitePlimsolls 额,我不是太理解你的问题,你能详细说一下么
      • 自律者得自由:比较基础详细了,谢谢分享
        xx_cc:@一叶障目不见林 谢谢你的喜欢,共勉
      • Jabber_YQ:学到了,谢谢
        xx_cc:@Jabber_YQ 谢谢你的喜欢 一起努力

      本文标题:iOS-UIApplication详解

      本文链接:https://www.haomeiwen.com/subject/qjewjttx.html