Objective-C面試題和基本概念

1、Object-C有多繼承嗎?沒有的話用什麼代替?cocoa 中所有的類都是NSObject 的子類


多繼承在這裏是用protocol 委託代理 來實現的


你不用去考慮繁瑣的多繼承 ,虛基類的概念.


ood的多態特性 在 obj-c 中通過委託來實現.


2、Object-C有私有方法嗎?私有變量呢?


objective-c – 類裏面的方法只有兩種, 靜態方法和實例方法. 這似乎就不是完整的面向對象了,按照OO的原則就是一個對象只暴露有用的東西. 如果沒有了私有方法的話, 對於一些小範圍的代碼重用就不那麼順手了. 在類裏面聲名一個私有方法


@interface Controller : NSObject { NSString *something; }


+ (void)thisIsAStaticMethod;


– (void)thisIsAnInstanceMethod;


@end


@interface Controller (private) -


(void)thisIsAPrivateMethod;


@end


@private可以用來修飾私有變量


在Objective‐C中,所有實例變量默認都是私有的,所有實例方法默認都是公有的


3、關鍵字const什麼含義?


const意味着”只讀”,下面的聲明都是什麼意思?


const int a;


int const a;


const int *a;


int * const a;


int const * a const;


前兩個的作用是一樣,a是一個常整型數。第三個意味着a是一個指向常整型數的指針(也就是,整型數是不可修改的,但指針可以)。第四個意思a是一個指向整 型數的常指針(也就是說,指針指向的整型數是可以修改的,但指針是不可修改的)。最後一個意味着a是一個指向常整型數的常指針(也就是說,指針指向的整型 數是不可修改的,同時指針也是不可修改的)。


結論:


; 關鍵字const的作用是爲給讀你代碼的人傳達非常有用的信息,實際上,聲明一個參數爲常量是爲了告訴了用戶這個參數的應用目的。如果你曾花很多時間清理其它人留下的垃圾,你就會很快學會感謝這點多餘的信息。(當然,懂得用const的程序員很少會留下的垃圾讓別人來清理的。)


; 通過給優化器一些附加的信息,使用關鍵字const也許能產生更緊湊的代碼。


; 合理地使用關鍵字const可以使編譯器很自然地保護那些不希望被改變的參數,防止其被無意的代碼修改。簡而言之,這樣可以減少bug的出現。


欲阻止一個變量被改變,可以使用 const 關鍵字。在定義該 const 變量時,通常需要對它進行初


始化,因爲以後就沒有機會再去改變它了;


(2)對指針來說,可以指定指針本身爲 const,也可以指定指針所指的數據爲 const,或二者同時指定爲 const;


(3)在一個函數聲明中,const 可以修飾形參,表明它是一個輸入參數,在函數內部不能改變其值;


(4)對於類的成員函數,若指定其爲 const 類型,則表明其是一個常函數,不能修改類的成員變量;


(5)對於類的成員函數,有時候必須指定其返回值爲 const 類型,以使得其返回值不爲“左值”。


4、關鍵字volatile有什麼含義?並給出三個不同例子?


一個定義爲volatile的變量是說這變量可能會被意想不到地改變,這樣,編譯器就不會去假設這個變量的值了。精確地說就是,優化器在用到


這個變量時必須每次都小心地重新讀取這個變量的值,而不是使用保存在寄存器裏的備份。下面是volatile變量的幾個例子:


並行設備的硬件寄存器(如:狀態寄存器)


一箇中斷服務子程序中會訪問到的非自動變量(Non-automatic variables)


多線程應用中被幾個任務共享的變量


一個參數既可以是const還可以是volatile嗎?解釋爲什麼。


一個指針可以是volatile 嗎?解釋爲什麼。


下面是答案:


是的。一個例子是隻讀的狀態寄存器。它是volatile因爲它可能被意想不到地改變。它是const因爲程序不應該試圖去修改它。


是的。儘管這並不很常見。一個例子是當一箇中服務子程序修該一個指向一個buffer的指針時。


static作用?


函數體內 static 變量的作用範圍爲該函數體,不同於 auto 變量,該變量的內存只被分配一次,


因此其值在下次調用時仍維持上次的值;


(2)在模塊內的 static 全局變量可以被模塊內所用函數訪問,但不能被模塊外其它函數訪問;


(3)在模塊內的 static 函數只可被這一模塊內的其它函數調用,這個函數的使用範圍被限制在聲明


它的模塊內;


(4)在類中的 static 成員變量屬於整個類所擁有,對類的所有對象只有一份拷貝;


(5)在類中的 static 成員函數屬於整個類所擁有,這個函數不接收 this 指針,因而只能訪問類的static 成員變量。


6、#import和#include的區別,@class代表什麼?


@class一般用於頭文件中需要聲明該類的某個實例變量的時候用到,在m文件中還是需要使用#import


而#import比起#include的好處就是不會引起重複包含


7、線程和進程的區別?


進程和線程都是由操作系統所體會的程序運行的基本單元,系統利用該基本單元實現系統對應用的併發性。


進程和線程的主要差別在於它們是不同的操作系統資源管理方式。進程有獨立的地址空間,一個進程崩潰後,在保護模式下不會對其它進程產生影響,而線程只是一 個進程中的不同執行路徑。線程有自己的堆棧和局部變量,但線程之間沒有單獨的地址空間,一個線程死掉就等於整個進程死掉,所以多進程的程序要比多線程的程 序健壯,但在進程切換時,耗費資源較大,效率要差一些。但對於一些要求同時進行並且又要共享某些變量的併發操作,只能用線程,不能用進程。


8、堆和棧的區別?


管理方式:對於棧來講,是由編譯器自動管理,無需我們手工控制;對於堆來說,釋放工作由程序員控制,容易產生memory leak。


申請大小:


