iOS面試總結

我是一只勤勞的小蜜蜂。閑暇之余,總結下一直以來自己面試過程中所遇到的一些高概率問題,分享給大家,共同成長。該貼后續將會持續更新~~

1.BAD_ACCESS在什么情況下出現?

①訪問一個僵尸對象,訪問僵尸對象的成員變量或者向其發消息;②死循環。

2.簡述下Objective-C中調用方法的過程(runtime)

Objective-C是動態語言,每個方法在運行時會被動態轉為消息發送,即:objc_msgSend(receiver, selector),整個過程介紹如下:
①objc在向一個對象發送消息時,runtime庫會根據對象的isa指針找到該對象實際所屬的類
②然后在該類中的方法列表以及其父類方法列表中尋找方法運行
③如果,在最頂層的父類(一般也就NSObject)中依然找不到相應的方法時,程序在運行時會掛掉并拋出異常unrecognized selector sent to XXX
④但是在這之前,objc的運行時會給出三次拯救程序崩潰的機會,這三次拯救程序奔潰的說明見問題《什么時候會報unrecognized selector的異常》中的說明
? 補充說明:Runtime 鑄就了Objective-C 是動態語言的特性,使得C語言具備了面向對象的特性,在程序運行期創建,檢查,修改類、對象及其對應的方法,這些操作都可以使用runtime中的對應方法實現。

3.什么是method swizzling(俗稱黑魔法)

簡單說就是進行方法交換。
①在Objective-C中調用一個方法,其實是向一個對象發送消息,查找消息的唯一依據是selector的名字。利用Objective-C的動態特性,可以實現在運行時偷換selector對應的方法實現,達到給方法掛鉤的目的
②每個類都有一個方法列表,存放著方法的名字和方法實現的映射關系,selector的本質其實就是方法名,IMP有點類似函數指針,指向具體的Method實現,通過selector就
![Uploading 4a6c4741-9186-4ba2-b354-cde08612df6c_550019.png . . .]可以找到對應的IMP

  • 交換方法的幾種實現方式
    • 利用 method_exchangeImplementations 交換兩個方法的實現
    • 利用 class_replaceMethod 替換方法的實現
    • 利用 method_setImplementation 來直接設置某個方法的IMP


      示意圖.png
4.objc中向一個nil對象發送消息將會發生什么?

在Objective-C中向nil發送消息是完全有效的——只是在運行時不會有任何作用
①如果一個方法返回值是一個對象,那么發送給nil的消息將返回0(nil);
② 如果方法返回值為指針類型,其指針大小為小于或者等于sizeof(void*);
③ float,double,long double 或者long long的整型標量,發送給nil的消息將返回0;
④ 如果方法返回值為結構體,發送給nil的消息將返回0。結構體中各個字段的值將都是0;
⑤ 如果方法的返回值不是上述提到的幾種情況,那么發送給nil的消息的返回值將是未定義的。
? 具體原因分析
①objc是動態語言,每個方法在運行時會被動態轉為消息發送,即:objc_msgSend(receiver, selector);
② 為了方便理解這個內容,還是貼一個objc的源代碼:

struct objc_class

{

    // isa指針指向Meta Class,因為Objc的類的本身也是一個Object,

    // 為了處理這個關系,runtime就創造了Meta Class,

    // 當給類發送[NSObject alloc]這樣消息時,實際上是把這個消息發給了Class Object

    Class isa OBJC_ISA_AVAILABILITY;

#if !__OBJC2__

    Class super_class OBJC2_UNAVAILABLE; // 父類

    const char *name OBJC2_UNAVAILABLE; // 類名

    long version OBJC2_UNAVAILABLE; // 類的版本信息,默認為0

    long info OBJC2_UNAVAILABLE; // 類信息,供運行期使用的一些位標識

    long instance_size OBJC2_UNAVAILABLE; // 該類的實例變量大小

    struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 該類的成員變量鏈表

    struct objc_method_list **methodLists OBJC2_UNAVAILABLE; // 方法定義的鏈表

    // 方法緩存,對象接到一個消息會根據isa指針查找消息對象,

    // 這時會在method Lists中遍歷,

    // 如果cache了,常用的方法調用時就能夠提高調用的效率。

    // 這個方法緩存只存在一份,不是每個類的實例對象都有一個方法緩存

    // 子類會在自己的方法緩存中緩存父類的方法,父類在自己的方法緩存中也會緩存自己的方法,而不是說子類就不緩存父類方法了

