你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> 面試時如何優雅的談論OC

面試時如何優雅的談論OC

編輯:IOS開發基礎

img (124).jpg

本文授權轉載,作者:吳白

在面試中,我們經常會遇到一些原理性的問題,很常識但很難用通俗的語言解釋清楚,這也是大部分業務級程序員經常失誤的地方。雖然寫了多年代碼,但是核心思想不清,導致自己的後續發展受限,這是一個優秀的程序員和普通程序員的分水嶺。要知其然而知其所以然!這也是整理這篇文章的初衷。文中結合了之前的一些文章,條理更清晰,內容更深入。

本文包括:

  • OC的面向對象

  • 運行時Runtime

  • 運行循環RunLoop

  • 事件響應鏈

  • 引用計數

  • 生命周期

  • 與其他語言的區別

Objective-C 簡稱OC(下面以此代稱),是在C語言的基礎上,增加了一層最小的面向對象語言。是一種靜態輸入的語言,即“必須先聲明數據中每個變量(或者容器)的數據類型”。但它是一個動態語言,代碼中的某一部分可以在app運行的時候被擴展和修改(比如,在被編譯之後)。OC完全兼容C語言,在代碼中,可以混用c,甚至是c++代碼。

面向對象三原則(封裝,繼承,多態)

面向對象具有四個基本特征:抽象,封裝,繼承和多態。

C語言是面向過程的語言(關注的是函數),OC,C++,JAVA,C#,PHP,Swift是面向對象的,面向過程關注的是解決問題涉及的步驟,而面向對象關注的是設計能夠實現解決問題所需功能的類。抽象是面向對象的思想基礎。

抽象包括兩個方面,一是過程抽象,二是數據抽象。過程抽象是指任何一個明確定義功能的操作都可被使用者看作單個的實體看待,盡管這個操作實際上可能由一系列更低級的操作來完成。數據抽象定義了數據類型和施加於該類型對象上的操作,並限定了對象的值只能通過使用這些操作修改和觀察。抽象是一種思想,封裝繼承和多態是這種思想的實現。

封裝

封裝是把過程和數據包圍起來(即函數和數據結構,函數是行為,數據結構是描述),有限制的對數據的訪問。面向對象基於這個基本概念開始的(因為面向對象更注重的是類),即現實世界可以被描繪成一系列完全自治、封裝的對象,這些對象通過一個受保護的接口訪問其他對象。一旦定義了一個對象的特性,則有必要決定這些特性的可見性,封裝保證了模塊具有較好的獨立性,使得程序維護修改較為容易。對應用程序的修改僅限於類的內部,因而可以將應用程序修改帶來的影響減少到最低限度。但是封裝會導致並行效率問題,因為執行部分和數據部分被綁定在一起,制約了並行程度。面向對象思想將函數和數據綁在一起,擴大了代碼重用時的粒度。而且封裝下的拆箱裝箱過程中也會導致內存的浪費。

繼承

繼承是一種層次模型,允許和鼓勵類的重用,並提供了一種明確表述共性的方法。新類繼承了原始類的特性,新類稱為原始類的派生類(子類和父類)。派生類可以從它的基類那裡繼承方法和實例變量,並且類可以修改或增加新的方法使之更適合特殊的需要。繼承性很好的解決了軟件的可重用性問題。但是,不恰當地使用繼承導致的最大的一個缺陷特征就是高耦合(即“牽一發而動全身”,是設計類時層次沒分清導致的)。解決方案是用組合替代繼承。將模塊拆開,然後通過定義好的接口進行交互,一般來說可以選擇Delegate模式來交互。使用繼承其實是如何給一類對象劃分層次的問題。在正確的繼承方式中,父類應當扮演的是底層的角色,子類是上層的業務。父類只是給子類提供服務,並不涉及子類的業務邏輯;層級關系明顯,功能劃分清晰;父類的所有變化,都需要在子類中體現,此時耦合已經成為需求。

多態