棧:在Windows下,棧是向低地址擴展的數據結構,是一塊連續的內存的區域。這句話的意思是棧頂的地址和棧的最大容量是系統預先規定好的,在 WINDOWS下,棧的大小是2M(也有的說是1M,總之是一個編譯時就確定的常數),如果申請的空間超過棧的剩餘空間時,將提示overflow。因 此,能從棧獲得的空間較小。


堆:堆是向高地址擴展的數據結構,是不連續的內存區域。這是由於系統是用鏈表來存儲的空閒內存地址的,自然是不連續的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬內存。由此可見,堆獲得的空間比較靈活,也比較大。


碎片問題:對於堆來講,頻繁的new/delete勢必會造成內存空間的不連續,從而造成大量的碎片,使程序效率降低。對於棧來講,則不會存在這個問題,因爲棧是先進後出的隊列,他們是如此的一一對應,以至於永遠都不可能有一個內存塊從棧中間彈出


分配方式:堆都是動態分配的,沒有靜態分配的堆。棧有2種分配方式:靜態分配和動態分配。靜態分配是編譯器完成的,比如局部變量的分配。動態分配由alloca函數進行分配,但是棧的動態分配和堆是不同的,他的動態分配是由編譯器進行釋放,無需我們手工實現。


分配效率:棧是機器系統提供的數據結構,計算機會在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執行,這就決定了棧的效率比較高。堆則是C/C++函數庫提供的,它的機制是很複雜的。


9、Object-C的內存管理?


1.當你使用new,alloc和copy方法創建一個對象時,該對象的保留計數器值爲1.當你不再使用該對象時,你要負責向該對象發送一條release或autorelease消息.這樣,該對象將在使用壽命結束時被銷燬.


2.當你通過任何其他方法獲得一個對象時,則假設該對象的保留計數器值爲1,而且已經被設置爲自動釋放,你不需要執行任何操作來確保該對象被清理.如果你打算在一段時間內擁有該對象,則需要保留它並確保在操作完成時釋放它.


3.如果你保留了某個對象,你需要(最終)釋放或自動釋放該對象.必須保持retain方法和release方法的使用次數相等.


10、爲什麼很多內置的類,如TableViewController的delegate的屬性是assign不是retain?


循環引用


所有的引用計數系統,都存在循環應用的問題。例如下面的引用關係:


對象a創建並引用到了對象b.


對象b創建並引用到了對象c.


對象c創建並引用到了對象b.


這時候b和c的引用計數分別是2和1。當a不再使用b,調用release釋放對b的所有權,因爲c還引用了b,所以b的引用計數爲1,b不會被釋放。b不釋放,c的引用計數就是1,c也不會被釋放。從此,b和c永遠留在內存中。


這種情況,必須打斷循環引用,通過其他規則來維護引用關係。比如,我們常見的delegate往往是assign方式的屬性而不是retain方式的屬 性,賦值不會增加引用計數,就是爲了防止delegation兩端產生不必要的循環引用。如果一個UITableViewController 對象a通 過retain獲取了UITableView對象b的所有權,這個UITableView對象b的delegate又是a,如果這個delegate是 retain方式的,那基本上就沒有機會釋放這兩個對象了。自己在設計使用delegate模式時,也要注意這點。


11、定義屬性時,什麼情況使用copy、assign、retain?


assign用於簡單數據類型,如NSInteger,double,bool,


retain和copy用於對象,


copy用於當a指向一個對象,b也想指向同樣的對象的時候,如果用assign,a如果釋放,再調用b會crash,如果用copy 的方式,a和b各自有自己的內存,就可以解決這個問題。


retain 會使計數器加一,也可以解決assign的問題。


另外:atomic和nonatomic用來決定編譯器生成的getter和setter是否爲原子操作。在多線程環境下,原子操作是必要的,否則有可能引起錯誤的結果。


加了atomic,setter函數會變成下面這樣:


if (property != newValue) {


[property release];


property = [newValue retain];


}


12、對象是什麼時候被release的?


引用計數爲0時。


autorelease實際上只是把對release的調用延遲了,對於每一個Autorelease,系統只是把該Object放入了當前的 Autorelease pool中,當該pool被釋放時,該pool中的所有Object會被調用Release。對於每一個Runloop,系統會 隱式創建一個Autorelease pool,這樣所有的release pool會構成一個象CallStack一樣的一個棧式結構,在每一個 Runloop結束時,當前棧頂的Autorelease pool會被銷燬,這樣這個pool裏的每個Object(就是autorelease的對 象)會被release。那什麼是一個Runloop呢?一個UI事件,Timer call, delegate call, 都會是一個新的 Runloop


13、iOS有沒有垃圾回收?


Objective-C 2.0也是有垃圾回收機制的,但是只能在Mac OS X Leopard 10.5 以上的版本使用。


14、tableView的重用機制?


查看UITableView頭文件,會找到NSMutableArray*  visiableCells,和 NSMutableDictnery* reusableTableCells兩個結構。visiableCells內保存當前顯示的 cells,reusableTableCells保存可重用的cells。


TableView顯示之初,reusableTableCells爲空,那麼 tableView dequeueReusableCellWithIdentifier:CellIdentifier返回nil。開始的cell都 是通過 [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] 來創建,而且cellForRowAtIndexPath只是調用最大顯示cell數的次數。


比如:有100條數據,iPhone一屏最多顯示10個cell。程序最開始顯示TableView的情況是:


1.用 [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] 創建10次cell,並給cell指定同樣的重用標識(當然,可以爲不同顯示類型的cell指定不同的標識)。並且10個cell全部都加入到 visiableCells數組,reusableTableCells爲空。


2.向下拖動tableView,當cell1完全移出屏幕,並且cell11(它也是alloc出來的,原因同上)完全顯示出來的時候。 cell11加入到visiableCells,cell1移出visiableCells,cell1加入到reusableTableCells。


