1. 程式人生 > >iOS面試題<一>

iOS面試題<一>

1、        如何用GCD同步若干個非同步呼叫?(如根據若干個url非同步載入多張圖片,然後在都下載完成後合成一張整圖)

總體上說:  使用dispatch group,然後 wait forever 等待完成, 或者採取 group notify 來通知回撥。

  細節:

 1. 建立非同步佇列

 2. 建立dispatch_group dispatch_group_t = dispatch_group_create()

       3.

通過組來執行非同步下載任務

 dispatch_group_async(queueGroup, aQueue,^{   

       NSLog(@"下載圖片.");   

 });

4.等到所有任務完成   dispatch_group_wait(queueGroup,DISPATCH_TIME_FOREVER);

5.合成圖片

2、        @synthesize和@dynamic區別

在宣告property屬性後,有2種實現選擇

@synthesize

編譯器期間,讓編譯器自動生成getter/setter方法。

當有自定義的存或取方法時,自定義會遮蔽自動生成該方法

@dynamic

告訴編譯器,不自動生成getter/setter方法,避免編譯期間產生警告

然後由自己實現存取方法

@property就是編譯其自動幫我們生成一個私有的成員變數和setter與getter方法的宣告和實現

3、        weak關鍵字

strong:適用於OC物件,作用和非ARC中的retain作用相同,它修飾的成員變數為強指標型別;

weak:適用於OC物件,作用和非ARC中的assign作用相同,修飾的成員變數為弱指標型別;在ARC中,出現迴圈引用的時候,必須要有一端使用weak

      assign: 用於非指標變數。用於基礎資料型別。直接進行賦值,這也是預設的。setter方法直接賦值,而不進行retain操作

retain:用於指標變數。setter方法對引數進行release舊值,再retain新值。

copy:它指出,在賦值時使用傳入值的一份拷貝

      readwrite: 產生setter\getter方法

readonly: 只產生簡單的getter,沒有setter。

      copy: setter方法進行Copy操作,與retain一樣

      nonatomic: 禁止多執行緒,變數保護,提高效能

4、        iOS容易造成迴圈引用的三種場景

迴圈引用可以簡單理解為A引用了B,而B又引用了A,雙方都同時保持對方的一個引用,導致任何時候引用計數都不為0,始終無法釋放。

(1)計時器NSTimer:一方面,NSTimer經常會被作為某個類的成員變數,而NSTimer初始化時要指定self為target,容易造成迴圈引用。另一方面,若timer一直處於validate的狀態,則其引用計數將始終大於0。

解決方案:

在於-(void)cleanTimer函式的呼叫時機不對,顯然不能想當然地放在呼叫者的dealloc中。一個比較好的解決方法是開放這個函式,讓Friend的呼叫者顯式地呼叫來清理現場

(2)block:某個類將block作為自己的屬性變數,然後該類在block的方法體裡面又使用了該類本身

解決方案:

1) ARC環境下:ARC環境下可以通過使用_weak宣告一個代替self的新變數代替原先的self,通過這種方式告訴block,不要在block內部對self進行強制strong引用

2) 2)MRC環境下:使用_block即可,這樣的意思是告訴block:不要在內部對self進行retain了

(3)委託delegate

宣告delegate時請用assign(MRC)或者weak(ARC)

5、        IOS 四種儲存資料的方式

1.NSKeyedArchiver:採用歸檔的形式來儲存資料,該資料物件需要遵守NSCoding協議,並且該物件對應的類必須提供encodeWithCoder:和initWithCoder:方法。前一個方法告訴系統怎麼對物件進行編碼,而後一個方法則是告訴系統怎麼對物件進行解碼

歸檔的形式來儲存資料,只能一次性歸檔儲存以及一次性解壓。所以只能針對小量資料

2.NSUserDefaults:用來儲存應用程式設定和屬性、使用者儲存的資料。使用者再次開啟程式或開機後這些資料仍然存在。NSUserDefaults可以儲存的資料型別包括:NSData、NSString、NSNumber、NSDate、NSArray、NSDictionary。如果要儲存其他型別,則需要轉換為前面的型別,才能用NSUserDefaults儲存。

3.SQLite:採用SQLite資料庫來儲存資料。

第一步:需要新增SQLite相關的庫以及標頭檔案:在專案檔案的Build Phases下,找到Link Binary Library(ies),新增libsqlite3.0.dylib

第二步:開始使用SQLite

