1. 程式人生 > >iOS-UIApplication詳解

iOS-UIApplication詳解

對象 orien ica oar span nali messages @property pen

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:[email protected]"]];
    打開一個網頁資源 [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
鏈接:http://www.jianshu.com/p/f0a2117406d8
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請註明出處。

iOS-UIApplication詳解