3.接着向下拖動tableView,因爲reusableTableCells中已經有值,所以,當需要顯示新的 cell,cellForRowAtIndexPath再次被調用的時 候,tableView dequeueReusableCellWithIdentifier:CellIdentifier,返回cell1。 cell1加入到visiableCells,cell1移出reusableTableCells;cell2移出 visiableCells,cell2加入到reusableTableCells。之後再需要顯示的Cell就可以正常重用了。


15、ViewController 的loadView、viewDidLoad、viewDidUnload分別是什麼時候調用的,在自定義ViewCointroller時在這幾個函數中應該做什麼工作?


由init、loadView、viewDidLoad、viewDidUnload、dealloc的關係說起


init方法


在init方法中實例化必要的對象(遵從LazyLoad思想)


init方法中初始化ViewController本身


loadView方法


當view需要被展示而它卻是nil時,viewController會調用該方法。不要直接調用該方法。


如果手工維護views,必須重載重寫該方法


如果使用IB維護views,必須不能重載重寫該方法


loadView和IB構建view


你在控制器中實現了loadView方法,那麼你可能會在應用運行的某個時候被內存管理控制調用。 如果設備內存不足的時候, view 控制器會收到 didReceiveMemoryWarning的消息。 默認的實現是檢查當前控制器的view是否在使用。如果它的view不在當前正在使用的 view hierarchy裏面,且你的控制器實現了loadView方法,那麼這個view將被release, loadView方法將被再次調用 來創建一個新的view。


viewDidLoad方法


viewDidLoad 此方法只有當view從nib文件初始化的時候才被調用。


重載重寫該方法以進一步定製view


在iPhone OS 3.0及之後的版本中,還應該重載重寫viewDidUnload來釋放對view的任何索引


viewDidLoad後調用數據Model


viewDidUnload方法


當系統內存吃緊的時候會調用該方法(注:viewController沒有被dealloc)


內存吃緊時,在iPhone OS 3.0之前didReceiveMemoryWarning是釋放無用內存的唯一方式,但是OS 3.0及以後viewDidUnload方法是更好的方式


在該方法中將所有IBOutlet(無論是property還是實例變量)置爲nil(系統release view時已經將其release掉了)


在該方法中釋放其他與view有關的對象、其他在運行時創建(但非系統必須)的對象、在viewDidLoad中被創建的對象、緩存數據 等 release對象後,將對象置爲nil(IBOutlet只需要將其置爲nil,系統release view時已經將其release掉了)


一般認爲viewDidUnload是viewDidLoad的鏡像,因爲當view被重新請求時,viewDidLoad還會重新被執行


viewDidUnload中被release的對象必須是很容易被重新創建的對象(比如在viewDidLoad或其他方法中創建的對象),不要release用戶數據或其他很難被重新創建的對象


dealloc方法


viewDidUnload和dealloc方法沒有關聯,dealloc還是繼續做它該做的事情


16、ViewController的didReceiveMemoryWarning是在什麼時候調用的?默認的操作是什麼?


當程序接到內存警告時View Controller將會收到這個消息:didReceiveMemoryWarning


從iOS3.0開始,不需要重載這個函數,把釋放內存的代碼放到viewDidUnload中去。


這個函數的默認實現是:檢查controller是否可以安全地釋放它的view(這裏加粗的view指的是controller的view屬性),比如view本身沒有superview並且可以被很容易地重建(從nib或者loadView函數)。


如果view可以被釋放,那麼這個函數釋放view並調用viewDidUnload。


你可以重載這個函數來釋放controller中使用的其他內存。但要記得調用這個函數的super實現來允許父類(一般是UIVIewController)釋放view。


如果你的ViewController保存着view的子view的引用,那麼,在早期的iOS版本中,你應該在這個函數中來釋放這些引用。而在iOS3.0或更高版本中,你應該在viewDidUnload中釋放這些引用。


17、列舉Cocoa中常見的集中多線程的實現,並談談多線程安全的幾種解決辦法,一般什麼地方會用到多線程?


NSThread,GCD等。儘量用上層分裝好的方法去實現多線程而不是手動調用NSThread。


18、怎麼理解MVC,在Cocoa中MVC是怎麼實現的?


Model: 代表你的應用程序是什麼(不是怎麼展現)


Controller: 控制你的Model怎麼展現給用戶(UI邏輯)


View: Controller的奴隸。。。


1 Model,Controller,View相互通訊的規則:


Controller可以直接和Model通信


Controller也可以直接和View通信


Model和View永遠不能直接通信


iOS中View和Controller的通信是透明和固定的,主要通過outlet和action實現


View使用Delegate接口和Controller同步信息


View不直接和數據通信,使用dataSource接口從Controller處獲取數據


View的delegate和dataSource一般就是Controller


Controller負責爲View翻譯和格式化Model的數據


Model使用Notification & KVO的方式分發數據更新信息,Controller可以有選擇的監聽自己感興趣的信息。


View也可以監聽廣播信息,但一般不是Model發出的信息


一個完整的App就是很多MVC的集合


19、delegate和notification區別,分別在什麼情況下使用?


Delegate:


消息的發送者(sender)告知接收者(receiver)某個事件將要發生,delegate同意然然後發送者響應事件,delegate機制使得接收者可以改變發送者的行爲。通常發送者和接收者的關係是直接的一對多的關係。


Notification:


消息的發送者告知接收者事件已經發生或者將要發送,僅此而已,接收者並不能反過來影響發送者的行爲。通常發送者和接收者的關係是間接的多對多關係。


1. 效率肯定是delegate比nsnotification高。