多態性是指允許不同類的對象對同一消息作出響應。多態性包括參數化多態性和包含多態性。很好的解決了應用程序函數同名問題,多態一般都要跟繼承結合起來說,其本質是子類通過覆蓋或重載父類的方法,來使得對同一類對象同一方法的調用產生不同的結果。覆蓋是對接口方法的實現,繼承中也可能會在子類覆蓋父類中的方法。重載,是指我們可以定義一些名稱相同的方法,通過定義不同的輸入參數來區分這些方法,然後再調用時,VM就會根據不同的參數樣式,來選擇合適的方法執行。在使用重載時只能通過不同的參數樣式。例如,不同的參數類型,不同的參數個數,不同的參數順序(當然,同一方法內的幾個參數類型必須不一樣); 但繼承會引入多態使用混亂的境況並產生耦合,更好的方法是使用接口。通過IOP將子類與可能被子類引入的不相關邏輯剝離開來,提高了子類的可重用性,降低了遷移時可能的耦合。接口規范了子類哪些必須實現,哪些可選實現。那些不在接口定義的方法列表裡的父類方法,事實上就是不建議覆重的方法。如果引入多態之後導致對象角色不夠單純,那就不應當引入多態,如果引入多態之後依舊是單純角色,那就可以引入多態;如果要覆重的方法是角色業務的其中一個組成部分,那麼就最好不要用多態的方案,用IOP,因為在外界調用的時候其實並不需要通過多態來滿足定制化的需求。

動態性(Runtime)

Objective-C 是面相運行時的語言,它會盡可能的把編譯和鏈接時要執行的邏輯延遲到運行時。使用Runtime可以按需要把消息重定向給合適的對象,交換方法的實現等等。

Runtime簡稱運行時,其中最主要的是消息機制,是一個主要使用 C 和匯編寫的庫,為 C 添加了面相對象的能力並創造了 Objective-C。。OC的函數調用稱為消息發送。屬於動態調用過程。在編譯的時候並不能決定真正調用哪個函數(在編 譯階段,OC可以調用任何函數,即使這個函數並未實現,只要聲明過就不會報錯。而C語言在編譯階段就會報錯)。只有在真正運行的時候才會根據函數的名稱找 到對應的函數來調用。

如:

[obj makeText];
==》
objc_msgSend(obj,@selector(makeText));

編譯器執行上述轉換。在objc_msgSend函數中,首先通過obj的isa指針找到obj對應的class。每個對象內部都默認有一個isa指針指向這個對象所使用的類。isa是對象中的隱藏指針,指向創建這個對象的類。在Class中先去cache中通過SEL查找對應函數method(cache中method列表是以SEL為key通過hash表來存儲的,這樣能提高函數查找速度),若cache中未找到,再去methodList中查找,若methodlist中未找到,則取superClass中查找。若能找到,則將method加入到cache中,以方便下次查找,並通過method中的函數指針跳轉到對應的函數中去執行。

動態性的三方面

OC的動態特性表現為了三個方面:動態類型、動態綁定、動態加載。之所以叫做動態,是因為必須到運行時(runtime)才會做一些事情。

動態類型,就是id類型。動態類型是跟靜態類型相對的。內置的基本類型都屬於靜態類型(int、NSString等)。靜態類型在編譯的時候就能被識別出來(即前面說的靜態輸入)。所以,若程序發生了類型不對應,編譯器就會發出警告。而動態類型就編譯器編譯的時候是不能被識別的,要等到運行時(runtime),即程序運行的時候才會根據語境來識別。所以這裡面就有兩個概念要分清:編譯時跟運行時。

動態語言和靜態語言的一個區別是靜態語言提前編譯好文件,即所有的邏輯已在編譯時確定,運行時直接加載編譯後的文件;而動態語言是在運行時才確定實現。典型的靜態語言是C++,動態語言包括OC,JAVA,C#等;因為靜態語言提前編譯好了執行文件,也就是通常所說的靜態語言效率較高的原因。

動態綁定(dynamic binding)需要用到@selector/SEL。先來看看“函數”,對於其他一些靜態語言,比如c++,一般在編譯的時候就已經將要調用的函數的函數簽名都告訴編譯器了。靜態的,不能改變。而在OC中,其實是沒有函數的概念的,我們叫“消息機制”,所謂的函數調用就是給對象發送一條消息。這時,動態綁定的特性就來了。OC可以先跳過編譯,到運行的時候才動態地添加函數調用,在運行時才決定要調用什麼方法,需要傳什麼參數進去,這就是動態綁定。要實現他就必須用SEL變量綁定一個方法。最終形成的這個SEL變量就代表一個方法的引用。這裡要注意一點:SEL並不是C裡面的函數指針,雖然很像,但真心不是函數指針。SEL變量只是一個整數,他是該方法的ID。以前的函數調用,是根據函數名,也就是字符串去查找函數體。但現在,我們是根據一個ID整數來查找方法,整數的查找自然要比字符串的查找快得多!所以,動態綁定的特定不僅方便,而且效率更高。