    struct objc_cache *cache OBJC2_UNAVAILABLE;

    struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 協議鏈表

#endif

} OBJC2_UNAVAILABLE;

分析:
①objc在向一個對象發送消息時,runtime庫會根據對象的isa指針找到該對象實際所屬的類,然后在該類中的方法列表以及其父類方法列表中尋找方法運行,然后再發送消息的時候,objc_msgSend方法不會返回值,所謂的返回內容都是具體調用時執行的。
② 如果向一個nil對象發送消息,首先在尋找對象的isa指針時就是0地址返回了,所以不會出現任何錯誤。

5.objc中向一個對象發送消息[obj foo]和objc_msgSend()函數之間有什么關系?

[obj foo];在objc動態編譯時,會被轉意為:
objc_msgSend(obj, @selector(foo));

6.什么時候會報unrecognized selector的異常?

當調用該對象上某個方法,而該對象上沒有實現這個方法的時候, 可以通過“消息轉發”進行解決,如果還是不行就會報unrecognized selector異常。objc是動態語言,每個方法在運行時會被動態轉為消息發送,即:objc_msgSend(receiver, selector),整個過程介紹如下:
①objc在向一個對象發送消息時,runtime庫會根據對象的isa指針找到該對象實際所屬的類;
②然后在該類中的方法列表以及其父類方法列表中尋找方法運行
③如果,在最頂層的父類中依然找不到相應的方法時,程序在運行時會掛掉并拋出異常unrecognized selector sent to XXX 。但是在這之前,objc的運行時會給出三次拯救程序崩潰的機會:

○ Method resolution

§ objc運行時會調用+resolveInstanceMethod:或者 +resolveClassMethod:,讓你有機會提供一個函數實現。

§ 如果你添加了函數并返回 YES,那運行時系統就會重新啟動一次消息發送的過程

§ 如果 resolve 方法返回 NO ,運行時就會移到下一步,消息轉發

○ Fast forwarding

§ 如果目標對象實現了-forwardingTargetForSelector:,Runtime 這時就會調用這個方法,給你把這個消息轉發給其他對象的機會

§ 只要這個方法返回的不是nil和self,整個消息發送的過程就會被重啟,當然發送的對象會變成你返回的那個對象。

§ 否則,就會繼續Normal Fowarding。

§ 這里叫Fast,只是為了區別下一步的轉發機制。因為這一步不會創建任何新的對象,但Normal forwarding轉發會創建一個NSInvocation對象,相對Normal forwarding轉發更快點,所以這里叫Fast forwarding

○ Normal forwarding

§ 這一步是Runtime最后一次給你挽救的機會。

§ 首先它會發送-methodSignatureForSelector:消息獲得函數的參數和返回值類型。

§ 如果-methodSignatureForSelector:返回nil,Runtime則會發出-doesNotRecognizeSelector:消息,程序這時也就掛掉了。

§ 如果返回了一個函數簽名,Runtime就會創建一個NSInvocation對象并發送-forwardInvocation:消息給目標對象
7.HTTP協議中POST方法和GET方法有那些區別?

①GET用于向服務器請求數據,POST用于提交數據;
②GET請求,請求參數拼接形式暴露在地址欄,而POST請求參數則放在請求體里面,因此GET請求不適合用于驗證密碼等操作;
③GET請求的URL有長度限制,POST請求不會有長度限制。

8.猜想runloop內部是如何實現的?

從字面意思看:運行循環、跑圈;
本質:內部就是do-while循環,在這個循環內部不斷地處理各種事件(任務),比如:Source、Timer、Observer;
? 每條線程都有唯一一個RunLoop對象與之對應,主線程的RunLoop默認已經啟動,子線程的RunLoop需要手動啟動;
? 每次RunLoop啟動時,只能指定其中一個 Mode,這個Mode被稱作 CurrentMode,如果需要切換Mode,只能退出Loop,再重新指定一個Mode進入,這樣做主要是為了隔離不同Mode中的Source、Timer、Observer,讓其互不影響;

9.蘋果是如何實現autoreleasepool的?

autoreleasepool以一個隊列數組的形式實現,主要通過下列三個函數完成。
objc_autoreleasepoolPush
objc_autoreleasepoolPop
objc_aurorelease

10.這個寫法會出什么問題: @property (copy) NSMutableArray *array;