2. delegate方法比notification更加直接,最典型的特徵是,delegate方法往往需要關注返回值,也就是delegate方法 的結果。比如-windowShouldClose:,需要關心返回的是yes還是no。所以delegate方法往往包含should這個很傳神的詞。 也就是好比你做我的delegate,我會問你我想關閉窗口你願意嗎?你需要給我一個答案,我根據你的答案來決定如何做下一步。相反 的,notification最大的特色就是不關心接受者的態度,我只管把通告放出來,你接受不接受就是你的事情,同時我也不關心結果。所以 notification往往用did這個詞彙,比如NSWindowDidResizeNotification,那麼nswindow對象放出這個 notification後就什麼都不管了也不會等待接受者的反應。


1)兩個模塊之間聯繫不是很緊密,就用notification傳值,例如多線程之間傳值用notificaiton。


2)delegate只是一種較爲簡單的回調,且主要用在一個模塊中,例如底層功能完成了,需要把一些值傳到上層去,就事先把上層的函數通過 delegate傳到底層,然後在底層call這個delegate,它們都在一個模塊中,完成一個功能,例如 說 NavgationController 從 B 界面到A 點返回按鈕 (調用popViewController方法) 可以用delegate 比較好。


別走開,下頁更精彩




20、self.跟self什麼區別?


21、id、nil代表什麼?


id和void *並非完全一樣。在上面的代碼中,id是指向struct objc_object的一個指針,這個意思基本上是說,id是一個指向任何 一個繼承了Object(或者NSObject)類的對象。需要注意的是id是一個指針,所以你在使用id的時候不需要加星號。比如id foo=nil 定義了一個nil指針,這個指針指向NSObject的一個任意子類。而id *foo=nil則定義了一個指針,這個指針指向另一個指針,被指向的這個 指針指向NSObject的一個子類。


nil和C語言的NULL相同,在objc/objc.h中定義。nil表示一個Objctive-C對象,這個對象的指針指向空(沒有東西就是空)。


首字母大寫的Nil和nil有一點不一樣,Nil定義一個指向空的類(是Class,而不是對象)。


SEL是“selector”的一個類型,表示一個方法的名字


Method(我們常說的方法)表示一種類型,這種類型與selector和實現(implementation)相關


IMP定義爲 id (*IMP) (id, SEL, …)。這樣說來, IMP是一個指向函數的指針,這個被指向的函數包括id(“self”指針),調用的SEL(方法名),再加上一些其他參數.說白了IMP就是實現方法。


22、內存管理 Autorelease、retain、copy、assign的set方法和含義?


1,你初始化(alloc/init)的對象,你需要釋放(release)它。例如:


NSMutableArray aArray = [[NSArray alloc] init]; 後,需要 [aArray release];


2,你retain或copy的,你需要釋放它。例如:


[aArray retain] 後,需要 [aArray release];


3,被傳遞(assign)的對象,你需要斟酌的retain和release。例如:


obj2 = [[obj1 someMethod] autorelease];


對象2接收對象1的一個自動釋放的值,或傳遞一個基本數據類型(NSInteger,NSString)時:你或希望將對象2進行retain,以防止它在被使用之前就被自動釋放掉。但是在retain後,一定要在適當的時候進行釋放。


關於索引計數(Reference Counting)的問題


retain值 = 索引計數(Reference Counting)


NSArray對象會retain(retain值加一)任何數組中的對象。當NSArray被卸載(dealloc)的時候,所有數組中的對象會被 執行一次釋放(retain值減一)。不僅僅是NSArray,任何收集類(Collection Classes)都執行類似操作。例如 NSDictionary,甚至UINavigationController。


Alloc/init建立的對象,索引計數爲1。無需將其再次retain。


[NSArray array]和[NSDate date]等“方法”建立一個索引計數爲1的對象,但是也是一個自動釋放對象。所以是本地臨時對象,那麼無所謂了。如果是打算在全Class中使用的變量(iVar),則必須retain它。


缺省的類方法返回值都被執行了“自動釋放”方法。(*如上中的NSArray)


在類中的卸載方法“dealloc”中,release所有未被平衡的NS對象。(*所有未被autorelease,而retain值爲1的)


23、類別的作用?


有時我們需要在一個已經定義好的類中增加一些方法,而不想去重寫該類。比如,當工程已經很大,代碼量比較多,或者類中已經包住很多方法,已經有其他代碼調用了該類創建對象並使用該類的方法時,可以使用類別對該類擴充新的方法。


注意:類別只能擴充方法,而不能擴充成員變量。


24、委託(舉例)


委託代理(degegate),顧名思義,把某個對象要做的事情委託給別的對象去做。那麼別的對象就是這個對象的代理,代替它來打理要做的事。反映到程序中,首先要明確一個對象的委託方是哪個對象,委託所做的內容是什麼。


委託機制是一種設計模式,在很多語言中都用到的,這只是個通用的思想,網上會有很多關於這方面的介紹。


那麼在蘋果開發過程中,用到委託的程序實現思想如下,我主要拿如何在視圖之間傳輸信息做個例子。


譬如:在兩個頁面(UIIview視圖對象)實現傳值,用委託(delegate)可以很好做到!


方法:


類A


@interface A:UIView


id transparendValueDelegate;


@property(nomatic, retain) id transparendValueDelegate;


@end


@implemtion A


@synthesize transparendValueDelegate


-(void)Function


{


NSString* value = @"hello";


//讓代理對象執行transparendValue動作


[transparendValueDelegate transparendValue: value];


}


@end


類B


@interface B:UIView


NSString* value;


@end


@implemtion B


-(void)transparendValue:(NSString*)fromValue


{


value = fromValue;


NSLog(@"the value is %@ ",value);


}


@end


//下面的設置A代理委託對象爲B


//在定義A和B類對象處:


A* a = [[A alloc] init];


B* b = [[B alloc] init];