動態加載就是根據需求動態地加載資源,在運行時加載新類。在運行時創建一個新類,只需要3步:

1、為 class pair分配存儲空間 ,使用 objc_allocateClassPair函數

2、增加需要的方法使用class_addMethod函數,增加實例變量用class_addIvar

3 、用objc_registerClassPair函數注冊這個類,以便它能被別人使用。

Method Swizzling

在Objective-C中調用一個方法,其實是向一個對象發送消息,查找消息的唯一依據是selector的名字。利用Objective-C的動態特性,可以實現在運行時偷換selector對應的方法實現,達到給方法掛鉤的目的。每個類都有一個方法列表,存放著selector的名字和方法實現的映射關系。IMP類似函數指針,指向具體的Method實現。

用 method_exchangeImplementations 來交換2個方法中的IMP,

用 class_replaceMethod 來修改類,

用 method_setImplementation 來直接設置某個方法的IMP,歸根結底,都是偷換了selector的IMP。

RunLoop

RunLoop是一讓線程能隨時處理事件但不退出的機制。RunLoop實際上是一個對象,這個對象管理了其需要處理的事件和消息,並提供了一個入口函數來執行Event Loop的邏輯。線程執行了這個函數後,就會一直處於這個函數內部 "接受消息->等待->處理" 的循環中,直到這個循環結束(比如傳入 quit 的消息),函數返回。讓線程在沒有處理消息時休眠以避免資源占用、在有消息到來時立刻被喚醒。一個runloop就是一個事件處理循環,用來不停的監聽和處理輸入事件並將其分配到對應的目標上進行處理。

RunLoop的四個作用為:使程序一直運行接受用戶輸入;決定程序在何時應該處理哪些Event;調用解耦;節省CPU時間。

線程和 RunLoop 之間是一一對應的,其關系是保存在一個全局的 Dictionary 裡。線程剛創建時並沒有 RunLoop,如果你不主動獲取,那它一直都不會有。RunLoop 的創建是發生在第一次獲取時,RunLoop 的銷毀是發生在線程結束時。你只能在一個線程的內部獲取其RunLoop(主線程除外)。

主線程的runloop默認是啟動的。

OSX/iOS 系統中,提供了兩個這樣的對象:NSRunLoop和CFRunLoopRef。CFRunLoopRef 是在 CoreFoundation 框架內的,它提供了純 C 函數的 API,所有這些 API 都是線程安全的。NSRunLoop 是基於 CFRunLoopRef 的封裝,提供了面向對象的 API,但是這些 API 不是線程安全的。

NSRunLoop是一種更加高明的消息處理模式,在對消息處理過程進行了更好的抽象和封裝,不用處理一些很瑣碎很低層次的具體消息的處理,在NSRunLoop中每一個消息就被打包在input source或者是timer source中了。使用run loop可以使你的線程在有工作的時候工作,沒有工作的時候休眠,可以大大節省系統資源。

對其它線程來說,runloop默認是沒有啟動的,如果你需要更多的線程交互則可以手動配置和啟動,如果線程只是去執行一個長時間的已確定的任務則不需要。在任何一個Cocoa程序的線程中,都可以通過:

NSRunLoop *runloop = [NSRunLoop currentRunLoop];

獲取到當前線程的runloop。

Cocoa中的NSRunLoop類並不是線程安全的

我們不能在一個線程中去操作另外一個線程的runloop對象,那很可能會造成意想不到的後果。但是CoreFundation中的不透明類CFRunLoopRef是線程安全的,而且兩種類型的runloop完全可以混合使用。Cocoa中的NSRunLoop類可以通過實例方法:

 - (CFRunLoopRef)getCFRunLoop;

獲取對應的CFRunLoopRef類,來達到線程安全的目的。

Runloop的管理並不完全是自動的。我們仍必須設計線程代碼以在適當的時候啟動runloop並正確響應輸入事件,當然前提是線程中需要用到runloop。而且,我們還需要使用while/for語句來驅動runloop能夠循環運行,下面的代碼就成功驅動了一個run loop:

BOOL isRunning = NO;
do {
 isRunning = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDatedistantFuture]];
} while (isRunning);

Runloop同時也負責autorelease pool的創建和釋放