因為copy策略拷貝出來的是一個不可變對象,然而卻把它當成可變對象使用,很容易造成程序奔潰。
這里還有一個問題,該屬性使用了同步鎖,會在創建時生成一些額外的代碼用于幫助編寫多線程程序,這會帶來性能問題,通過聲明nonatomic可以節省這些雖然很小但是不必要額外開銷,在iOS開發中應該使用nonatomic替代atomic。

11.如何讓自定義類可以用 copy 修飾符?如何重寫帶 copy 關鍵字的 setter?

若想令自己所寫的對象具有拷貝功能,則需實現NSCopying協議。如果自定義的對象分為可變版本與不可變版本,那么就要同時實現NSCopyiog與NSMutableCopying協議,不過一般沒什么必要,實現NSCopying協議就夠了

 實現不可變版本拷貝

- (id)copyWithZone:(NSZone *)zone;

 實現可變版本拷貝

- (id)mutableCopyWithZone:(NSZone *)zone;

 重寫帶 copy 關鍵字的setter

- (void)setName:(NSString *)name

{

_name = [name copy];

}
12.+(void)load; +(void)initialize;有什么用處?
 +(void)load;```

① 當類對象被引入項目時, runtime會向每一個類對象發送 load 消息;
②load 方法會在每一個類甚至分類被引入時僅調用一次,調用的順序:父類優先于子類, 子類優先于分類;
③由于load 方法會在類被import 時調用一次,而這時往往是改變類的行為的最佳時機,在這里可以使用例如method swizlling 來修改原有的方法;
④load 方法不會被類自動繼承。

+(void)initialize;```
也是在第一次使用這個類的時候會調用這個方法,也就是說 initialize也是懶加載。
? 總結:
① 在Objective-C中,runtime會自動調用每個類的這兩個方法;
② +load會在類初始加載時調用;
③+initialize會在第一次調用類的類方法或實例方法之前被調用;
④這兩個方法是可選的,且只有在實現了它們時才會被調用;
⑤兩者的共同點:兩個方法都只會被調用一次。

13.如何關閉默認的KVO的默認實現,KVO的實現原理?

所謂的“手動觸發”是區別于“自動觸發”:
自動觸發是指類似這種場景:在注冊 KVO 之前設置一個初始值,注冊之后,設置一個不一樣的值,就可以觸發了。

想知道如何手動觸發,必須知道自動觸發 KVO 的原理:
鍵值觀察通知依賴于 NSObject 的兩個方法: willChangeValueForKey: 和 didChangevlueForKey: 。在一個被觀察屬性發生改變之前, willChangeValueForKey: 一定會被調用,這就 會記錄舊的值。而當改變發生后, didChangeValueForKey: 會被調用,繼而 observeValueForKey:ofObject:change:context: 也會被調用。如果可以手動實現這些調用,就可以實現“手動觸發”了。

當你觀察一個對象時,一個新的類會被動態創建。這個類繼承自該對象的原本的類,并重寫了被觀察屬性的 setter 方法。重寫的 setter 方法會負責在調用原 setter 方法之前和之后,通知所有觀察對象:值的更改。最后通過 isa 混寫(isa-swizzling) 把這個對象的 isa 指針 ( isa 指針告訴 Runtime 系統這個對象的類是什么 ) 指向這個新創建的子類,對象就神奇的變成了新創建的子類的實例。如下所示:

示意圖.png
14.若一個類有實例變量NSString *_foo,調用setValue:forKey:時,是以foo還是_foo作為key?

? 都可以

15.KVC和KVO的keyPath一定是屬性么?

? 可以是成員變量

16.直接調用_objc_msgForward函數將會發生什么?

_objc_msgForward是 IMP 類型,用于消息轉發的:當向一個對象發送一條消息,但它并沒有實現的時候,_objc_msgForward會嘗試做消息轉發。

直接調用_objc_msgForward是非常危險的事,如果用不好會直接導致程序Crash,但是如果用得好,能做很多非常酷的事。

一旦調用_objc_msgForward,將跳過查找 IMP 的過程,直接觸發“消息轉發”,如果調用了_objc_msgForward,即使這個對象確實已經實現了這個方法,你也會告訴objc_msgSend:“我沒有在這個對象里找到這個方法的實現”。

17.斷點續傳如何實現的?

斷點續傳的理解可以分為兩部分:一部分是斷點,一部分是續傳。斷點的由來是在下載過程中,將一個下載文件分成了多個部分,同時進行多個部分一起的下載,當 某個時間點,任務被暫停了,此時下載暫停的位置就是斷點了。續傳就是當一個未完成的下載任務再次開始時,會從上次的斷點繼續傳送。