a. transparendValueDelegate = b;//設置對象a代理爲對象b


這樣在視圖A和B之間可以通過委託來傳值!


25、retainCount?


26..屬性readwrite,readonly,assign,retain,copy,nonatomic 各是什麼作用,在那種情況下用


assign:指定setter方法用簡單的賦值,這是默認操作。你可以對標量類型(如int)使用這個屬性。你可以想象一個float,它不是一個對象,所以它不能retain、copy。


retain:指定retain應該在後面的對象上調用,前一個值發送一條release消息。你可以想象一個NSString實例,它是一個對象,而且你可能想要retain它。


copy:指定應該使用對象的副本(深度複製),前一個值發送一條release消息。基本上像retain,但是沒有增加引用計數,是分配一塊新的內存來放置它。


readonly:將只生成getter方法而不生成setter方法(getter方法沒有get前綴)。


readwrite:默認屬性,將生成不帶額外參數的getter和setter方法(setter方法只有一個參數)。


atomic:對於對象的默認屬性,就是setter/getter生成的方法是一個原子操作。如果有多個線程同時調用setter的話,不會出現某一個線程執行setter全部語句之前,另一個線程開始執行setter的情況,相關於方法頭尾加了鎖一樣。


nonatomic:不保證setter/getter的原子性,多線程情況下數據可能會有問題。


27.類變量的@protected ,@private ,@public ,@package聲明各有什麼含義


Objective-C 對存取權限的設定。也是變量的作用域。


protected 該類和所有的子類中的方法可以直接訪問這樣的變量,這是默認的。


private — 該類中的方法可以訪問這樣的變量,子類不可以。 public — 除了自己和子類中的方法外,也可以被其他類或者其他模塊中的方法所訪問。開放性最大。 package — 對於64位圖像,這樣的成員變量可以在實現這個類的圖像中隨意訪問。


28.淺拷貝和深拷貝區別是什麼


簡單的來說就是,在有指針的情況下,淺拷貝只是增加了一個指針指向已經存在的內存,而深拷貝就是增加一個指針並且申請一個新的內存,使這個增加的指針指向這個新的內存,採用深拷貝的情況下,釋放內存的時候就不會出現在淺拷貝時重複釋放同一內存的錯誤


29.Cocoa中與虛基類的概念麼?怎麼簡潔的實現


30.NSString 和 NSMutableString 有什麼區別


NSString相當於一個const char* 不可以改變。


而 NSMutableString相當於 char* 可以改變內部的內容。


31.自動釋放池跟GC有什麼區別?iPhone上有GC麼?[pool release] 和[pool drain]有什麼區別


”Autorelease Pools”(自動釋放池)在應用中的使用技巧。


1,Autorelease Pools概要


一個”Autorelease Pool”實例中“包含”其它各種調用了”autorelease”方法的對象。當它釋放時,其中所有被管理對象都會收 到”relrease”的消信。注意,同一個對象可以被多次調用”autorelease”方法,並可以放到同一個”Autorelease Pool” 中。引入這個自動釋放池機制,對象的”autorelease”方法代替”relrease”方法可以延長它的生命週期,直接到當 前”Autorelrease Pool”釋放。如果想讓此對象的生命週期超過”Autorelease Pool”,還可以再次”retain”,呵 呵,有意思吧?且讓我慢慢道來。


Cocoa總是認爲當前至少有一個”Autorelease Pool”對象是可用的。若此對象並不存在,你調用的”autorelease”的所有對象都不會被自動釋放掉,可想而知,造成內存泄露。Cocoa把這個錯誤信息寫入日誌??僅僅是爲了以後分析。


你可以用”alloc”與”init”方法創建一個”NSAutoreleasePool”對象,並且可以調用”release”或”drain” (”release”與”drain”的區別是”drain”在有GC的環境中會引起GC回收操作,”release”反之。但在非GC環境中,兩者相 同。官方的說法是爲了程序的兼容性,應該考慮用”drain”代替”release”,)方法來回收它(調用它的”autorelease” 或”retain”方法會引起異常)。在一個完整的上下文最後”Autorelease Pool”對象應該被”release”掉(在方法內或一段循環 體內創建的”Autorelease Pool”對象)。


“Autorelease Pools”的所有實例在棧中管理(我們暫時叫他“自動釋放池棧”),並且它們是可以被嵌套的(父生子,子生孫。。。子子孫 孫 ^_^)。例如,當我們創建一個”Autorelease Pool”對象後,它就被自動放到“自動釋放池棧”的棧頂。當本池對象回收時,它就隨之從 這個棧中POP掉。那麼也就是說,當任何一個對象調用”autorelease”方法後,它會被放入當前線程中當前棧頂的自動釋放池中。


接下來我們聊聊”Autorelease Pools”的嵌套問題。在你的應用中,你可以任意多的創建”Autorelease Pool”對象,而這些 對象被當前線程的“自動釋放池棧”所管理。那麼除了一個接一個的順序創建並銷燬它的情況外,還有一種使用方式,就是嵌套式的創建與使用。例如:在你的主函 數創建了一個”autorelease pool”,然後又調用了創建了”autorelease pool”實例的其它方法;或是在外循環中創建 了”Autorelease Pool”的實例,而內循環中也做了相同的事情。有意思吧,呵呵,嵌套的機制使父Pool實例釋放後,它的所有子Pool也 將釋放。但這裏還存在一些副作用,後續文章會詳細討論。


“Application kit”在一個事件循環裏會自動創建一個”autorelease pool”。像鼠標鍵的按下與釋放,所以你編寫的代碼通常不需要考慮太多這方面的事情。當然,有以下三種情況你會創建與銷燬自己的Pool實例:


1,應用不是基於”Application Kit”,像”Command-line tool”,因爲它並沒有內置的”autorelease pools”的支持。