在使用手動的內存管理方式的項目中,會經常用到很多自動釋放的對象,如果這些對象不能夠被即時釋放掉,會造成內存占用量急劇增大。Runloop就為我們做了這樣的工作,每當一個運行循環結束的時候,它都會釋放一次autorelease pool,同時pool中的所有自動釋放類型變量都會被釋放掉。

系統默認注冊了5個Mode:

  • kCFRunLoopDefaultMode: App的默認 Mode,通常主線程是在這個 Mode 下運行的。

  • UITrackingRunLoopMode: 界面跟蹤 Mode,用於 ScrollView 追蹤觸摸滑動,保證界面滑動時不受其他 Mode 影響。

  • UIInitializationRunLoopMode: 在剛啟動 App 時第進入的第一個 Mode,啟動完成後就不再使用。

  • GSEventReceiveRunLoopMode: 接受系統事件的內部 Mode,通常用不到。

  • kCFRunLoopCommonModes: 這是一個占位的 Mode,沒有實際作用。

輪播圖中的NSTimer問題

創建定時器:

1:NSTimer *timer = [NSTimer timerWithTimeInterval:2 target:self selector:@selector(changeImage) userInfo:nil repeats:YES];

此方法創建的定時器,必須加到NSRunLoop中。

NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer:timer forMode: NSRunLoopCommonModes];

forMode的參數有兩種類型可供選擇: NSDefaultRunLoopMode , NSRunLoopCommonModes,第一個參數為默認參數,當下面有textView,textfield等控件時,拖拽控件,此時輪播器會停止輪播,是因為NSRunLoop的原因,NSRunLoop為一個死循環,實時監測有無事件響應,如果當前線程就是主線程,也就是UI線程時,某些UI事件,比如UIScrollView的拖動操作,會將Run Loop切換成NSEventTrackingRunLoopMode模式,在這個過程中,默認的NSDefaultRunLoopMode模式中注冊的事件是不會被執行的。NSRunLoopCommonModes 能夠在多線程中起作用,這個模式等效於NSDefaultRunLoopMode和NSEventTrackingRunLoopMode的結合,這也是將modes換為NSRunLoopCommonModes便可解決的原因。

2: self.timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(changeImage) userInfo:nil repeats:YES];

此種創建定時器的方式,默認加到了runloop,且默認為第二個參數。

main函數的運行

在main.m中:

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

UIApplicationMain() 函數會為main thread 設置一個NSRunLoop 對象,這就解釋了app應用可以在無人操作的時候休息,需要讓它干活的時候又能立馬響應。

僅當在為你的程序創建輔助線程的時候,你才需要顯式運行一個runloop。Runloop是程序主線程基礎設施的關鍵部分,所以,Cocoa和Carbon程序提供了代碼運行主程序的循環並自動啟動runloop。IOS程序中UIApplication的run方法(或Mac OS X中的NSApplication)作為程序啟動步驟的一部分,它在程序正常啟動的時候就會啟動程序的主循環。如果你使用xcode提供的模板創建你的程序,那你永遠不需要自己去顯式的調用這些例程。

對於輔助線程,你需要判斷一個runloop是否是必須的。如果是必須的,那麼你要自己配置並啟動它。你不需要在任何情況下都去啟動一個線程的runloop。比如,你使用線程來處理一個預先定義的長時間運行的任務時,你應該避免啟動runloop。Runloop在你要和線程有更多的交互時才需要,比如以下情況:

1.使用端口或自定義輸入源來和其他線程通信;

2.使用線程的定時器;

3.Cocoa中使用任何performSelector...的方法;

4.使線程周期性工作;

事件響應鏈

對於IOS設備用戶來說,操作設備的方式主要有三種:觸摸屏幕、晃動設備、通過遙控設施控制設備。對應的事件類型有以下三種:

1、觸屏事件(Touch Event)

2、運動事件(Motion Event)

3、遠端控制事件(Remote-Control Event)

事件的傳遞和響應分兩個鏈:

  • 傳遞鏈:由系統向離用戶最近的view傳遞。

UIKit –> active app’s event queue –> window –> root view –>……–>lowest view

  • 響應鏈:由離用戶最近的view向系統傳遞。

initial view –> super view –> …..–> view controller –> window –> Application

響應者鏈(Responder Chain):由多個響應者對象連接起來的鏈條,作用是能很清楚的看見每個響應者之間的聯系,並且可以讓一個事件多個對象處理。

