七、內存管理
1.objc的內存管理簡介
(1)如果您通過分配和初始化(比如[[MyClass alloc] init])的方式來創建對象,您就擁有這個對象,需要負責該對象的釋放。這個規則在使用NSObject的便利方法new時也同樣適用。
(2)如果您拷貝一個對象,您也擁有拷貝得到的對象,需要負責該對象的釋放。
(3)如果您保持一個對象,您就部分擁有這個對象,需要在不再使用時釋放該對象。
(4)通過alloc,new, copy, retain的對象,retainCount+1;release或者autorelease后retainCount-1,如果retainCount為0時,對象會被消毀,dealloc方法被調用。
(5)誰擁有,誰管理;
2.什么是retain count?
答:引用計數(ref count或者retain count)。對象的內部保存一個數字,表示被引用的次數。
例如,某個對象被兩個指針所指向(引用)那么它的retain count為2。需要銷毀對象的時候,不直接調用dealloc,而是調用release。release會讓retain count減1,只有retain count等于0,系統才會調用dealloc真正銷毀這個對象。
3.自動釋放池是什么,如何工作?
答:當您向一個對象發送一個autorelease消息時,Cocoa就會將該對象的一個引用放入到最新的自動釋放池。它仍然是個正當的對象,因此自動釋放池定義的作用域內的其它對象可以向它發送消息。當程序執行到作用域結束的位置時,自動釋放池就會被釋放,池中的所有對象也就被釋放。
4.autorelease的對象是在什么時候被release的?
答:autorelease實際上只是把對release的調用延遲了,對于每一個Autorelease,系統只是把該Object放入了當前的Autorelease pool中,當該pool被釋放時,該pool中的所有Object會被調用Release。
對于每一個Runloop,系統會隱式創建一個Autorelease pool,這樣所有的release pool會構成一個象CallStack一樣的一個棧式結構,在每一個Runloop結束時,當前棧頂的Autorelease pool會被銷毀,這樣這個pool里的每個Object(就是autorelease的對象)會被release。
5.那什么是一個Runloop呢?
一個UI事件,Timer call,delegate call,都會是一個新的Runloop。
6.以下每行代碼執行后,person對象的retain count分別是多少
Person *person = [[Person alloc] init]; count 1
[person retain]; count 2
[person release];count 1
[person release];retain count = 1;
7.下面代碼中obj2是否需要dealloc?
ClassA *obj1 = [[ClassA alloc] init];
ClassA *obj2 = obj1;
[obj1 hello]; //輸出hello
[obj1 release];
[obj2 hello]; //程序能否執行到這一行?
[obj2 release];
答不需要他和obj2指向的是同一塊空間
8.看下面的程序,第一個NSLog會輸出什么?這時str的retainCount是多少?第二個和第三個呢?為什么?
NSMutableArray* ary = [[NSMutableArray array] retain];
NSString *str = [NSString stringWithFormat:@"test"];
[str retain];
[ary addObject:str];
NSLog(@”%@%d”,str,[str retainCount]);
[str retain];
[str release];
[str release];
NSLog(@”%@%d”,str,[str retainCount]);
[ary removeAllObjects];
NSLog(@”%@%d”,str,[str retainCount]);
答:
str的retainCount創建+1,retain+1,加入數組自動+1
3
retain+1,release-1,release-1
2
數組刪除所有對象,所有數組內的對象自動-1
1
9.autorelease和垃圾回收機制(gc)有什么關系?
答:autorelase是用代碼手寫,在eventloop結束后被釋放。
垃圾回收機制開啟的話,你只用alloc,不用release,它會自動偵測一些你不用的對象,將它release掉。
可能在實現方式上或者說release的時機判斷上有不同,但是效果都是自動relase這個對象。
10.IPhone OS有沒有垃圾回收(gc)?
沒有。iPhone開發的時候沒有垃圾回收機制,OC支持gc,但只限制在Mac OS上。
11.這段代碼有什么問題,如何修改
for (int i = 0; i < someLargeNumber; i++)
{
NSString *string = @”Abc”;
string = [string lowercaseString];
string = [string stringByAppendingString:@"xyz"];
NSLog(@“%@”, string);
}
答:同時生成了大量autorelease對象,不利于內存管理。但是如果放在子線程的話,而且沒有開啟垃圾回收機制的話,則會造成內存泄露。
修改一:
for(int i = 0; i
NSAutoreleasePool * pool1 = [[NSAutoreleasePool alloc] init];
NSString *string = @"Abc";
string = [string lowercaseString];
string = [string stringByAppendingString:@"xyz"];
NSLog(@"%@",string);
[pool1 drain];
}
修改二:
NSAutoreleasePool * pool1 = [[NSAutoreleasePool alloc] init];
for(int i = 0; i
NSString *string = @"Abc";
string = [string lowercaseString];
string = [string stringByAppendingString:@"xyz"];
NSLog(@"%@",string);
}
[pool1 drain];
一點說明:
修改一的autoreleasePool的建立方法是考慮在如果每次循環生成大量的autorelease對象,這些對象占用很大內存的情況下,循環了1000次,那么這些所有的內存加起來就已經夠程序崩潰了,那么這時候加在循環里面可以避免程序崩潰。
但是如果程序循環1000次生成的內存也不是很多,則可以用方法二,提高效率。
[pool drain]和[pool release]在沒有垃圾回收機制的情況下,他們的效果是一樣的。但是如果做mac開發而且開啟了垃圾回收機制的話,要用drain而不是release,因為那種情況下用release只是把pool這個對象清理了,而pool里面的對象是沒有被清理掉的。
附:CoreFoundation部分
1)create,copy會形成own關系,不需要時應該CFRelease();
2) get方式得到的object,不形成own關系,不需要管理;
3)一個object作為參數傳遞到函數中后,receiver不與他形成own關系,也就是可能在任何時間被deallocate掉,所以需要CFRetain();
4)CFIndex count = CFGetRetainCount(obj);
5) myCFObj1 = myCFObj2-->引用拷貝,不會生成2個對象,應該使用CFStringCreatCopy()
6)符合的CF對象,copy時需要自己實現deep copy;
八、CocoaTouch
1.main.m中都發生了什么?
答:程序入口,創建自動釋放池,創建應用程序對象,并啟動其主循環,運行程序,釋放程序運行期間得所有加入自動釋放池的對象。
2.int retVal = UIApplicationMain(argc, argv, nil, nil);是什么意思?
答:對UIApplication對象進行了初始化,這個方法除了argc和argv參數外,另外這個函數還有兩個字符串參數來識別UIApplication類和UIApplication代理類,在這里默認是2個nil,第一個參數為nil就默認把UIApplication類作為缺省值進行初始化,可以在這里不填nil而是使用自己定義的UIApplication子類。至于第二個參數nil就設置為nil就把模板生成的HelloWorldAppdelegate類作為默認值。
3.編寫NSArray的setter和getter.
答:getter比較容易,直接返回NSArray的指針就可以了,
setter注意每個元素加進去得時候需要retain一次。
4.什么是Notification?答:觀察者模式,controller向defaultNotificationCenter添加自己的notification,其他類注冊這個notification就可以收到通知,這些類可以在收到通知時做自己的操作(多觀察者默認隨機順序發通知給觀察者們,而且每個觀察者都要等當前的某個觀察者的操作做完才能輪到他來操作,可用NotificationQueue的方式安排觀察者的反應順序,也可以在添加觀察者中設定反映時間,取消觀察需要在viewDidUnload跟dealloc中都要注銷)。
5.多線程編程中,NSThread子線程與主線程的交互.
答:子線程內執行[self performSelectorOnMainThread:@selector(function:)withObject:];通知主線程執行相應方法。或者用全局變量的方式。
6.objective-c中是所有對象間的交互是如何實現的?(深圳皆凱科技有限公司筆試題)
答:在Objective-C中所有對象間的交互都是通過指針實現的,確切的說話,叫做發送消息。
8.objective-c中是如何實現線程同步的?
答:關鍵字@synchronized()
7.id聲明的對象有什么特性?
答:id聲明的對象具有運行時的特性,即可以指向任意類型的objcetive-c的對象;
8.cocoa touch框架
iPhone OS應用程序的基礎Cocoa Touch框架重用了許多Mac系統的成熟模式,但是它更多地專注于觸摸的接口和優化。UIKit為您提供了在iPhone OS上實現圖形,事件驅動程序的基本工具,其建立在和Mac OS X中一樣的Foundation框架上,包括文件處理,網絡,字符串操作等。
Cocoa Touch具有和iPhone用戶接口一致的特殊設計。有了UIKit,您可以使用iPhone OS上的獨特的圖形接口控件,按鈕,以及全屏視圖的功能,您還可以使用加速儀和多點觸摸手勢來控制您的應用。
各色俱全的框架除了UIKit外,Cocoa Touch包含了創建世界一流iPhone應用程序需要的所有框架,從三維圖形,到專業音效,甚至提供設備訪問API以控制攝像頭,或通過GPS獲知當前位置。Cocoa Touch既包含只需要幾行代碼就可以完成全部任務的強大的Objective-C框架,也在需要時提供基礎的C語言API來直接訪問系統。這些框架包括:
Core Animation
通過Core Animation,您就可以通過一個基于組合獨立圖層的簡單的編程模型來創建豐富的用戶體驗。
Core Audio
Core Audio是播放,處理和錄制音頻的專業技術,能夠輕松為您的應用程序添加強大的音頻功能。
Core Data
提供了一個面向對象的數據管理解決方案,它易于使用和理解,甚至可處理任何應用或大或小的數據模型。
功能列表:框架分類
下面是Cocoa Touch中一小部分可用的框架:
音頻和視頻
Core Audio
OpenAL
Media Library
AV Foundation
數據管理
Core Data
SQLite
圖形和動畫
Core Animation
OpenGL ES
Quartz 2D
網絡/li>
Bonjour
WebKit
BSD Sockets
用戶應用
Address Book
Core Location
Map Kit
Store Kit
九、設計模式
1.MVC模式的理解
MVC設計模式考慮三種對象:模型對象、視圖對象、和控制器對象。模型對象代表特別的知識和專業技能,它們負責保有應用程序的數據和定義操作數據的邏輯。視圖對象知道如何顯示應用程序的模型數據,而且可能允許用戶對其進行編輯。控制器對象是應用程序的視圖對象和模型對象之間的協調者。
2.描述一下iOS SDK中如何實現MVC的開發模式
MVC是模型、視圖、控制開發模式,對于iOS SDK,所有的View都是視圖層的,它應該獨立于模型層,由視圖控制層來控制。所有的用戶數據都是模型層,它應該獨立于視圖。所有的ViewController都是控制層,由它負責控制視圖,訪問模型數據。
3.類工廠方法是什么
類工廠方法的實現是為了向客戶提供方便,它們將分配和初始化合在一個步驟中,返回被創建的對象,并進行自動釋放處理。這些方法的形式是+ (type)className…(其中className不包括任何前綴)。
工廠方法可能不僅僅為了方便使用。它們不但可以將分配和初始化合在一起,還可以為初始化過程提供對象的分配信息。
類工廠方法的另一個目的是使類(比如NSWorkspace)提供單件實例。雖然init…方法可以確認一個類在每次程序運行過程只存在一個實例,但它需要首先分配一個“生的”實例,然后還必須釋放該實例。
工廠方法則可以避免為可能沒有用的對象盲目分配內存。
4.單件實例是什么
Foundation和Application Kit框架中的一些類只允許創建單件對象,即這些類在當前進程中的唯一實例。舉例來說,NSFileManager和NSWorkspace類在使用時都是基于進程進行單件對象的實例化。當向這些類請求實例的時候,它們會向您傳遞單一實例的一個引用,如果該實例還不存在,則首先進行實例的分配和初始化。單件對象充當控制中心的角色,負責指引或協調類的各種服務。如果類在概念上只有一個實例(比如
NSWorkspace),就應該產生一個單件實例,而不是多個實例;如果將來某一天可能有多個實例,您可以使用單件實例機制,而不是工廠方法或函數。
十、操作系統
1.線程與進程的區別和聯系?
答:進程和線程都是由操作系統所體會的程序運行的基本單元,系統利用該基本單元實現系統對應用的并發性。
進程和線程的主要差別在于它們是不同的操作系統資源管理方式。進程有獨立的地址空間,一個進程崩潰后,在保護模式下不會對其它進程產生影響,而線程只是一個進程中的不同執行路徑。線程有自己的堆棧和局部變量,但線程之間沒有單獨的地址空間,一個線程死掉就等于整個進程死掉,所以多進程的程序要比多線程的程序健壯,但在進程切換時,耗費資源較大,效率要差一些。但對于一些要求同時進行并且又要共享某些變量的并發操作,只能用線程,不能用進程。
2.列舉幾種進程的同步機制,并比較其優缺點。
答案:原子操作信號量機制自旋鎖管程,會合,分布式系統
進程之間通信的途徑
答案:共享存儲系統消息傳遞系統管道:以文件系統為基礎
進程死鎖的原因
答案:資源競爭及進程推進順序非法
死鎖的4個必要條件
答案:互斥、請求保持、不可剝奪、環路
死鎖的處理
答案:鴕鳥策略、預防策略、避免策略、檢測與解除死鎖
3.堆和棧的區別
管理方式:對于棧來講,是由編譯器自動管理,無需我們手工控制;對于堆來說,釋放工作由程序員控制,容易產生memory leak。
申請大小:
棧:在Windows下,棧是向低地址擴展的數據結構,是一塊連續的內存的區域。這句話的意思是棧頂的地址和棧的最大容量是系統預先規定好的,在WINDOWS下,棧的大小是2M(也有的說是1M,總之是一個編譯時就確定的常數),如果申請的空間超過棧的剩余空間時,將提示overflow。因此,能從棧獲得的空間較小。
堆:堆是向高地址擴展的數據結構,是不連續的內存區域。這是由于系統是用鏈表來存儲的空閑內存地址的,自然是不連續的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限于計算機系統中有效的虛擬內存。由此可見,堆獲得的空間比較靈活,也比較大。
碎片問題:對于堆來講,頻繁的new/delete勢必會造成內存空間的不連續,從而造成大量的碎片,使程序效率降低。對于棧來講,則不會存在這個問題,因為棧是先進后出的隊列,他們是如此的一一對應,以至于永遠都不可能有一個內存塊從棧中間彈出
分配方式:堆都是動態分配的,沒有靜態分配的堆。棧有2種分配方式:靜態分配和動態分配。靜態分配是編譯器完成的,比如局部變量的分配。動態分配由alloca函數進行分配,但是棧的動態分配和堆是不同的,他的動態分配是由編譯器進行釋放,無需我們手工實現。
分配效率:棧是機器系統提供的數據結構,計算機會在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執行,這就決定了棧的效率比較高。堆則是C/C++函數庫提供的,它的機制是很復雜的。
十一、雜項
1.動態綁定
—在運行時確定要調用的方法
動態綁定將調用方法的確定也推遲到運行時。在編譯時,方法的調用并不和代碼綁定在一起,只有在消實發送出來之后,才確定被調用的代碼。通過動態類型和動態綁定技術,您的代碼每次執行都可以得到不同的結果。運行時因子負責確定消息的接收者和被調用的方法。運行時的消息分發機制為動態綁定提供支持。當您向一個動態類型確定了的對象發送消息時,運行環境系統會通過接收者的isa指針定位對象的類,并以此為起點確定被調用的方法,方法和消息是動態綁定的。而且,您不必在Objective-C代碼中做任何工作,就可以自動獲取動態綁定的好處。您在每次發送消息時,
特別是當消息的接收者是動態類型已經確定的對象時,動態綁定就會例行而透明地發生。
2.目標-動作機制
目標是動作消息的接收者。一個控件,或者更為常見的是它的單元,以插座變量(參見”插座變量”部分)的形式保有其動作消息的目標。
動作是控件發送給目標的消息,或者從目標的角度看,它是目標為了響應動作而實現的方法。
程序需要某些機制來進行事件和指令的翻譯。這個機制就是目標-動作機制。
3.什么是鍵-值,鍵路徑是什么
模型的性質是通過一個簡單的鍵(通常是個字符串)來指定的。視圖和控制器通過鍵來查找相應的屬性值。在一個給定的實體中,同一個屬性的所有值具有相同的數據類型。鍵-值編碼技術用于進行這樣的查找—它是一種間接訪問對象屬性的機制。
鍵路徑是一個由用點作分隔符的鍵組成的字符串,用于指定一個連接在一起的對象性質序列。第一個鍵的性質是由先前的性質決定的,接下來每個鍵的值也是相對于其前面的性質。鍵路徑使您可以以獨立于模型實現的方式指定相關對象的性質。通過鍵路徑,您可以指定對象圖中的一個任意深度的路徑,使其指向相關對象的特定屬性。
4.什么時候用delegate,什么時候用Notification?
答:delegate針對one-to-one關系,并且reciever可以返回值給sender,
notification可以針對one-to-one/many/none,reciever無法返回值給sender.
所以,delegate用于sender希望接受到reciever的某個功能反饋值,notification用于通知多個object某個事件。
5.什么是KVC和KVO?
答:KVC(Key-Value-Coding)內部的實現:一個對象在調用setValue的時候,(1)首先根據方法名找到運行方法的時候所需要的環境參數。(2)他會從自己isa指針結合環境參數,找到具體的方法實現的接口。(3)再直接查找得來的具體的方法實現。
KVO(Key-Value-Observing):當觀察者為一個對象的屬性進行了注冊,被觀察對象的isa指針被修改的時候,isa指針就會指向一個中間類,而不是真實的類。所以isa指針其實不需要指向實例對象真實的類。所以我們的程序最好不要依賴于isa指針。在調用類的方法的時候,最好要明確對象實例的類名。
其它回答:
kvc就是key value coding,簡而言之就是根據key值改變它的內容,我覺得很類似于dictionary。
kvo就是Key Value Observing,就是相當于你監控特定對象的特定key,當key對應的值發生改變時,會觸發它的對應方法。
kvc實現(NSKeyValueCoding Protocol),最簡單的方法就是setValue: forKey:以及valueForKey:方法。例如你實現一個Person類,有兩個property name,age,生成一個新對象p,可以用[p setValue:@"Solomon" forKey:@"name"];這樣的方法進行賦值。
kvo實現(NSKeyValueObserving Protocol),–addObserver:forKeyPath:options:context:對你想要監控的對象,想要監控的屬性添加一個observe,當值改變時,會觸發– willChangeValueForKey:等方法。
kvc kvo結合使用,可以當作對對象屬性值進行監控的一個notification,它對值進行監控。而notification也同時可以對消息響應之類做出監控。
簡單說KVC就是一個實現并擴展了setter/getter的方法集。
6.Notification和KVO有什么不同?
KVO就是給屬性添加一個監控器,當值發生改變的時候,給你一個接口去處理它。textView用過吧,當textView的值改變時,不也有一個textViewDidChange:的delegate方法么?
它就是一個NSObject的protocol,本來就是一個很簡單的東西,不要想的很復雜化。這些東西的提出只是為了更方便,而不是它有什么特殊的含義,正如MVC一樣。
notification也就是在程序檢測event的loop里面加上一個跟蹤事件的判斷,如果接收到了這個事件,則做自己想要去做的事情。比如一個uiview的對象接收到一個觸摸事件,它在系統檢測event的無限循環里接收到了它,然后返回一個uitouch的事件讓你去處理,從根本上來說它和notification的性質一樣的,雖然可能實現方式不盡相同,但是總歸是跳不出這個圈子的。
當然,再往底層的東西,怎么去傳遞notification之類,蘋果封裝好了,你也不可能知道。就算你是蘋果的程序員,由你來實現,也可能有不同的方式來達到同樣的目的。而這個已經超出了sdk編程的范圍。