2,創建線程,你必需在線程開始時創建一個”Autorelease Pool”實例。反之,會造成內存池露(會在以後的文章詳細說明線程與池的技巧)。


3,一個循環內創建了太多的臨時對象,你應該爲他們創建一個”Autorelease Pool”對象,並在下次循還前銷燬它們。


2,自動釋放池中的”Non-AppKit”應用


在”Non-AppKit”應用中使用自動釋放池的機制其實是相當簡單的事情。你僅僅需要在main()起始處創建”Autorelease Pool” 對象,並在結尾處釋放掉它。就像在Xcode的Foundation Tool的創建模版裏寫的一樣。這個確保你在應用生命週期內至少有一 個”Autorelease Pool”是可用的。但是,這也使所有在此期間的所有”autorelease”的對象都必需在應用結束後才被釋放。這也許 會引起在應用的使用中不斷的增長,所以,你仍然考慮在不同的作用域創建新的”Autorelease Pool”。


大多應用中都存在各種級別的循環機制。在這些應用中,你可以在每個循環內的開頭創建一個”Autorelease Pool”對象,並在結尾處釋放掉它。


例如:


void main()


{


NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];


NSArray *args = [[NSProcessInfo processInfo] arguments];


unsigned count, limit = [args count];


for (count = 0; count < limit; count++)


{


NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];


NSString *fileContents;


NSString *fileName;


fileName = [args objectAtIndex:count];


fileContents = [[[NSString alloc] initWithContentsOfFile:fileName] autorelease];


// this is equivalent to using stringWithContentsOfFile:


[loopPool release];


}


[pool drain];


exit (EXIT_SUCCESS);


}


在命令行中處理所有以參數傳來的文件。一次循環處理一個文件。在循環的開頭創建一個”NSAutoreleasePool”對象,並在循環結束時釋放掉。 因此,任何在其中創建並調用“autorelease”的對象都將添加到這個Pool實例中,當本池被釋放後,這些對象也將被回收。注意,任何在作用域內 創建的”autoreleased”對象(像”fileName”),雖然並沒有顯示的調用”autorelease”方法,但都將被當前池所管理並釋 放。


32.C和obj-c 如何混用


1)obj-c的編譯器處理後綴爲m的文件時,可以識別obj-c和c的代碼,處理mm文件可以識別obj-c,c,c++代碼,但cpp文件必須只能用c/c++代碼,而且cpp文件include的頭文件中,也不能出現obj-c的代碼,因爲cpp只是cpp


2)在mm文件中混用cpp直接使用即可,所以obj-c混cpp不是問題


3)在cpp中混用obj-c其實就是使用obj-c編寫的模塊是我們想要的。


如果模塊以類實現,那麼要按照cpp class的標準寫類的定義,頭文件中不能出現obj-c的東西,包括#import cocoa的。實現文件中,即類的實現代碼中可以使用obj-c的東西,可以import,只是後綴是mm。


如果模塊以函數實現,那麼頭文件要按c的格式聲明函數,實現文件中,c++函數內部可以用obj-c,但後綴還是mm或m。


總結:只要cpp文件和cpp include的文件中不包含obj-c的東西就可以用了,cpp混用obj-c的關鍵是使用接口,而不能直接使用實現代 碼,實際上cpp混用的是obj-c編譯後的o文件,這個東西其實是無差別的,所以可以用。obj-c的編譯器支持cpp


33.響應者鏈是什麼


響應者鏈是Application Kit事件處理架構的中心機制。它由一系列鏈接在一起的響應者對象組成,事件或者動作消息可以沿着這些對象進行傳 遞。如圖6-20顯示的那樣,如果一個響應者對象不能處理某個事件或動作-也就是說,它不響應那個消息,或者不認識那個事件,則將該消息重新發送給鏈中的 下一個響應者。消息沿着響應者鏈向上、向更高級別的對象傳遞,直到最終被處理(如果最終還是沒有被處理,就會被拋棄)。


當Application Kit在應用程序中構造對象時,會爲每個窗口建立響應者鏈。響應者鏈中的基本對象是NSWindow對象及其視圖層次。在視圖層次中級別較低的視圖將比級別更高的視圖優先獲得處理事件或動作消息的機會。NSWindow中保有一個第一響應者的引用,它通常是當前窗口中處於選擇狀態的視圖,窗口通常把響應消息的機會首先給它。對於事件消息,響應者鏈通常以發生事件的窗口對應的NSWindow對象作爲結束,雖然其它對象也可以作爲下一個響應者被加入到NSWindow對象的後面。


34..UIscrollVew用到了什麼設計模式?還能再foundation庫中找到類似的嗎?


組合模式composition,所有的container view都用了這個模式


觀察者模式observer,所有的UIResponder都用了這個模式。


模板(Template)模式,所有datasource和delegate接口都是模板模式的典型應用


33. .timer的間隔週期準嗎?爲什麼?怎樣實現一個精準的timer?


NSTimer可以精確到50-100毫秒.


NSTimer不是絕對準確的,而且中間耗時或阻塞錯過下一個點,那麼下一個點就pass過去了


此份面試題包含40個題目,是現在網上能搜索到的一個比較熱的一份,但是答案並不是很詳細和完整,基本答案來着cocoaChina,和一些自己的補充。


34.Difference between shallow copy and deep copy?


淺複製和深複製的區別?


答案:淺層複製:只複製指向對象的指針,而不復制引用對象本身。


深層複製:複製引用對象本身。


意思就是說我有個A對象,複製一份後得到A_copy對象後,對於淺複製來說,A和A_copy指向的是同一個內存資源,複製的只不過是是一個指針,對象本身資源


還是隻有一份,那如果我們對A_copy執行了修改操作,那麼發現A引用的對象同樣被修改,這其實違背了我們複製拷貝的一個思想。深複製就好理解了,內存中存在了