使用多線程斷點續傳下載的時候,將下載或上傳任務(一個文件或一個壓縮包)人為的劃分為幾個部分,每一個部分采用一個線程進行上傳或下載,多個線程并發可以占用服務器端更多資源,從而加快下載速度。

在下載(或上傳)過程中,如果網絡故障、電量不足等原因導致下載中斷,這就需要使用到斷點續傳功能。下次啟動時,可以從記錄位置(已經下載的部分)開始,繼續下載以后未下載的部分,避免重復部分的下載。斷點續傳實質就是能記錄上一次已下載完成的位置。

斷點續傳的過程:
①斷點續傳需要在下載過程中記錄每條線程的下載進度;
②每次下載開始之前先讀取數據庫,查詢是否有未完成的記錄,有就繼續下載,沒有則創建新記錄插入數據庫;
③在每次向文件中寫入數據之后,在數據庫中更新下載進度;
④下載完成之后刪除數據庫中下載記錄。

18.當 TableView 的 Cell 改變時,如何讓這些改變以動畫的形式呈現?
@interface ViewController ()

@property (nonatomic, strong) NSIndexPath *index;

@end

@implementation ViewController

static NSString *ID = @"cell";

- (void)viewDidLoad {

   [super viewDidLoad];

}
 
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];

    cell.textLabel.text = [NSString stringWithFormat:@"%ld",(long)indexPath.row];

    return cell;

}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

{

    return 10;

}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

{
  
    if(self.index == indexPath){

        return 120;

    }

    return 60;

}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

{

    self.index = indexPath;

    [tableView deselectRowAtIndexPath:indexPath animated:TRUE];

    //重點是這2句代碼實現的功能

    [tableView beginUpdates];

    [tableView endUpdates];

}
19.如何把一個包含自定義對象的數組序列化到磁盤?
//自定義對象只需要實現NSCoding協議即可

- (void)viewDidLoad

{

    [super viewDidLoad];

   User *user = [User new];

    Account *account = [Account new];

    NSArray *userArray = @[user, account];

   // 存到磁盤

    NSData * tempArchive = [NSKeyedArchiver archivedDataWithRootObject: userArray];

}

 //代理方法

- (instancetype)initWithCoder:(NSCoder *)coder

{

    self = [super initWithCoder:coder];

    if (self) {

        self.user = [aDecoder decodeObjectForKey:@"user"];

        self.account = [aDecoder decodeObjectForKey:@"account"];

    }

    return self;

}

// 代理方法

-(void)encodeWithCoder:(NSCoder *)aCoder{

    [aCoder encodeObject:self.user forKey:@"user"];

    [aCoder encodeObject:self.account forKey:@"account"];

}
20.內存管理的幾條原則時什么?按照默認法則.那些關鍵字生成的對象需要手動釋放?在和property結合的時候怎樣有效的避免內存泄露?

①誰申請,誰釋放;
②遵循Cocoa Touch的使用原則;
③內存管理主要要避免“過早釋放”和“內存泄漏”,對于“過早釋放”需要注意@property設置特性時,一定要用對特性關鍵字,對于“內存泄漏”,一定要申請了要負責釋放,要細心。
④關鍵字alloc 或new 生成的對象需要手動釋放;
⑤設置正確的property屬性,對于retain需要在合適的地方釋放。

21.Object C中創建線程的方法是什么?如果在主線程中執行代碼,方法是什么?如果想延時執行代碼、方法又是什么?

線程創建有三種方法:使用NSThread創建、使用GCD的dispatch、使用子類化的NSOperation,然后將其加入NSOperationQueue;在主線程執行代碼,方法是performSelectorOnMainThread,如果想延時執行代碼可以用performSelector:onThread:withObject:waitUntilDone:

22.IBOutlet連出來的視圖屬性為什么可以被設置成weak?

因為父控件的subViews數組已經對它有一個強引用。

23.XIB中User Defined Runtime Attributes如何使用?

①User Defined Runtime Attributes是一個不被看重但功能非常強大的的特性,它能夠通過KVC的方式配置一些你在interface builder中不能配置的屬性。
② 當你希望在IB中作盡可能多得事情,這個特性能夠幫助你編寫更加輕量級的viewcontroller。

24.請簡述UITableView的復用機制。

①每次創建cell的時候通過dequeueReusableCellWithIdentifier:方法創建cell,它先到緩存池中找指定標識的cell,如果沒有就直接返回nil。
②如果沒有找到指定標識的cell,那么會通過initWithStyle:reuseIdentifier:創建一個cell。
③ 當cell離開界面就會被放到緩存池中,以供下次復用