4.CoreData.Core Data是資料持久化儲存的最佳方式。資料最終的儲存型別可以是:SQLite資料庫,XML,二進位制,記憶體裡,或自定義資料型別

好處:能夠合理管理記憶體,避免使用sql的麻煩,高效

構成:

(1)NSManagedObjectContext(被管理的資料上下文)

操作實際內容(操作持久層)

作用:插入資料,查詢資料,刪除資料

(2)NSManagedObjectModel(被管理的資料模型)

資料庫所有表格或資料結構,包含各實體的定義資訊

作用:新增實體的屬性,建立屬性之間的關係

操作方法:檢視編輯器,或程式碼

(3)NSPersistentStoreCoordinator(持久化儲存助理)

相當於資料庫的聯結器

作用:設定資料儲存的名字,位置,儲存方式,和儲存時機

(4)NSManagedObject(被管理的資料記錄)

相當於資料庫中的表格記錄

(5)NSFetchRequest(獲取資料的請求)

相當於查詢語句

(6)NSEntityDescription(實體結構)

相當於表格結構

(7)字尾為.xcdatamodeld的包

裡面是.xcdatamodel檔案,用資料模型編輯器編輯

編譯後為.momd或.mom檔案

6、         loadView 和 viewDidLoad 的區別

iewDidLoad此方法只有當view從nib檔案初始化的時候才被呼叫。

loadView此方法在控制器的view為nil的時候被呼叫。 此方法用於以程式設計的方式建立view的時候用到

7、        UIViewController的生命週期及iOS程式執行順序

當一個檢視控制器被建立,並在螢幕上顯示的時候。 程式碼的執行順序

1、 alloc  建立物件,分配空間

2、init (initWithNibName)初始化物件,初始化資料

3、loadView  從nib載入檢視 ,通常這一步不需要去幹涉。除非你沒有使用xib檔案建立檢視

4、viewDidLoad  載入完成,可以進行自定義資料以及動態建立其他控制元件

5、viewWillAppear  檢視將出現在螢幕之前,馬上這個檢視就會被展現在螢幕上了

6、viewDidAppear    檢視已在螢幕上渲染完成

當一個檢視被移除螢幕並且銷燬的時候的執行順序,這個順序差不多和上面的相反

1、viewWillDisappear  檢視將被從螢幕上移除之前執行

2、viewDidDisappear  檢視已經被從螢幕上移除,使用者看不到這個檢視了

3、dealloc  檢視被銷燬,此處需要對你在init和viewDidLoad中建立的物件進行釋放

APP在執行時的呼叫順序

      1)- (void)viewDidLoad

一個APP在載入時會先通過呼叫loadView方法或者載入IB中建立的初始介面的方法,將檢視載入到記憶體中。然後會呼叫viewDidLoad方法來進行進一步的設定。只會在APP剛開始載入的時候呼叫一次

2) -(void)viewDidUnload; 在系統退出或者收到記憶體警告的時候才會被呼叫

3)-(void)viewWillAppear:(BOOL)animated;系統在載入所有資料後,將會在螢幕上顯示檢視,這時會先呼叫這個方法

4) -(void)viewDidAppear:(BOOL)animated;對檢視進行更新。那麼可以重寫這個方法

5) -(void)viewWillDisappear:(BOOL)animated;在檢視變換時,

當前檢視在即將被移除、或者被覆蓋時,會呼叫這個方法進行一些善後的

處理和設定

6) -(void)viewDidDisappear:(BOOL)animated;我們可以重寫這個

方法,對已經消失,或者被覆蓋,或者已經隱藏了的檢視做一些其他操作

 

執行APP —> 載入檢視 —> 呼叫viewDidLoad方法 —> 呼叫

viewWillAppear方法 —>呼叫viewDidAppear方法 —>正常執行 

8、        iOS的記憶體管理

在ObjC中每個物件內部都有一個與之對應的整數(retainCount),叫“引用計數器”,當一個物件在建立之後它的引用計數器為1,當呼叫這個物件的alloc、retain、new、copy方法之後引用計數器自動在原來的基礎上加1(ObjC中呼叫一個物件的方法就是給這個物件傳送一個訊息),當呼叫這個物件的release方法之後它的引用計數器減1,如果一個物件的引用計數器為0,則系統會自動呼叫這個物件的dealloc方法來銷燬這個物件。

記憶體釋放的原則:誰建立、誰釋放