兩份獨立對象本身。


用網上一哥們通俗的話將就是:


淺複製好比你和你的影子,你完蛋,你的影子也完蛋


深複製好比你和你的克隆人,你完蛋,你的克隆人還活着。


別走開,下頁更精彩




35.What is advantage of categories? What is difference between implementing a category and inheritance?


類別的作用?繼承和類別在實現中有何區別?


答案:category 可以在不獲悉,不改變原來代碼的情況下往裏面添加新的方法,只能添加,不能刪除修改。


並且如果類別和原來類中的方法產生名稱衝突,則類別將覆蓋原來的方法,因爲類別具有更高的優先級。


類別主要有3個作用:


(1)將類的實現分散到多個不同文件或多個不同框架中。


(2)創建對私有方法的前向引用。


(3)向對象添加非正式協議。


繼承可以增加,修改或者刪除方法,並且可以增加屬性。


36.Difference between categories and extensions?


類別和類擴展的區別。


答案:category和extensions的不同在於後者可以添加屬性。另外後者添加的方法是必須要實現的。


extensions可以認爲是一個私有的Category。


37.Difference between protocol in objective c and interfaces in java?


oc中的協議和java中的接口概念有何不同?


答案:OC中的代理有2層含義,官方定義爲 formal和informal protocol。前者和Java接口一樣。


informal protocol中的方法屬於設計模式考慮範疇,不是必須實現的,但是如果有實現,就會改變類的屬性。


其實關於正式協議,類別和非正式協議我很早前學習的時候大致看過,也寫在了學習教程裏


“非正式協議概念其實就是類別的另一種表達方式“這裏有一些你可能希望實現的方法,你可以使用他們更好的完成工作”。


這個意思是,這些是可選的。比如我門要一個更好的方法,我們就會申明一個這樣的類別去實現。然後你在後期可以直接使用這些更好的方法。


這麼看,總覺得類別這玩意兒有點像協議的可選協議。"


現在來看,其實protocal已經開始對兩者都統一和規範起來操作,因爲資料中說“非正式協議使用interface修飾“,


現在我們看到協議中兩個修飾詞:“必須實現(@requied)”和“可選實現(@optional)”。


38.What are KVO and KVC?


答案:kvc:鍵 - 值編碼是一種間接訪問對象的屬性使用字符串來標識屬性,而不是通過調用存取方法,直接或通過實例變量訪問的機制。


很多情況下可以簡化程序代碼。apple文檔其實給了一個很好的例子。


kvo:鍵值觀察機制,他提供了觀察某一屬性變化的方法,極大的簡化了代碼。


具體用看到嗯哼用到過的一個地方是對於按鈕點擊變化狀態的的監控。


比如我自定義的一個button


[cpp]


[self addObserver:self forKeyPath:@"highlighted" options:0 context:nil];


#pragma mark KVO


- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context


{


([keyPath isEqualToString:@"highlighted"] ) {


[self setNeedsDisplay];


}


}


對於系統是根據keypath去取的到相應的值發生改變,理論上來說是和kvc機制的道理是一樣的。


對於kvc機制如何通過key尋找到value:


“當通過KVC調用對象時,比如:[self valueForKey:@”someKey”]時,程序會自動試圖通過幾種不同的方式解析這個調用。首先 查找對象是否帶有 someKey 這個方法,如果沒找到,會繼續查找對象是否帶有someKey這個實例變量(iVar),如果還沒有找到,程序會繼續 試圖調用 -(id) valueForUndefinedKey:這個方法。如果這個方法還是沒有被實現的話,程序會拋出一個 NSUndefinedKeyException異常錯誤。


(cocoachina.com注:Key-Value Coding查找方法的時候,不僅僅會查找someKey這個方法,還會查找 getsomeKey這個方法,前面加一個get,或者_someKey以及_getsomeKey這幾種形式。同時,查找實例變量的時候也會不僅僅查找 someKey這個變量,也會查找_someKey這個變量是否存在。)


設計valueForUndefinedKey:方法的主要目的是當你使用-(id)valueForKey方法從對象中請求值時,對象能夠在錯誤發生前,有最後的機會響應這個請求。這樣做有很多好處,下面的兩個例子說明了這樣做的好處。“


來至cocoa,這個說法應該挺有道理。


因爲我們知道button卻是存在一個highlighted實例變量.因此爲何上面我們只是add一個相關的keypath就行了,


可以按照kvc查找的邏輯理解,就說的過去了。


39.What is purpose of delegates?


代理的作用?


答案:代理的目的是改變或傳遞控制鏈。允許一個類在某些特定時刻通知到其他類,而不需要獲取到那些類的指針。可以減少框架複雜度。


另外一點,代理可以理解爲java中的回調監聽機制的一種類似。


40.What are mutable and immutable types in Objective C?


oc中可修改和不可以修改類型。


答案:可修改不可修改的集合類。這個我個人簡單理解就是可動態添加修改和不可動態添加修改一樣。


比如NSArray和NSMutableArray。前者在初始化後的內存控件就是固定不可變的,後者可以添加等,可以動態申請新的內存空間。


41.When we call objective c is runtime language what does it mean?


我們說的oc是動態運行時語言是什麼意思?


答案:多態。 主要是將數據類型的確定由編譯時,推遲到了運行時。


這個問題其實淺涉及到兩個概念,運行時和多態。


簡單來說,運行時機制使我們直到運行時纔去決定一個對象的類別,以及調用該類別對象指定方法。


多態:不同對象以自己的方式響應相同的消息的能力叫做多態。意思就是假設生物類(life)都用有一個相同的方法-eat;


那人類屬於生物,豬也屬於生物,都繼承了life後,實現各自的eat,但是調用是我們只需調用各自的eat方法。