25.如何高性能的給UIImageView 加個圓角?

? 不好的解決方案
○ 使用下面的方式會強制Core Animation提前渲染屏幕的離屏繪制, 而離屏繪制就會給性能帶來負面影響,會有卡頓的現象出現 。

self.view.layer.cornerRadius = 5;

self.view.layer.masksToBounds = YES;

? 正確的解決方案:使用繪圖技術。

- (UIImage *)circleImage

{

    NO代表透明

    UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0);

    獲得上下文

    CGContextRef ctx = UIGraphicsGetCurrentContext();

    添加一個圓

    CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);

    CGContextAddEllipseInRect(ctx, rect);

    裁剪

    CGContextClip(ctx);

    將圖片畫上去

    [self drawInRect:rect];

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

    關閉上下文

    UIGraphicsEndImageContext();

    return image;

}

? 還有一種方案:使用了貝塞爾曲線"切割"個這個圖片, 給UIImageView 添加了的圓角,其實也是通過繪圖技術來實現的

 

UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];

imageView.center = CGPointMake(200, 300);

UIImage *anotherImage = [UIImage imageNamed:@"image"];

UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 1.0);

[[UIBezierPath bezierPathWithRoundedRect:imageView.bounds

                            cornerRadius:50] addClip];

[anotherImage drawInRect:imageView.bounds];

imageView.image = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

[self.view addSubview:imageView];
26.使用drawRect有什么影響?

? drawRect方法依賴Core Graphics框架來進行自定義的繪制

? 缺點:它處理touch事件時每次按鈕被點擊后,都會用setNeddsDisplay進行強制重繪;而且不止一次,每次單點事件觸發兩次執行。這樣的話從性能的角度來說,對CPU和內存來說都是欠佳的。特別是如果在我們的界面上有多個這樣的UIButton實例,那就會很糟糕了

? 這個方法的調用機制也是非常特別. 當你調用 setNeedsDisplay 方法時, UIKit 將會把當前圖層標記為dirty,但還是會顯示原來的內容,直到下一次的視圖渲染周期,才會將標記為 dirty 的圖層重新建立Core Graphics上下文,然后將內存中的數據恢復出來, 再使用 CGContextRef 進行繪制。

27.如何渲染UILabel的文字?

通過NSAttributedString/NSMutableAttributedString(富文本)

28.控制器的生命周期

? 就是問的view的生命周期,下面已經按方法執行順序進行了排序

自定義控制器view,這個方法只有實現了才會執行

- (void)loadView

{

    self.view = [[UIView alloc] init];

    self.view.backgroundColor = [UIColor orangeColor];

}
view是懶加載,只要view加載完畢就調用這個方法

- (void)viewDidLoad

{

    [super viewDidLoad];

    NSLog(@"%s",__func__);

}

view即將顯示

- (void)viewWillAppear:(BOOL)animated

{

    [super viewWillAppear:animated];

    NSLog(@"%s",__func__);

}

view即將開始布局子控件

- (void)viewWillLayoutSubviews

{

    [super viewWillLayoutSubviews];

    NSLog(@"%s",__func__);

}

view已經完成子控件的布局

- (void)viewDidLayoutSubviews

{

    [super viewDidLayoutSubviews];

    NSLog(@"%s",__func__);

}

view已經出現

- (void)viewDidAppear:(BOOL)animated

{

    [super viewDidAppear:animated];

    NSLog(@"%s",__func__);

}

view即將消失

- (void)viewWillDisappear:(BOOL)animated

{

    [super viewWillDisappear:animated];

    NSLog(@"%s",__func__);

}

view已經消失

- (void)viewDidDisappear:(BOOL)animated

{

    [super viewDidDisappear:animated];

    NSLog(@"%s",__func__);

}

收到內存警告

- (void)didReceiveMemoryWarning

{

    [super didReceiveMemoryWarning];

    NSLog(@"%s",__func__);

}

方法已過期,即將銷毀view

- (void)viewWillUnload

{

}

方法已過期,已經銷毀view

- (void)viewDidUnload

{

}
29.iOS本地數據存儲都有幾種方式?