Object-C物件生成分配空間在堆上,需要使用指標來指向其引用。

      +(id) alloc;注意這裡的alloc是一個類方法,呼叫alloc方法之後會在記憶體中分配一塊空間,並且引用計數會設定為1

+(id) init;呼叫init方法表示初始化物件

-(void) dealloc;這裡注意一下dealloc不是一個類方法,而是一個例項方法。dealloc 方法用於銷燬物件,當引用計數為0的時候系統會自動呼叫dealloc方法銷燬物件

-(void) release;呼叫這個方法用於釋放物件的引用,引用計數會-1

-(void) retain ;呼叫這個方法用於將引用計數+1

-(NSUInteger)retainCount;用於獲取一個物件當前被多少物件擁有

2、任意寫一段block程式碼,要求非同步處理

      dispatch_async(dispatch_queue_t queue,^{});

3、UIWindow和UIView、CALayer的區別

UIWindow是UIView的子類。主要作用是:提供一個區域來顯示UIView和將事件分發給UIView。一個應用基本上只有一個UIWindow

UIView是iOS系統中介面元素的基礎,所有介面元素都繼承自它。UIView本身是由CoreAnimation來實現的。UIView真正的繪圖部分是由CALyer得類來管理的。當訪問UIView的跟繪圖、座標有關的屬性,如frame、bounds等,實際上內部都是在訪問UIView所包含的CALayer的相關屬性

UIView和CALayer的區別:

1、UIView可以響應事件,Layer不可以

   UIView的繼承結構為:UIResponder:NSObject。UIResponder是用來響應事件的,所以UIView可以響應使用者事件

   CALayer的繼承結構為:NSObject,直接繼承自NSObject所以CALayer不能響應事件

2、UIView側重於對顯示內容的管理,CALayer側重於對內容的繪製

3、兩者都有樹狀層級結構,View內部有SubViews,Layer內部有SubLayers,但是Layer比View多了個AnchorPoint。

4、    CALayer內部維護這三份Layer Tree,分別是presentLayer Tree動畫樹、modeLayer模型樹、Render Tree渲染樹

4、        delegate、Notification以及KVO、KVC的區別

delegate、Notification以及KVO的功能類似,都是作用於OC中物件

      的訊息通訊。但三者的使用場景是不同的。

A.    delegate是一種回撥函式,一對一。接受者可以返回值給傳送者

B.    Notification,使用Notification Center,類似廣播方式,所以更適合一對多的通訊;接受者無法返回值給傳送者

C.    KVO,key-Value-Observing,觀察者模式,適用於監聽另一物件的屬性的變化。一個物件能夠觀察另外一個物件的屬性的值,並且能夠發現值的變化。一對多的通訊,無返回值

KVO的使用也很簡單,就是簡單的3步。
     

1. 註冊需要觀察的物件的屬性

      addObserver:forKeyPath:options:context:
    

2. 實現

observeValueForKeyPath:ofObject:change:context:方法,這

個方法當觀察的屬性變化時會自動呼叫
    

      3.取消註冊觀察removeObserver:forKeyPath:context:

 

D.    KVC,即是指 NSKeyValueCoding,鍵值編碼,一個非正式的Protocol,通過指定的key來訪問物件的屬性。而不是通過呼叫Setter、Getter方法訪問。KVO就是基於 KVC 實現的關鍵技術之一

5、        繼承跟類別的區別,為什麼要有類別的存在?

*類別:類別是對一個功能完備的類的一種補充,就像是一個東西的主要基本功能都完成了,可以用類別為這個類新增不同的元件,使得這個類能夠適應不同情況的需求。比如animal這個類,具有eat和run等方法,想給這個類新增一個bark的方法,可以用類別。

 

*繼承:多個類具有相同的例項變數和方法時,考慮用繼承。即子類可以繼承父類的相同特性。如animal具有年齡和體重兩個屬性,dog也具有年齡和體重兩 個屬性,dog可以繼承animal的這兩個屬性,即為繼承。

共同點:都是給一個類進行擴充套件

區別:1.類別是對方法的擴充套件,不能新增成員變數。繼承可以在原來父類的成員變數的基礎上,新增新的成員變數

      2.類別只能新增新的方法,不能修改和刪除原來的方法。繼承可以增加、修改和刪除方法。

      3.類別不提倡對原有的方法進行過載。繼承可以通過使用super對原來方法進行過載。

     4.類別可以被繼承,如果一個父類中定義了類別,那麼其子類中也會繼承此類別