也就是不同的對象以自己的方式響應了相同的消息(響應了eat這個選擇器)。


因此也可以說,運行時機制是多態的基礎?~~~


42.what is difference between NSNotification and protocol?


通知和協議的不同之處?


答案:協議有控制鏈(has-a)的關係,通知沒有。


首先我一開始也不太明白,什麼叫控制鏈(專業術語了~)。但是簡單分析下通知和代理的行爲模式,我們大致可以有自己的理解


簡單來說,通知的話,它可以一對多,一條消息可以發送給多個消息接受者。


代理按我們的理解,到不是直接說不能一對多,比如我們知道的明星經濟代理人,很多時候一個經濟人負責好幾個明星的事務。


只是對於不同明星間,代理的事物對象都是不一樣的,一一對應,不可能說明天要處理A明星要一個發佈會,代理人發出處理發佈會的消息後,別稱B的


發佈會了。但是通知就不一樣,他只關心發出通知,而不關心多少接收到感興趣要處理。


因此控制鏈(has-a從英語單詞大致可以看出,單一擁有和可控制的對應關係。


43.What is push notification?


什麼是推送消息?


答案:太簡單,不作答~~~~~~~~~~


這是cocoa上的答案。


其實到不是說太簡單,只是太泛泛的一個概念的東西。就好比說,什麼是人。


推送通知更是一種技術。


簡單點就是客戶端獲取資源的一種手段。


普通情況下,都是客戶端主動的pull。


推送則是服務器端主動push。


44.Polymorphism?


關於多態性


答案:多態,子類指針可以賦值給父類。


這個題目其實可以出到一切面嚮對象語言中,


因此關於多態,繼承和封裝基本最好都有個自我意識的理解,也並非一定要把書上資料上寫的能背出來。


最重要的是轉化成自我理解。


45.Singleton?


對於單例的理解


答案:11,12題目其實出的有點泛泛的感覺了,可能說是編程語言需要或是必備的基礎。


基本能用熟悉的語言寫出一個單例,以及可以運用到的場景或是你編程中碰到過運用的此種模式的框架類等。


進一步點,考慮下如何在多線程訪問單例時的安全性。


46.What is responder chain?


說說響應鏈


答案: 事件響應鏈。包括點擊事件,畫面刷新事件等。在視圖棧內從上至下,或者從下之上傳播。


可以說點事件的分發,傳遞以及處理。具體可以去看下touch事件這塊。因爲問的太抽象化了


嚴重懷疑題目出到越後面就越籠統。


47.Difference between frame and bounds?


frame和bounds有什麼不同?


答案:frame指的是:該view在父view座標系統中的位置和大小。(參照點是父親的座標系統)


bounds指的是:該view在本身座標系統中 的位置和大小。(參照點是本身座標系統)


48.Difference between method and selector?


方法和選擇器有何不同?


答案:selector是一個方法的名字,method是一個組合體,包含了名字和實現.


詳情可以看apple文檔。


49.Is there any garbage collection mechanism in Objective C.?


OC的垃圾回收機制?


答案: OC2.0有Garbage collection,但是iOS平臺不提供。


一般我們瞭解的objective-c對於內存管理都是手動操作的,但是也有自動釋放池。


但是差了大部分資料,貌似不要和arc機制搞混就好了。


求更多~~


50.NSOperation queue?


答案:存放NSOperation的集合類。


操作和操作隊列,基本可以看成java中的線程和線程池的概念。用於處理ios多線程開發的問題。


網上部分資料提到一點是,雖然是queue,但是卻並不是帶有隊列的概念,放入的操作並非是按照嚴格的先進現出。


這邊又有個疑點是,對於隊列來說,先進先出的概念是Afunc添加進隊列,Bfunc緊跟着也進入隊列,Afunc先執行這個是必然的,


但是Bfunc是等Afunc完全操作完以後,B纔開始啓動並且執行,因此隊列的概念離亂上有點違背了多線程處理這個概念。


但是轉念一想其實可以參考銀行的取票和叫號系統。


因此對於A比B先排隊取票但是B率先執行完操作,我們亦然可以感性認爲這還是一個隊列。


但是後來看到一票關於這操作隊列話題的文章,其中有一句提到


“因爲兩個操作提交的時間間隔很近,線程池中的線程,誰先啓動是不定的。”


瞬間覺得這個queue名字有點忽悠人了,還不如pool~


綜合一點,我們知道他可以比較大的用處在於可以幫組多線程編程就好了。


51.What is lazy loading?


答案:懶漢模式,只在用到的時候纔去初始化。


也可以理解成延時加載。


我覺得最好也最簡單的一個列子就是tableView中圖片的加載顯示了。


一個延時載,避免內存過高,一個異步加載,避免線程堵塞。


52.Can we use two tableview controllers on one viewcontroller?


是否在一個視圖控制器中嵌入兩個tableview控制器?


答案:一個視圖控制只提供了一個View視圖,理論上一個tableViewController也不能放吧,


只能說可以嵌入一個tableview視圖。當然,題目本身也有歧義,如果不是我們定性思維認爲的UIViewController,


而是宏觀的表示視圖控制者,那我們倒是可以把其看成一個視圖控制者,它可以控制多個視圖控制器,比如TabbarController


那樣的感覺。


53.Can we use one tableview with two different datasources? How you will achieve this?


一個tableView是否可以關聯兩個不同的數據源?你會怎麼處理?


答案:首先我們從代碼來看,數據源如何關聯上的,其實是在數據源關聯的代理方法裏實現的。


因此我們並不關心如何去關聯他,他怎麼關聯上,方法只是讓我返回根據自己的需要去設置如相關的數據源。


因此,我覺得可以設置多個數據源啊,但是有個問題是,你這是想幹嘛呢?想讓列表如何顯示,不同的數據源分區塊顯示?



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章