①.NSkeyedArchiver:采用歸檔的形式來保存數據,該數據對象需要遵守NSCoding協議,并且該對象對應的類必須提供encodeWithCoder:和initWithCoder:方法.前一個方法告訴系統怎么對對象進行編碼,而后一個方法則是告訴系統怎么對對象進行解碼。
②.NSUserDefaults:用來保存應用程序設置和屬性,用戶保存的數據.用戶再次打開程序或者開機后這些數據仍然存在.NSUserDefaults可以存儲的數據類型包括:NSData,NSString,NSNumber,NSDate,NSArray.NSDictionary,其他類型的數據需要先行轉換。
③.Write寫入方式:永久保存在磁盤中.具體:a.獲得文件保存的路徑.b.生成該路徑下的文件,c,往文件中寫入數據.d.從文件中讀出數據。
④.SQLite:采用SQLite數據庫來存儲數據,SQLite作為一種輕量級數據庫.具體:a.添加SQLite相關的庫以及頭文件,b.使用數據庫存數數據:打開數據庫,編寫數據庫語句,執行,關閉數據庫.另:寫入數據庫,字符串可以采用char方式,而從數據庫中取出char類型,當char類型有表示中文字符時,會出現亂碼,這是因為數據庫默認使用ascII編碼方式,所以想要正確從數據庫中取出中文,需要使用NSString來接受從數據庫取出的字符串。
⑤.CoreData:原理是對SQLite的封裝,開發者不需要接觸sql語句,就可以對數據庫進行操作。

30.簡述應用程序按HOME鍵進入后臺時的生命周期,以及從后臺進入前臺時的生命周期.
//前者:
- (void)applicationWillResignActive:(UIApplication *)application
- (void)applicationDidEnterBackground:(UIApplication *)application

//后者:
- (void)applicationWillEnterForeground:(UIApplication *)application
- (void)applicationDidBecomeActive:(UIApplication *)application

補充各個程序運行狀態時代理的回調:
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions
//告訴代理進程啟動但還沒進入狀態保存
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
//告訴代理啟動基本完成程序準備開始運行
- (void)applicationWillResignActive:(UIApplication *)application
//當應用程序將要入非活動狀態執行,在此期間,應用程序不接收消息或事件,比如來電話了
- (void)applicationDidBecomeActive:(UIApplication *)application
//當應用程序入活動狀態執行,這個剛好跟上面那個方法相反
- (void)applicationDidEnterBackground:(UIApplication *)application
//當程序被推送到后臺的時候調用。所以要設置后臺繼續運行,則在這個函數里面設置即可
- (void)applicationWillEnterForeground:(UIApplication *)application
//當程序從后臺將要重新回到前臺時候調用,這個剛好跟上面的那個方法相反。
- (void)applicationWillTerminate:(UIApplication *)application
//當程序將要退出是被調用,通常是用來保存數據和一些退出前的清理工作。這個需要要設置UIApplicationExitsOnSuspend的鍵值。
- (void)applicationDidFinishLaunching:(UIApplication*)application
//當程序載入后執行
在上面8個方法對應的方法中鍵入NSLog打印。

現在啟動程序看看執行的順序:
//啟動程序
lifeCycle[40428:11303] willFinishLaunchingWithOptions
lifeCycle[40428:11303] didFinishLaunchingWithOptions
lifeCycle[40428:11303] applicationDidBecomeActive
//按下home鍵
lifeCycle[40428:11303] applicationWillResignActive
lifeCycle[40428:11303] applicationDidEnterBackground
//雙擊home鍵,再打開程序
lifeCycle[40428:11303] applicationWillEnterForeground
lifeCycle[40428:11303] applicationDidBecomeActive
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 被面試問的問題, 和網上找到的我覺得不錯的問題 會保持更新 -- 因都寫在一起了, 所以可能會穿插添加. 請諒解 ...
    DSperson閱讀 442評論 0 2
  • 這篇文章完全是基于南峰子老師博客的轉載 這篇文章完全是基于南峰子老師博客的轉載 這篇文章完全是基于南峰子老師博客的...
    西木閱讀 30,636評論 33 466
  • 參考鏈接: http://www.cnblogs.com/ioshe/p/5489086.html 簡介 Runt...
    樂樂的簡書閱讀 2,156評論 0 9
  • 為什么承受不了呢,生命中有些痛需要自己承受。大家都有要承受的東西。 對自己要求高一點,做到100%吧。 越努力,越幸運。
    矖軣閱讀 181評論 0 0
  • 在學習手繪插畫的道路上,需要創造力,更需要長期不懈的堅持。 1、人人可以畫插畫。手繪插畫與專業的繪畫不同,專業繪畫...
    兒童快樂成長驛站閱讀 1,925評論 0 14