響應者對象(Responder Object),指的是有響應和處理事件能力的對象。響應者鏈就是由一系列的響應者對象構成的一個層次結構。

UIResponder是所有響應對象的基類,在UIResponder類中定義了處理上述各種事件的接口。我們熟悉的UIApplication、 UIViewController、UIWindow和所有繼承自UIView的UIKit類都直接或間接的繼承自UIResponder,所以它們的實例都是可以構成響應者鏈的響應者對象。

響應者鏈有以下特點:

1、響應者鏈通常是由視圖(UIView)構成的;

2、一個視圖的下一個響應者是它視圖控制器(UIViewController)(如果有的話),然後再轉給它的父視圖(Super View);

3、視圖控制器(如果有的話)的下一個響應者為其管理的視圖的父視圖;

4、單例的窗口(UIWindow)的內容視圖將指向窗口本身作為它的下一個響應者,Cocoa Touch應用不像Cocoa應用,它只有一個UIWindow對象,因此整個響應者鏈要簡單一點;

5、單例的應用(UIApplication)是一個響應者鏈的終點,它的下一個響應者指向nil,以結束整個循環。

iOS系統檢測到手指觸摸(Touch)操作時會將其打包成一個UIEvent對象,並放入當前活動Application的事件隊列,單例的UIApplication會從事件隊列中取出觸摸事件並傳遞給單例的UIWindow來處理,UIWindow對象首先會使用hitTest:withEvent:方法尋找此次Touch操作初始點所在的視圖(View),即需要將觸摸事件傳遞給其處理的視圖,這個過程稱之為hit-test view。

UIWindow實例對象會首先在它的內容視圖上調用hitTest:withEvent:,此方法會在其視圖層級結構中的每個視圖上調用pointInside:withEvent:(該方法用來判斷點擊事件發生的位置是否處於當前視圖范圍內,以確定用戶是不是點擊了當前視圖),如果pointInside:withEvent:返回YES,則繼續逐級調用,直到找到touch操作發生的位置,這個視圖也就是要找的hit-test view。

hitTest:withEvent:方法的處理流程如下:

首先調用當前視圖的pointInside:withEvent:方法判斷觸摸點是否在當前視圖內;若返回NO,則hitTest:withEvent:返回nil;若返回YES,則向當前視圖的所有子視圖(subviews)發送hitTest:withEvent:消息,所有子視圖的遍歷順序是從最頂層視圖一直到到最底層視圖,即從subviews數組的末尾向前遍歷,直到有子視圖返回非空對象或者全部子視圖遍歷完畢;若第一次有子視圖返回非空對象,則hitTest:withEvent:方法返回此對象,處理結束;如所有子視圖都返回非,則hitTest:withEvent:方法返回自身(self)。

引用計數器(ARC 和 MRC)

  • ARC:自動引用計數器(Automatic Reference Counting)

  • MRC:手動引用計算器(由於現在幾乎不用了,不做過多解說)

Objective-C中提供了兩種內存管理機制MRC(MannulReference Counting)和ARC(Automatic Reference Counting),分別提供對內存的手動和自動管理,來滿足不同的需求。Xcode 4.1及其以前版本沒有ARC。

在MRC的內存管理模式下,與對變量的管理相關的方法有:retain,release和autorelease。retain和release方法操作的是引用記數,當引用記數為零時,便自動釋放內存。並且可以用NSAutoreleasePool對象,對加入自動釋放池(autorelease調用)的變量進行管理,當內存緊張時回收內存。

(1) retain,該方法的作用是將內存數據的所有權附給另一指針變量,引用數加1,即retainCount+= 1;

(2) release,該方法是釋放指針變量對內存數據的所有權,引用數減1,即retainCount-= 1;

(3) autorelease,該方法是將該對象內存的管理放到autoreleasepool中。

在ARC中與內存管理有關的標識符,可以分為變量標識符和屬性標識符,對於變量默認為__strong,而對於屬性默認為unsafe_unretained。也存在autoreleasepool。

其中assign/retain/copy與MRC下property的標識符意義相同,strong類似與retain,assign類似於unsafe_unretained,strong/weak/unsafe_unretained與ARC下變量標識符意義相同,只是一個用於屬性的標識,一個用於變量的標識(帶兩個下劃短線__)。

生命周期