6、        簡述ARC的機制原理

如果需要持有一個物件,那麼對其傳送retain 。如果之後不再使用該物件,那麼需要對其傳送release(或者autorealse) 每一次對retain,alloc或者new的呼叫,需要對應一次release或autorealse呼叫

ARC所做的只不過是在程式碼編譯時自動在合適的位置插入release或autorelease

7、        簡單編寫一個block代理?

8、        MVC是什麼?有什麼特性?為什麼在iphone上被廣泛運用?

Model View Controller,是模型(model)-檢視(view)-控制器(controller)的縮寫。一種軟體設計典範,用一種業務邏輯、資料、介面顯示分離的方法組織程式碼,將業務邏輯聚集到一個部件裡面,在改進和個性化定製介面及使用者互動的同時,不需要重新編寫業務邏輯。MVC被獨特的發展起來用於對映傳統的輸入、處理和輸出功能在一個邏輯的圖形化使用者介面的結構中

9、        委託是什麼?委託的property宣告用什麼屬性?為什麼?

委託:一個物件儲存另一個物件的引用,被引用的物件實現了事先確定的協議,該協議用於將引用物件中的變化通知給被引用物件。

委託和委託方雙方的property宣告屬性都是assign而不是retain

為了避免迴圈引用造成的記憶體洩露

迴圈引用的問題這樣理解:比如在main函式中建立了兩個類的物件A和B,現在引用計數是1.現在讓A和B互相引用(A有一個屬性是B物件,屬性說明是retain;B有一個屬性是A物件,屬性說明是retain),現在兩個物件的引用計數都增加1,都變成了2.現在執行[Areleasw];[B release];此時建立物件的main函式已經釋放了自己對物件的所有權,但是此時A和B的引用計數都還是1,因為他們互相引用了。 這使你發現A和B將無法釋放,因為要想釋放A必須先釋放B,在B的dealloc方法中再釋放A。同理,想要釋放B必須先釋放A,在A的dealloc方法中再釋放B。所以這兩個物件將一直存在記憶體中而不釋放,這就是所謂的迴圈引用的問題

10、     專案使用過哪些第三方庫?

11、     怎麼實現tableView懶載入?

12、     編寫一個singleton單例的類?

13、     開發過程中最常見的異常有哪些,列舉幾個?

14、      推送機制

蘋果的推送服務APNs基本原理

蘋果利用自己專門的推送伺服器(APNs)接收來自我們自己應用伺服器的需要被推送的資訊,然後推送到指定的iOS裝置上,然後由裝置通知到我們的應用程式,裝置以通知或者聲音的形式通知使用者有新的訊息。

裝置和APNS伺服器之間的通訊是基於SSL協議的TCP流通訊,二者之間維持一個長連線

推送的過程經過如下步驟:

1.首先,安裝了具有推送功能的應用,我們的裝置在有網路的情況下會連線蘋果推送伺服器,連線過程中,APNS會驗證device_token,連線成功後維持一個長連線;

2.Provider(我們自己的伺服器)收到需要被推送的訊息並結合被推送裝置的device_token一起打包傳送給APNS伺服器;

3.APNS伺服器將推送資訊推送給指定device_token的裝置;

4.裝置收到推送訊息後通知我們的應用程式並顯示和提示使用者(聲音、彈出框)

15、     獲取一臺裝置唯一標識的方法有哪些?

   -(NSString*) uuid {    

    CFUUIDRef puuid = CFUUIDCreate( nil );    

    CFStringRef uuidString = CFUUIDCreateString( nil, puuid

 );    

    NSString * result = (NSString *)CFStringCreateCopy( NUL

L, uuidString);    

    CFRelease(puuid);    

    CFRelease(uuidString);  

return [result autorelease];

16、     寫一個委託的interface。

#import

@protocolMyDelegate;//宣告

@interfaceMyClass:NSobject

{

iddelegate;

}

@end

@protocolMyDelegate//委託方法

-(void)didJobs:(NsArray*)args;

@end

17、     如何管理記憶體

Objective-C提供了三種記憶體管理方式:manualretain-release(MRR,手動管理),automaticreference counting(ARC,自動引用計數),garbagecollection(垃圾回收)。iOS不支援垃圾回收

記憶體管理的目的是:

1.不要釋放或者覆蓋還在使用的記憶體,這會引起程式崩潰;

2.釋放不再使用的記憶體,防止記憶體洩露