app應用程序有5種狀態:

  • Not running未運行:程序沒啟動。

  • Inactive未激活:程序在前台運行,不過沒有接收到事件。在沒有事件處理情況下程序通常停留在這個狀態。

  • Active激活:程序在前台運行而且接收到了事件。這也是前台的一個正常的模式。

  • Backgroud後台:程序在後台而且能執行代碼,大多數程序進入這個狀態後會在在這個狀態上停留一會。時間到之後會進入掛起狀態(Suspended)。有的程序經過特殊的請求後可以長期處於Backgroud狀態。

  • Suspended掛起:程序在後台不能執行代碼。系統會自動把程序變成這個狀態而且不會發出通知。當掛起時,程序還是停留在內存中的,當系統內存低時,系統就把掛起的程序清除掉,為前台程序提供更多的內存。

iOS的入口在main.m文件的main函數,根據UIApplicationMain函數,程序將進入AppDelegate.m,這個文件是xcode新建工程時自動生成的。AppDelegate.m文件,關乎著應用程序的生命周期。

1、application didFinishLaunchingWithOptions:當應用程序啟動時執行,應用程序啟動入口,只在應用程序啟動時執行一次。若用戶直接啟動,lauchOptions內無數據,若通過其他方式啟動應用,lauchOptions包含對應方式的內容。

2、applicationWillResignActive:在應用程序將要由活動狀態切換到非活動狀態時候,要執行的委托調用,如 按下 home 按鈕,返回主屏幕,或全屏之間切換應用程序等。

3、applicationDidEnterBackground:在應用程序已進入後台程序時,要執行的委托調用。

4、applicationWillEnterForeground:在應用程序將要進入前台時(被激活),要執行的委托調用,剛好與applicationWillResignActive 方法相對應。

5、applicationDidBecomeActive:在應用程序已被激活後,要執行的委托調用,剛好與applicationDidEnterBackground 方法相對應。

6、applicationWillTerminate:在應用程序要完全推出的時候,要執行的委托調用,這個需要要設置UIApplicationExitsOnSuspend的鍵值。

初次啟動:

iOS_didFinishLaunchingWithOptions

iOS_applicationDidBecomeActive

按下home鍵:

iOS_applicationWillResignActive

iOS_applicationDidEnterBackground

點擊程序圖標進入:

iOS_applicationWillEnterForeground

iOS_applicationDidBecomeActive

當應用程序進入後台時,應該保存用戶數據或狀態信息,所有沒寫到磁盤的文件或信息,在進入後台時,最後都寫到磁盤去,因為程序可能在後台被殺死。釋放盡可能釋放的內存。

- (void)applicationDidEnterBackground:(UIApplication *)application

方法有大概5秒的時間讓你完成這些任務。如果超過時間還有未完成的任務,你的程序就會被終止而且從內存中清除。

如果還需要長時間的運行任務,可以在該方法中調用

[application beginBackgroundTaskWithExpirationHandler:^{
NSLog(@"begin Background Task With Expiration Handler");
}];

程序終止

程序只要符合以下情況之一,只要進入後台或掛起狀態就會終止:

①iOS4.0以前的系統

②app是基於iOS4.0之前系統開發的。

③設備不支持多任務

④在Info.plist文件中,程序包含了 UIApplicationExitsOnSuspend 鍵。

系統常常是為其他app啟動時由於內存不足而回收內存最後需要終止應用程序,但有時也會是由於app很長時間才響應而終止。如果app當時運行在後台並且沒有暫停,系統會在應用程序終止之前調用app的代理的方法 - (void)applicationWillTerminate:(UIApplication *)application,這樣可以讓你可以做一些清理工作。你可以保存一些數據或app的狀態。這個方法也有5秒鐘的限制。超時後方法會返回程序從內存中清除。用戶可以手工關閉應用程序。

和其他動態語言的區別

OC中方法的實現只能寫在@implementation··@end中,對象方法的聲明只能寫在@interface···@end中間;對象方法都以-號開頭,類方法都以+號開頭;函數屬於整個文件,可以寫在文件中的任何位置,包括@interface··@end中,但寫在@interface···@end會無法識別;

對象方法只能由對象來調用,類方法只能由類來調用,不能當做函數一樣調用,對象方法歸類\\對象所有;類方法調用不依賴於對象;類方法內部不能直接通過成員變量名訪問對象的成員變量。OC只支持單繼承,沒有接口,但可以用delegate代替。

Objective-C與其他語言最大的區別是其運行時的動態性,它能讓你在運行時為類添加方法或者去除方法以及使用反射。極大的方便了程序的擴展。

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved