37.cocoa內(nèi)存管理規(guī)則
1)當(dāng)你使用new,alloc或copy方法創(chuàng)建一個對象時,該對象的保留計數(shù)器值為1。當(dāng)不再使用該對象時,你要負責(zé)向該對象發(fā)送一條release或autorelease消息。這樣,該對象將在其使用壽命結(jié)束時被銷毀。
2)當(dāng)你通過任何其他方法獲得一個對象時,則假設(shè)該對象的保留計數(shù)器值為1,而且已經(jīng)被設(shè)置為自動釋放,你不需要執(zhí)行任何操作來確保該對象被清理。如果你打算在一段時間內(nèi)擁有該對象,則需要保留它并確保在操作完成時釋放它。
3)如果你保留了某個對象,你需要(最終)釋放或自動釋放該對象。必須保持retain方法和release方法的使用次數(shù)相同。
38.清理自動釋放池
由于自動釋放池的銷毀時間是完全確立的,所以它在循環(huán)執(zhí)行過程中不會被銷毀。在迭代中或者循環(huán)中,需要建立自己的自動釋放池。
39.垃圾回收gc
自動內(nèi)存管理機制。objective-c的垃圾回收器是一種繼承性的垃圾回收器。與那些已經(jīng)存在了一段時間的對象相比,新創(chuàng)建的對象更可能被當(dāng)成 垃圾。 垃圾回收器定期檢查變量和對象以及他們之間的指針,當(dāng)發(fā)現(xiàn)沒有任何變量指向某個對象時,就將該對象視為應(yīng)該被丟棄的垃圾。如果你再一個實例變量中指向某個 對象,一定要在某個時候使該實例變量賦值為nil,以取消對該對象的引用并使垃圾回收器知道該對象可以被清理了。
與自動釋放池一樣,垃圾回收器也是在時間循環(huán)結(jié)束時才觸發(fā)。
ARC是什么?
ARC是iOS 5推出的新功能,全稱叫 ARC(Automatic Reference Counting)。簡單地說,就是代碼中自動加入了retain/release,原先需要手動添加的用來處理內(nèi)存管理的引用計數(shù)的代碼可以自動地由編譯器完成了。
該機能在 iOS 5/ Mac OS X 10.7 開始導(dǎo)入,利用 Xcode4.2 可以使用該機能。簡單地理解ARC,就是通過指定的語 法,讓編 譯器(LLVM 3.0)在編譯代碼時,自動生成實例的引用計數(shù)管理部分代碼。有一點,ARC并不是GC,它只是一種代碼靜態(tài)分析 (Static Analyzer)工具。
40.分配
是一個新對象誕生的過程。是從操作系統(tǒng)獲得一塊內(nèi)存并將其指定為存放對象的實例變量的位置。
40.初始化
與分配對應(yīng)的操作是初始化。初始化從操作系統(tǒng)取得一塊內(nèi)存。準備用于存儲對象。
嵌套調(diào)用技術(shù)非常重要,因為初始化方法返回的對象可能與分配的對象不同。
1)初始化時做什么?
給實例變量賦值并創(chuàng)建你得對象完成任務(wù)所需要的其他對象。
2)便利初始化函數(shù)
許多類包含便利初始化函數(shù)。用來完成某些額外的工作的初始化方法,可以減少你自己完成這些工作的麻煩。
例如:NSString類中-(id)initWithFormat:(NSString *)format,...;
3)指定初始化函數(shù)
類中的某個初始化方法被指派為指定初始化函數(shù)。該類所有初始化方法使用指定初始化函數(shù)執(zhí)行初始化操作。子類使用其超類的指定初始化函數(shù)實現(xiàn)超類的初始化。
例如:其他初始化函數(shù)通過指定初始化函數(shù)實現(xiàn)。
41.初始化函數(shù)規(guī)則
不需要為你自己的類創(chuàng)建初始化函數(shù)方法。如果不需要設(shè)置任何狀態(tài),或者只需要alloc方法將內(nèi)存清零的默認行為,則不需要擔(dān)心init。
如果構(gòu)造了一個初始化函數(shù),則一定要在你自己的指定初始化函數(shù)中調(diào)用超類的指定初始化函數(shù)。一定要將超類的初始化函數(shù)的值賦給self對象,并返回你自己的初始化方法的值。因為超類可能決定返回一個完全不同的對象。
如果初始化函數(shù)不止一個,則要選擇一個座位指定初始化函數(shù)。被選定的方法應(yīng)該調(diào)用超類指定初始化函數(shù)。要按照指定初始化函數(shù)的形式實現(xiàn)所有其他初始化函數(shù),就像我們在前面的實現(xiàn)一樣。
42.特性@property
objective-c2.0的特性只適用于mac os x 10.5或更高版本。特性主要應(yīng)用于cocoa的新組件(尤其是華麗奪目的core Animation效果)。
1)簡化接口
@property預(yù)編譯指令的作用是自動生命屬性的setter和getter方法。
2)@synthesize也是一種新的編譯器功能,表示“創(chuàng)建該屬性的訪問器”。
3)點表達式
如果點表達式出現(xiàn)在=左邊,該屬性名稱的setter方法(set方法)將被調(diào)用。如果點表達式出現(xiàn)在對象變量右邊,則該屬性名稱的getter方法(get方法)將被調(diào)用。
4)特性擴展
@property()括號里面的東西,是對應(yīng)在set方法中要添加的語句。比如我在括號里寫retain,就相當(dāng)于在它的set方法里添加了一句 [xx retain]。
@property屬性
屬性分為3類:
1.讀寫屬性(Writability)包含:readwrite / readonly
2.setter語義(Setter Semantics)包含:assign / retain / copy
3.原子性(Atomicity)包含:nonatomic
下面具體說明各個屬性的含義
readwrite / readonly:
決定是否生成set訪問器,readwrite是默認屬性,生成getter和setter方法;readonly只生成getter方法,不生成setter方法。
readonly關(guān)鍵字代表setter不會被生成, 所以它不可以和 copy/retain/assign組合使用。
assign / retain / copy:
這些屬性用于指定set訪問器的語義,也就是說,這些屬性決定了以何種方式對數(shù)據(jù)成員賦予新值。
assign:直接賦值,索引計數(shù)不改變,適用于簡單數(shù)據(jù)類型,例如:NSIngeter、CGFloat、int、char等。
retain:指針的拷貝,使用的是原來的內(nèi)存空間。對象的索引計數(shù)加1。
此屬性只能用于Objective-C對象類型,而不能用于Core Foundation對象。(原因很明顯,retain會增加對象的引用計數(shù),而基本數(shù)據(jù)類型或者Core Foundation對象都沒有引用計數(shù))。
copy:對象的拷貝,新申請一塊內(nèi)存空間,并把原始內(nèi)容復(fù)制到那片空間。新對象的索引計數(shù)為1。
此屬性只對那些實行了NSCopying協(xié)議的對象類型有效。
很多Objective-C中的object最好使用用retain,一些特別的object(例如:string)使用copy。
nonatomic:
非原子性訪問,不加同步,多線程并發(fā)訪問會提高性能。如果不加此屬性,則默認是兩個訪問方法都為原子型事務(wù)訪問。默認值是atomic,為原子操作。
(atomic是Objc使用的一種線程保護技術(shù),基本上來講,是防止在寫未完成的時候被另外一個線程讀取,造成數(shù)據(jù)錯誤。而這種機制是耗費系統(tǒng)資源的, 所以在iPhone這種小型設(shè)備上,如果沒有使用多線程間的通訊編程,那么nonatomic是一個非常好的選擇。)
5)保留周期retain cycle 引用計數(shù)器在該周期中歸零。
6)什么是屬性訪問器
屬性訪問器(Property Accessor),包括 get 訪問器和 set 訪問器分別用于字段的讀寫操作
其設(shè)計目的主要是為了實現(xiàn)面向?qū)ο螅∣O)中的封裝思想。根據(jù)該思想,字段最好設(shè)為private,一個精巧的類最好不要直接把字段設(shè)為公有提供給客戶調(diào)用端直接訪問
另外要注意屬性本身并不一定和字段相聯(lián)系
7)self.a與a的區(qū)別
self.a使編譯器知道我們期望使用訪問器訪問a。如果只使用裸名a,編譯器將假設(shè)我們直接修改了實例變量。
8)self.a = nil
這行代碼表示使用nil參數(shù)調(diào)用setName:方法。生成的訪問器方法將自動釋放以前的name對象,并使用nil替代a。該方法完成了釋放 name對 象所占用內(nèi)存的操作。當(dāng)然,也可以只釋放name對象以清理其占用的內(nèi)存。如果你再dealloc方法以外的地方清除特性,那么使用"將nil賦值給對 象"的方法可以將特性設(shè)置為nil,同時可以使我們避免對已釋放內(nèi)存的懸空引用問題。
9)特性不是萬能的
有些方法不適合特性所能涵蓋的方法的相當(dāng)狹小的范圍。特性不支持那些需要接受額外參數(shù)的方法。
43.類別@category
1)聲明類別
@interface NSString (NumberConvenience)
-(NSNumber *)lengthAsNumber;
@end
該聲明具有2個特點。首先,現(xiàn)有類位于@interface關(guān)鍵字之后,其后是位于圓括號中的一個新名稱。該聲明表示,類別的名稱是 NumberConvenience,而且該類別將向NSString類中添加方法。只要保證類別名稱的唯一性,你可以向一個類中添加任意多得類別。
其次,你可以指定希望向其添加類別的類以及類別的名稱,而且你還可以列出添加的方法,最后以@end結(jié)束。由于不能添加新實現(xiàn)變量,因此與類聲明不同的是,類別的聲明中沒有實例變量部分。
2)實現(xiàn)類別
3)類別的局限性
第一,無法向類中添加新的實例變量。類別沒有位置容納實例變量。
第二,名稱沖突,即類別中得方法與現(xiàn)有的方法重名。當(dāng)發(fā)生名稱沖突時,類別具有更高的優(yōu)先級。你得類別方法將完全取代初始方法,從而無法再使用初始方法。有些編程人員在自己的類別方法中增加一個前綴,以確保不發(fā)生名稱沖突。
有一些技術(shù)可以克服類別無法增加新實例變量的局限。例如,可以使用全局字典存儲對象與你想要關(guān)聯(lián)的額外變量之間的映射。但此時你可能需要認真考慮一下,類別是否是完成當(dāng)前任務(wù)的最佳選擇。
4)類別的作用
cocoa中得類別主要用于3個目的:第一,將類的實現(xiàn)分散到不同文件或者不同框架中。第二,創(chuàng)建對私有方法的前向引用。第三,向?qū)ο筇砑臃钦絽f(xié)議。
44.run循環(huán)是一種cocoa構(gòu)造,它一直處于阻塞狀態(tài)(即不執(zhí)行任何處理),知道某些事件發(fā)生為止。
45.響應(yīng)選擇器
一個類別如何知道其委托對象是否能夠處理那些發(fā)送給它的消息?
類別首先檢查對象,詢問其能否響應(yīng)該選擇器。如果該對象能夠響應(yīng)該選擇器,
1)選擇器@selector()
選擇器只是一個方法名稱,但它以objective-c運行時使用的特殊方式編碼,以快速執(zhí)行查詢。你可以使用@selector()預(yù)編譯指令選擇器,其中方法名位于圓括號中。
46.委托 非正式協(xié)議
47.正式協(xié)議
與非正式協(xié)議一樣,正式協(xié)議是一個命名的方法列表。但與非正式協(xié)議不同的是,正式協(xié)議要求顯式的采用協(xié)議。采用協(xié)議的辦法是在類的@interface聲明中列出協(xié)議名稱。采用協(xié)議意味著你承諾實現(xiàn)該協(xié)議的所有方法。
1)聲明協(xié)議
@protocol NSCopying
-(id)copyWithZone:(NSZone *)zone;
@end
2)采用協(xié)議
@interface Car: NSObject
{
}
@end
3)協(xié)議和數(shù)據(jù)類型
如果一個用尖括號括起來的協(xié)議名稱跟隨在id之后,則編譯器將知道你期望任意類型的對象,只要其遵守該協(xié)議。
4)objective-c2.0的新特性@optional @required
@optional可選擇實現(xiàn)的方法
@required必須實現(xiàn)的方法
因此cocoa中得非正式協(xié)議正被帶有@optional的正式協(xié)議所取代。
48.Application Kit
1)IBOutlet與IBAction
他們實際上只是APPKit提供的#defines。IBOutlet的定義沒有任何作用,因此將不會對它進行編譯。IBAction定義為 void,這 意味著在AppController中聲明的方法的返回類型將使void。IBOutlet和IBAction不執(zhí)行任何操作,他們并不是用于編譯的,實 際上他們是為Interface Builder以及閱讀代碼的人提供的標記。通過查找IBOutlet和 IBAction,Interface Builder知道AppController對象具有兩個能夠連接的實例變量。
2)IBOutlet是如何工作的
當(dāng)加載nib文件時(MainMenu.nib會在應(yīng)用程序啟動時自動加載,可以創(chuàng)建你自己的nib文件并自行加載),存儲在nib文件中得任何對 象都會 被重新創(chuàng)建。這意味著會再后臺執(zhí)行alloc和init方法。所以,當(dāng)應(yīng)用程序啟動時,會分配并初始化一個AppController實例。在執(zhí)行 init方法期間,所有IBOutlet實例變量都為nil。只有創(chuàng)建了nib文件中得所有對象(這包括窗口和文本域和按鈕),所有連接才算完成。
一旦建立了所有連接(也就是將NSTextField對象的地址添加到AppController的實例變量中),會向創(chuàng)建的每個對象發(fā)送消息 awakeFromNib。一個非常常見的錯誤是試圖在init方法中使用IBOutlet執(zhí)行一些操作。由于所有實例變量都為nil,發(fā)送給他們的所有 消息不執(zhí)行任何操作,所以在init中得任何嘗試都會發(fā)生無提示失敗。(這是Cocoa導(dǎo)致效率低和占用大量調(diào)試時間的一個方面)。如果你想知道為什么這 些操作不起作用,可以使用NSLog輸出實例變量的值,并查看他們是否都為nil。對于創(chuàng)建的對象和發(fā)送的awakeFromNib消息,都不存在預(yù)定義 順序。
文件加載與保存
49.屬性列表
1)自動釋放對象
NSDate
NSData NSData對象是不可改變的。他們被創(chuàng)建后就不能改變。可以使用他們,但不能改變其中的內(nèi)容。
2)編碼對象 編碼和解碼
cocoa具備一種機制來將對象自身轉(zhuǎn)換為某種格式并保存到磁盤中。對象可以將他們的實例變量和其他數(shù)據(jù)塊編碼為數(shù)據(jù)塊,然后保存到磁盤中。以后將這些數(shù)據(jù)塊讀回到內(nèi)存中,并且還能基于保存的數(shù)據(jù)創(chuàng)建新對象。這個過程稱為編碼和解碼。或稱為序列化和反序列化。
50.鍵/值編碼 KVC
是一種間接改變對象狀態(tài)的方式,其實現(xiàn)方法是使用字符串描述要更改的對象狀態(tài)部分。
1)valueForKey與setValue:forKey:
這兩種方法的工作方式相同。他們首先查找名稱的setter(getter)方法,如果不存在setter(getter)方法,他們將在類中查找名為名稱或_名稱的實例變量。然后給它賦值(取值)。無需通過對象指針直接訪問實例變量。
2)路徑
鍵路徑的深度是任意的,具體取決于對象圖。
鍵路徑不僅能引用對象值,還可以引用一些運算符來進行一些運算,例如獲取一組值的平均值或返回這組值中得最小值和最大值。
例如:NSNumber *count;
count = [garage valueForKeyPath:@"cars.@count"];
NSLog(@"We have %@ cars", count);
我們將路徑“cars.@count”拆開,cars用于獲取cars屬性,它是來自garage的NSArray類型的值。接下來的部分是@count ,其中@符號意味著后面將進行一些運算。
和 cars@sun.mileage
最大值 cars@min.mileage
最小值 cars@max.mileage
3)整體操作
KVC非常棒的一點是,如果向NSArray請求一個鍵值,它實際上會查詢數(shù)組中得每個對象來查找這個鍵值,然后將查詢結(jié)果打包到另一個數(shù)組中并返回給你。這種方法也適用于通過鍵路徑訪問的對象內(nèi)部的數(shù)組。
4)批處理
KVC包含兩個調(diào)用,可以使用他們對對象進行批量更改。第一個調(diào)用是dictionaryWith-ValuesForKeys:。它接受一個字符串?dāng)?shù)組。該調(diào)用獲取一些鍵,對每個鍵使用valueForKey:,然后為鍵字符串和剛才獲取的值構(gòu)建一個字典。
1、Object-C有多繼承嗎?沒有的話用什么代替?cocoa 中所有的類都是NSObject 的子類
多繼承在這里是用protocol 委托代理 來實現(xiàn)的
你不用去考慮繁瑣的多繼承 ,虛基類的概念.
ood的多態(tài)特性 在 obj-c 中通過委托來實現(xiàn).
2、Object-C有私有方法嗎?私有變量呢?
objective-c – 類里面的方法只有兩種, 靜態(tài)方法和實例方法. 這似乎就不是完整的面向?qū)ο罅?按照OO的原則就是一個對象只暴露有用的東西. 如果沒有了私有方法的話, 對于一些小范圍的代碼重用就不那么順手了. 在類里面聲名一個私有方法
@interface Controller : NSObject { NSString *something; }
- (void)thisIsAStaticMethod;
– (void)thisIsAnInstanceMethod;
@end
@interface Controller (private) -
(void)thisIsAPrivateMethod;
@end
@private可以用來修飾私有變量
在Objective‐C中,所有實例變量默認都是私有的,所有實例方法默認都是公有的
3、關(guān)鍵字const什么含義?
const意味著”只讀”,下面的聲明都是什么意思?
const int a;
int const a;
const int *a;
int * const a;
int const * a const;
前兩個的作用是一樣,a是一個常整型數(shù)。第三個意味著a是一個指向常整型數(shù)的指針(也就是,整型數(shù)是不可修改的,但指針可以)。第四個意思a是一個指向整 型數(shù)的常指針(也就是說,指針指向的整型數(shù)是可以修改的,但指針是不可修改的)。最后一個意味著a是一個指向常整型數(shù)的常指針(也就是說,指針指向的整型 數(shù)是不可修改的,同時指針也是不可修改的)。
結(jié)論:
?; 關(guān)鍵字const的作用是為給讀你代碼的人傳達非常有用的信息,實際上,聲明一個參數(shù)為常量是為了告訴了用戶這個參數(shù)的應(yīng)用目的。如果你曾花很多時間清理其它人留下的垃圾,你就會很快學(xué)會感謝這點多余的信息。(當(dāng)然,懂得用const的程序員很少會留下的垃圾讓別人來清理的。)
?; 通過給優(yōu)化器一些附加的信息,使用關(guān)鍵字const也許能產(chǎn)生更緊湊的代碼。
?; 合理地使用關(guān)鍵字const可以使編譯器很自然地保護那些不希望被改變的參數(shù),防止其被無意的代碼修改。簡而言之,這樣可以減少bug的出現(xiàn)。
欲阻止一個變量被改變,可以使用 const 關(guān)鍵字。在定義該 const 變量時,通常需要對它進行初
始化,因為以后就沒有機會再去改變它了;
(2)對指針來說,可以指定指針本身為 const,也可以指定指針所指的數(shù)據(jù)為 const,或二者同時指定為 const;
(3)在一個函數(shù)聲明中,const 可以修飾形參,表明它是一個輸入?yún)?shù),在函數(shù)內(nèi)部不能改變其值;
(4)對于類的成員函數(shù),若指定其為 const 類型,則表明其是一個常函數(shù),不能修改類的成員變量;
(5)對于類的成員函數(shù),有時候必須指定其返回值為 const 類型,以使得其返回值不為“左值”。
4、關(guān)鍵字volatile有什么含義?并給出三個不同例子?
一個定義為volatile的變量是說這變量可能會被意想不到地改變,這樣,編譯器就不會去假設(shè)這個變量的值了。精確地說就是,優(yōu)化器在用到
這個變量時必須每次都小心地重新讀取這個變量的值,而不是使用保存在寄存器里的備份。下面是volatile變量的幾個例子:
并行設(shè)備的硬件寄存器(如:狀態(tài)寄存器)
一個中斷服務(wù)子程序中會訪問到的非自動變量(Non-automatic variables)
多線程應(yīng)用中被幾個任務(wù)共享的變量
一個參數(shù)既可以是const還可以是volatile嗎?解釋為什么。
一個指針可以是volatile 嗎?解釋為什么。
下面是答案:
是的。一個例子是只讀的狀態(tài)寄存器。它是volatile因為它可能被意想不到地改變。它是const因為程序不應(yīng)該試圖去修改它。
是的。盡管這并不很常見。一個例子是當(dāng)一個中服務(wù)子程序修該一個指向一個buffer的指針時。
static作用?
函數(shù)體內(nèi) static 變量的作用范圍為該函數(shù)體,不同于 auto 變量,該變量的內(nèi)存只被分配一次,
因此其值在下次調(diào)用時仍維持上次的值;
(2)在模塊內(nèi)的 static 全局變量可以被模塊內(nèi)所用函數(shù)訪問,但不能被模塊外其它函數(shù)訪問;
(3)在模塊內(nèi)的 static 函數(shù)只可被這一模塊內(nèi)的其它函數(shù)調(diào)用,這個函數(shù)的使用范圍被限制在聲明
它的模塊內(nèi);
(4)在類中的 static 成員變量屬于整個類所擁有,對類的所有對象只有一份拷貝;
(5)在類中的 static 成員函數(shù)屬于整個類所擁有,這個函數(shù)不接收 this 指針,因而只能訪問類的static 成員變量。
6、#import和#include的區(qū)別,@class代表什么?
@class一般用于頭文件中需要聲明該類的某個實例變量的時候用到,在m文件中還是需要使用#import
而#import比起#include的好處就是不會引起重復(fù)包含
7、線程和進程的區(qū)別?
進程和線程都是由操作系統(tǒng)所體會的程序運行的基本單元,系統(tǒng)利用該基本單元實現(xiàn)系統(tǒng)對應(yīng)用的并發(fā)性。
進程和線程的主要差別在于它們是不同的操作系統(tǒng)資源管理方式。進程有獨立的地址空間,一個進程崩潰后,在保護模式下不會對其它進程產(chǎn)生影響,而線程只是一 個進程中的不同執(zhí)行路徑。線程有自己的堆棧和局部變量,但線程之間沒有單獨的地址空間,一個線程死掉就等于整個進程死掉,所以多進程的程序要比多線程的程 序健壯,但在進程切換時,耗費資源較大,效率要差一些。但對于一些要求同時進行并且又要共享某些變量的并發(fā)操作,只能用線程,不能用進程。
8、堆和棧的區(qū)別?
管理方式:對于棧來講,是由編譯器自動管理,無需我們手工控制;對于堆來說,釋放工作由程序員控制,容易產(chǎn)生memory leak。
申請大小:
棧:在Windows下,棧是向低地址擴展的數(shù)據(jù)結(jié)構(gòu),是一塊連續(xù)的內(nèi)存的區(qū)域。這句話的意思是棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預(yù)先規(guī)定好的,在 WINDOWS下,棧的大小是2M(也有的說是1M,總之是一個編譯時就確定的常數(shù)),如果申請的空間超過棧的剩余空間時,將提示overflow。因 此,能從棧獲得的空間較小。
堆:堆是向高地址擴展的數(shù)據(jù)結(jié)構(gòu),是不連續(xù)的內(nèi)存區(qū)域。這是由于系統(tǒng)是用鏈表來存儲的空閑內(nèi)存地址的,自然是不連續(xù)的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限于計算機系統(tǒng)中有效的虛擬內(nèi)存。由此可見,堆獲得的空間比較靈活,也比較大。
碎片問題:對于堆來講,頻繁的new/delete勢必會造成內(nèi)存空間的不連續(xù),從而造成大量的碎片,使程序效率降低。對于棧來講,則不會存在這個問題,因為棧是先進后出的隊列,他們是如此的一一對應(yīng),以至于永遠都不可能有一個內(nèi)存塊從棧中間彈出
分配方式:堆都是動態(tài)分配的,沒有靜態(tài)分配的堆。棧有2種分配方式:靜態(tài)分配和動態(tài)分配。靜態(tài)分配是編譯器完成的,比如局部變量的分配。動態(tài)分配由alloca函數(shù)進行分配,但是棧的動態(tài)分配和堆是不同的,他的動態(tài)分配是由編譯器進行釋放,無需我們手工實現(xiàn)。
分配效率:棧是機器系統(tǒng)提供的數(shù)據(jù)結(jié)構(gòu),計算機會在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執(zhí)行,這就決定了棧的效率比較高。堆則是C/C++函數(shù)庫提供的,它的機制是很復(fù)雜的。
9、Object-C的內(nèi)存管理?
1.當(dāng)你使用new,alloc和copy方法創(chuàng)建一個對象時,該對象的保留計數(shù)器值為1.當(dāng)你不再使用該對象時,你要負責(zé)向該對象發(fā)送一條release或autorelease消息.這樣,該對象將在使用壽命結(jié)束時被銷毀.
2.當(dāng)你通過任何其他方法獲得一個對象時,則假設(shè)該對象的保留計數(shù)器值為1,而且已經(jīng)被設(shè)置為自動釋放,你不需要執(zhí)行任何操作來確保該對象被清理.如果你打算在一段時間內(nèi)擁有該對象,則需要保留它并確保在操作完成時釋放它.
3.如果你保留了某個對象,你需要(最終)釋放或自動釋放該對象.必須保持retain方法和release方法的使用次數(shù)相等.
10、為什么很多內(nèi)置的類,如TableViewController的delegate的屬性是assign不是retain?
循環(huán)引用
所有的引用計數(shù)系統(tǒng),都存在循環(huán)應(yīng)用的問題。例如下面的引用關(guān)系:
對象a創(chuàng)建并引用到了對象b.
對象b創(chuàng)建并引用到了對象c.
對象c創(chuàng)建并引用到了對象b.
這時候b和c的引用計數(shù)分別是2和1。當(dāng)a不再使用b,調(diào)用release釋放對b的所有權(quán),因為c還引用了b,所以b的引用計數(shù)為1,b不會被釋放。b不釋放,c的引用計數(shù)就是1,c也不會被釋放。從此,b和c永遠留在內(nèi)存中。
這種情況,必須打斷循環(huán)引用,通過其他規(guī)則來維護引用關(guān)系。比如,我們常見的delegate往往是assign方式的屬性而不是retain方式的屬 性,賦值不會增加引用計數(shù),就是為了防止delegation兩端產(chǎn)生不必要的循環(huán)引用。如果一個UITableViewController 對象a通 過retain獲取了UITableView對象b的所有權(quán),這個UITableView對象b的delegate又是a,如果這個delegate是 retain方式的,那基本上就沒有機會釋放這兩個對象了。自己在設(shè)計使用delegate模式時,也要注意這點。
11、定義屬性時,什么情況使用copy、assign、retain?
assign用于簡單數(shù)據(jù)類型,如NSInteger,double,bool,
retain和copy用于對象,
copy用于當(dāng)a指向一個對象,b也想指向同樣的對象的時候,如果用assign,a如果釋放,再調(diào)用b會crash,如果用copy 的方式,a和b各自有自己的內(nèi)存,就可以解決這個問題。
retain 會使計數(shù)器加一,也可以解決assign的問題。
另外:atomic和nonatomic用來決定編譯器生成的getter和setter是否為原子操作。在多線程環(huán)境下,原子操作是必要的,否則有可能引起錯誤的結(jié)果。
加了atomic,setter函數(shù)會變成下面這樣:
if (property != newValue) {
[property release];
property = [newValue retain];
}
12、對象是什么時候被release的?
引用計數(shù)為0時。
autorelease實際上只是把對release的調(diào)用延遲了,對于每一個Autorelease,系統(tǒng)只是把該Object放入了當(dāng)前的 Autorelease pool中,當(dāng)該pool被釋放時,該pool中的所有Object會被調(diào)用Release。對于每一個Runloop,系統(tǒng)會 隱式創(chuàng)建一個Autorelease pool,這樣所有的release pool會構(gòu)成一個象CallStack一樣的一個棧式結(jié)構(gòu),在每一個 Runloop結(jié)束時,當(dāng)前棧頂?shù)腁utorelease 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兩個結(jié)構(gòu)。visiableCells內(nèi)保存當(dāng)前顯示的 cells,reusableTableCells保存可重用的cells。
TableView顯示之初,reusableTableCells為空,那么 tableView dequeueReusableCellWithIdentifier:CellIdentifier返回nil。開始的cell都 是通過 [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] 來創(chuàng)建,而且cellForRowAtIndexPath只是調(diào)用最大顯示cell數(shù)的次數(shù)。
比如:有100條數(shù)據(jù),iPhone一屏最多顯示10個cell。程序最開始顯示TableView的情況是:
1.用 [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] 創(chuàng)建10次cell,并給cell指定同樣的重用標識(當(dāng)然,可以為不同顯示類型的cell指定不同的標識)。并且10個cell全部都加入到 visiableCells數(shù)組,reusableTableCells為空。
2.向下拖動tableView,當(dāng)cell1完全移出屏幕,并且cell11(它也是alloc出來的,原因同上)完全顯示出來的時候。 cell11加入到visiableCells,cell1移出visiableCells,cell1加入到reusableTableCells。
3.接著向下拖動tableView,因為reusableTableCells中已經(jīng)有值,所以,當(dāng)需要顯示新的 cell,cellForRowAtIndexPath再次被調(diào)用的時 候,tableView dequeueReusableCellWithIdentifier:CellIdentifier,返回cell1。 cell1加入到visiableCells,cell1移出reusableTableCells;cell2移出 visiableCells,cell2加入到reusableTableCells。之后再需要顯示的Cell就可以正常重用了。
15、ViewController 的loadView、viewDidLoad、viewDidUnload分別是什么時候調(diào)用的,在自定義ViewCointroller時在這幾個函數(shù)中應(yīng)該做什么工作?
由init、loadView、viewDidLoad、viewDidUnload、dealloc的關(guān)系說起
init方法
在init方法中實例化必要的對象(遵從LazyLoad思想)
init方法中初始化ViewController本身
loadView方法
當(dāng)view需要被展示而它卻是nil時,viewController會調(diào)用該方法。不要直接調(diào)用該方法。
如果手工維護views,必須重載重寫該方法
如果使用IB維護views,必須不能重載重寫該方法
loadView和IB構(gòu)建view
你在控制器中實現(xiàn)了loadView方法,那么你可能會在應(yīng)用運行的某個時候被內(nèi)存管理控制調(diào)用。 如果設(shè)備內(nèi)存不足的時候, view 控制器會收到 didReceiveMemoryWarning的消息。 默認的實現(xiàn)是檢查當(dāng)前控制器的view是否在使用。如果它的view不在當(dāng)前正在使用的 view hierarchy里面,且你的控制器實現(xiàn)了loadView方法,那么這個view將被release, loadView方法將被再次調(diào)用 來創(chuàng)建一個新的view。
viewDidLoad方法
viewDidLoad 此方法只有當(dāng)view從nib文件初始化的時候才被調(diào)用。
重載重寫該方法以進一步定制view
在iPhone OS 3.0及之后的版本中,還應(yīng)該重載重寫viewDidUnload來釋放對view的任何索引
viewDidLoad后調(diào)用數(shù)據(jù)Model
viewDidUnload方法
當(dāng)系統(tǒng)內(nèi)存吃緊的時候會調(diào)用該方法(注:viewController沒有被dealloc)
內(nèi)存吃緊時,在iPhone OS 3.0之前didReceiveMemoryWarning是釋放無用內(nèi)存的唯一方式,但是OS 3.0及以后viewDidUnload方法是更好的方式
在該方法中將所有IBOutlet(無論是property還是實例變量)置為nil(系統(tǒng)release view時已經(jīng)將其release掉了)
在該方法中釋放其他與view有關(guān)的對象、其他在運行時創(chuàng)建(但非系統(tǒng)必須)的對象、在viewDidLoad中被創(chuàng)建的對象、緩存數(shù)據(jù) 等 release對象后,將對象置為nil(IBOutlet只需要將其置為nil,系統(tǒng)release view時已經(jīng)將其release掉了)
一般認為viewDidUnload是viewDidLoad的鏡像,因為當(dāng)view被重新請求時,viewDidLoad還會重新被執(zhí)行
viewDidUnload中被release的對象必須是很容易被重新創(chuàng)建的對象(比如在viewDidLoad或其他方法中創(chuàng)建的對象),不要release用戶數(shù)據(jù)或其他很難被重新創(chuàng)建的對象
dealloc方法
viewDidUnload和dealloc方法沒有關(guān)聯(lián),dealloc還是繼續(xù)做它該做的事情
16、ViewController的didReceiveMemoryWarning是在什么時候調(diào)用的?默認的操作是什么?
當(dāng)程序接到內(nèi)存警告時View Controller將會收到這個消息:didReceiveMemoryWarning
從iOS3.0開始,不需要重載這個函數(shù),把釋放內(nèi)存的代碼放到viewDidUnload中去。
這個函數(shù)的默認實現(xiàn)是:檢查controller是否可以安全地釋放它的view(這里加粗的view指的是controller的view屬性),比如view本身沒有superview并且可以被很容易地重建(從nib或者loadView函數(shù))。
如果view可以被釋放,那么這個函數(shù)釋放view并調(diào)用viewDidUnload。
你可以重載這個函數(shù)來釋放controller中使用的其他內(nèi)存。但要記得調(diào)用這個函數(shù)的super實現(xiàn)來允許父類(一般是UIVIewController)釋放view。
如果你的ViewController保存著view的子view的引用,那么,在早期的iOS版本中,你應(yīng)該在這個函數(shù)中來釋放這些引用。而在iOS3.0或更高版本中,你應(yīng)該在viewDidUnload中釋放這些引用。
17、列舉Cocoa中常見的集中多線程的實現(xiàn),并談?wù)劧嗑€程安全的幾種解決辦法,一般什么地方會用到多線程?
NSThread,GCD等。盡量用上層分裝好的方法去實現(xiàn)多線程而不是手動調(diào)用NSThread。
18、怎么理解MVC,在Cocoa中MVC是怎么實現(xiàn)的?
Model: 代表你的應(yīng)用程序是什么(不是怎么展現(xiàn))
Controller: 控制你的Model怎么展現(xiàn)給用戶(UI邏輯)
View: Controller的奴隸。。。
1 Model,Controller,View相互通訊的規(guī)則:
Controller可以直接和Model通信
Controller也可以直接和View通信
Model和View永遠不能直接通信
iOS中View和Controller的通信是透明和固定的,主要通過outlet和action實現(xiàn)
View使用Delegate接口和Controller同步信息
View不直接和數(shù)據(jù)通信,使用dataSource接口從Controller處獲取數(shù)據(jù)
View的delegate和dataSource一般就是Controller
Controller負責(zé)為View翻譯和格式化Model的數(shù)據(jù)
Model使用Notification & KVO的方式分發(fā)數(shù)據(jù)更新信息,Controller可以有選擇的監(jiān)聽自己感興趣的信息。
View也可以監(jiān)聽廣播信息,但一般不是Model發(fā)出的信息
一個完整的App就是很多MVC的集合
19、delegate和notification區(qū)別,分別在什么情況下使用?
Delegate:
消息的發(fā)送者(sender)告知接收者(receiver)某個事件將要發(fā)生,delegate同意然然后發(fā)送者響應(yīng)事件,delegate機制使得接收者可以改變發(fā)送者的行為。通常發(fā)送者和接收者的關(guān)系是直接的一對多的關(guān)系。
Notification:
消息的發(fā)送者告知接收者事件已經(jīng)發(fā)生或者將要發(fā)送,僅此而已,接收者并不能反過來影響發(fā)送者的行為。通常發(fā)送者和接收者的關(guān)系是間接的多對多關(guān)系。
- 效率肯定是delegate比nsnotification高。
- delegate方法比notification更加直接,最典型的特征是,delegate方法往往需要關(guān)注返回值,也就是delegate方法 的結(jié)果。比如-windowShouldClose:,需要關(guān)心返回的是yes還是no。所以delegate方法往往包含should這個很傳神的詞。 也就是好比你做我的delegate,我會問你我想關(guān)閉窗口你愿意嗎?你需要給我一個答案,我根據(jù)你的答案來決定如何做下一步。相反 的,notification最大的特色就是不關(guān)心接受者的態(tài)度,我只管把通告放出來,你接受不接受就是你的事情,同時我也不關(guān)心結(jié)果。所以 notification往往用did這個詞匯,比如NSWindowDidResizeNotification,那么nswindow對象放出這個 notification后就什么都不管了也不會等待接受者的反應(yīng)。
1)兩個模塊之間聯(lián)系不是很緊密,就用notification傳值,例如多線程之間傳值用notificaiton。
2)delegate只是一種較為簡單的回調(diào),且主要用在一個模塊中,例如底層功能完成了,需要把一些值傳到上層去,就事先把上層的函數(shù)通過 delegate傳到底層,然后在底層call這個delegate,它們都在一個模塊中,完成一個功能,例如 說 NavgationController 從 B 界面到A 點返回按鈕 (調(diào)用popViewController方法) 可以用delegate 比較好
20、self.跟self什么區(qū)別?
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和實現(xiàn)(implementation)相關(guān)
IMP定義為 id (*IMP) (id, SEL, …)。這樣說來, IMP是一個指向函數(shù)的指針,這個被指向的函數(shù)包括id(“self”指針),調(diào)用的SEL(方法名),再加上一些其他參數(shù).說白了IMP就是實現(xiàn)方法。
22、內(nèi)存管理 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的一個自動釋放的值,或傳遞一個基本數(shù)據(jù)類型(NSInteger,NSString)時:你或希望將對象2進行retain,以防止它在被使用之前就被自動釋放掉。但是在retain后,一定要在適當(dāng)?shù)臅r候進行釋放。
關(guān)于索引計數(shù)(Reference Counting)的問題
retain值 = 索引計數(shù)(Reference Counting)
NSArray對象會retain(retain值加一)任何數(shù)組中的對象。當(dāng)NSArray被卸載(dealloc)的時候,所有數(shù)組中的對象會被 執(zhí)行一次釋放(retain值減一)。不僅僅是NSArray,任何收集類(Collection Classes)都執(zhí)行類似操作。例如 NSDictionary,甚至UINavigationController。
Alloc/init建立的對象,索引計數(shù)為1。無需將其再次retain。
[NSArray array]和[NSDate date]等“方法”建立一個索引計數(shù)為1的對象,但是也是一個自動釋放對象。所以是本地臨時對象,那么無所謂了。如果是打算在全Class中使用的變量(iVar),則必須retain它。
缺省的類方法返回值都被執(zhí)行了“自動釋放”方法。(*如上中的NSArray)
在類中的卸載方法“dealloc”中,release所有未被平衡的NS對象。(*所有未被autorelease,而retain值為1的)
23、類別的作用?
有時我們需要在一個已經(jīng)定義好的類中增加一些方法,而不想去重寫該類。比如,當(dāng)工程已經(jīng)很大,代碼量比較多,或者類中已經(jīng)包住很多方法,已經(jīng)有其他代碼調(diào)用了該類創(chuàng)建對象并使用該類的方法時,可以使用類別對該類擴充新的方法。
注意:類別只能擴充方法,而不能擴充成員變量。
24、委托(舉例)
委托代理(degegate),顧名思義,把某個對象要做的事情委托給別的對象去做。那么別的對象就是這個對象的代理,代替它來打理要做的事。反映到程序中,首先要明確一個對象的委托方是哪個對象,委托所做的內(nèi)容是什么。
委托機制是一種設(shè)計模式,在很多語言中都用到的,這只是個通用的思想,網(wǎng)上會有很多關(guān)于這方面的介紹。
那么在蘋果開發(fā)過程中,用到委托的程序?qū)崿F(xiàn)思想如下,我主要拿如何在視圖之間傳輸信息做個例子。
譬如:在兩個頁面(UIIview視圖對象)實現(xiàn)傳值,用委托(delegate)可以很好做到!
方法:
類A
@interface A:UIView
id transparendValueDelegate;
@property(nomatic, retain) id transparendValueDelegate;
@end
@implemtion A
@synthesize transparendValueDelegate
-(void)Function
{
NSString* value = @"hello";
//讓代理對象執(zhí)行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
//下面的設(shè)置A代理委托對象為B
//在定義A和B類對象處:
A* a = [[A alloc] init];
B* b = [[B alloc] init];
a. transparendValueDelegate = b;//設(shè)置對象a代理為對象b
這樣在視圖A和B之間可以通過委托來傳值!
25、retainCount?
26..屬性readwrite,readonly,assign,retain,copy,nonatomic 各是什么作用,在那種情況下用
assign:指定setter方法用簡單的賦值,這是默認操作。你可以對標量類型(如int)使用這個屬性。你可以想象一個float,它不是一個對象,所以它不能retain、copy。
retain:指定retain應(yīng)該在后面的對象上調(diào)用,前一個值發(fā)送一條release消息。你可以想象一個NSString實例,它是一個對象,而且你可能想要retain它。
copy:指定應(yīng)該使用對象的副本(深度復(fù)制),前一個值發(fā)送一條release消息。基本上像retain,但是沒有增加引用計數(shù),是分配一塊新的內(nèi)存來放置它。
readonly:將只生成getter方法而不生成setter方法(getter方法沒有g(shù)et前綴)。
readwrite:默認屬性,將生成不帶額外參數(shù)的getter和setter方法(setter方法只有一個參數(shù))。
atomic:對于對象的默認屬性,就是setter/getter生成的方法是一個原子操作。如果有多個線程同時調(diào)用setter的話,不會出現(xiàn)某一個線程執(zhí)行setter全部語句之前,另一個線程開始執(zhí)行setter的情況,相關(guān)于方法頭尾加了鎖一樣。
nonatomic:不保證setter/getter的原子性,多線程情況下數(shù)據(jù)可能會有問題。
27.類變量的@protected ,@private ,@public ,@package聲明各有什么含義
Objective-C 對存取權(quán)限的設(shè)定。也是變量的作用域。
protected 該類和所有的子類中的方法可以直接訪問這樣的變量,這是默認的。
private — 該類中的方法可以訪問這樣的變量,子類不可以。 public — 除了自己和子類中的方法外,也可以被其他類或者其他模塊中的方法所訪問。開放性最大。 package — 對于64位圖像,這樣的成員變量可以在實現(xiàn)這個類的圖像中隨意訪問。
28.淺拷貝和深拷貝區(qū)別是什么
簡單的來說就是,在有指針的情況下,淺拷貝只是增加了一個指針指向已經(jīng)存在的內(nèi)存,而深拷貝就是增加一個指針并且申請一個新的內(nèi)存,使這個增加的指針指向這個新的內(nèi)存,采用深拷貝的情況下,釋放內(nèi)存的時候就不會出現(xiàn)在淺拷貝時重復(fù)釋放同一內(nèi)存的錯誤
29.Cocoa中與虛基類的概念么?怎么簡潔的實現(xiàn)
30.NSString 和 NSMutableString 有什么區(qū)別
NSString相當(dāng)于一個const char* 不可以改變。
而 NSMutableString相當(dāng)于 char* 可以改變內(nèi)部的內(nèi)容。
31.自動釋放池跟GC有什么區(qū)別?iPhone上有GC么?[pool release] 和[pool drain]有什么區(qū)別
”Autorelease Pools”(自動釋放池)在應(yīng)用中的使用技巧。
1,Autorelease Pools概要
一個”Autorelease Pool”實例中“包含”其它各種調(diào)用了”autorelease”方法的對象。當(dāng)它釋放時,其中所有被管理對象都會收 到”relrease”的消信。注意,同一個對象可以被多次調(diào)用”autorelease”方法,并可以放到同一個”Autorelease Pool” 中。引入這個自動釋放池機制,對象的”autorelease”方法代替”relrease”方法可以延長它的生命周期,直接到當(dāng) 前”Autorelrease Pool”釋放。如果想讓此對象的生命周期超過”Autorelease Pool”,還可以再次”retain”,呵 呵,有意思吧?且讓我慢慢道來。
Cocoa總是認為當(dāng)前至少有一個”Autorelease Pool”對象是可用的。若此對象并不存在,你調(diào)用的”autorelease”的所有對象都不會被自動釋放掉,可想而知,造成內(nèi)存泄露。Cocoa把這個錯誤信息寫入日志??僅僅是為了以后分析。
你可以用”alloc”與”init”方法創(chuàng)建一個”NSAutoreleasePool”對象,并且可以調(diào)用”release”或”drain” (”release”與”drain”的區(qū)別是”drain”在有GC的環(huán)境中會引起GC回收操作,”release”反之。但在非GC環(huán)境中,兩者相 同。官方的說法是為了程序的兼容性,應(yīng)該考慮用”drain”代替”release”,)方法來回收它(調(diào)用它的”autorelease” 或”retain”方法會引起異常)。在一個完整的上下文最后”Autorelease Pool”對象應(yīng)該被”release”掉(在方法內(nèi)或一段循環(huán) 體內(nèi)創(chuàng)建的”Autorelease Pool”對象)。
“Autorelease Pools”的所有實例在棧中管理(我們暫時叫他“自動釋放池棧”),并且它們是可以被嵌套的(父生子,子生孫。。。子子孫 孫 _)。例如,當(dāng)我們創(chuàng)建一個”Autorelease Pool”對象后,它就被自動放到“自動釋放池棧”的棧頂。當(dāng)本池對象回收時,它就隨之從 這個棧中POP掉。那么也就是說,當(dāng)任何一個對象調(diào)用”autorelease”方法后,它會被放入當(dāng)前線程中當(dāng)前棧頂?shù)淖詣俞尫懦刂小?/p>
接下來我們聊聊”Autorelease Pools”的嵌套問題。在你的應(yīng)用中,你可以任意多的創(chuàng)建”Autorelease Pool”對象,而這些 對象被當(dāng)前線程的“自動釋放池棧”所管理。那么除了一個接一個的順序創(chuàng)建并銷毀它的情況外,還有一種使用方式,就是嵌套式的創(chuàng)建與使用。例如:在你的主函 數(shù)創(chuàng)建了一個”autorelease pool”,然后又調(diào)用了創(chuàng)建了”autorelease pool”實例的其它方法;或是在外循環(huán)中創(chuàng)建 了”Autorelease Pool”的實例,而內(nèi)循環(huán)中也做了相同的事情。有意思吧,呵呵,嵌套的機制使父Pool實例釋放后,它的所有子Pool也 將釋放。但這里還存在一些副作用,后續(xù)文章會詳細討論。
“Application kit”在一個事件循環(huán)里會自動創(chuàng)建一個”autorelease pool”。像鼠標鍵的按下與釋放,所以你編寫的代碼通常不需要考慮太多這方面的事情。當(dāng)然,有以下三種情況你會創(chuàng)建與銷毀自己的Pool實例:
1,應(yīng)用不是基于”Application Kit”,像”Command-line tool”,因為它并沒有內(nèi)置的”autorelease pools”的支持。
2,創(chuàng)建線程,你必需在線程開始時創(chuàng)建一個”Autorelease Pool”實例。反之,會造成內(nèi)存池露(會在以后的文章詳細說明線程與池的技巧)。
3,一個循環(huán)內(nèi)創(chuàng)建了太多的臨時對象,你應(yīng)該為他們創(chuàng)建一個”Autorelease Pool”對象,并在下次循還前銷毀它們。
2,自動釋放池中的”Non-AppKit”應(yīng)用
在”Non-AppKit”應(yīng)用中使用自動釋放池的機制其實是相當(dāng)簡單的事情。你僅僅需要在main()起始處創(chuàng)建”Autorelease Pool” 對象,并在結(jié)尾處釋放掉它。就像在Xcode的Foundation Tool的創(chuàng)建模版里寫的一樣。這個確保你在應(yīng)用生命周期內(nèi)至少有一 個”Autorelease Pool”是可用的。但是,這也使所有在此期間的所有”autorelease”的對象都必需在應(yīng)用結(jié)束后才被釋放。這也許 會引起在應(yīng)用的使用中不斷的增長,所以,你仍然考慮在不同的作用域創(chuàng)建新的”Autorelease Pool”。
大多應(yīng)用中都存在各種級別的循環(huán)機制。在這些應(yīng)用中,你可以在每個循環(huán)內(nèi)的開頭創(chuàng)建一個”Autorelease Pool”對象,并在結(jié)尾處釋放掉它。
例如:
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);
}
在命令行中處理所有以參數(shù)傳來的文件。一次循環(huán)處理一個文件。在循環(huán)的開頭創(chuàng)建一個”NSAutoreleasePool”對象,并在循環(huán)結(jié)束時釋放掉。 因此,任何在其中創(chuàng)建并調(diào)用“autorelease”的對象都將添加到這個Pool實例中,當(dāng)本池被釋放后,這些對象也將被回收。注意,任何在作用域內(nèi) 創(chuàng)建的”autoreleased”對象(像”fileName”),雖然并沒有顯示的調(diào)用”autorelease”方法,但都將被當(dāng)前池所管理并釋 放。
32.C和obj-c 如何混用
1)obj-c的編譯器處理后綴為m的文件時,可以識別obj-c和c的代碼,處理mm文件可以識別obj-c,c,c++代碼,但cpp文件必須只能用c/c++代碼,而且cpp文件include的頭文件中,也不能出現(xiàn)obj-c的代碼,因為cpp只是cpp
2)在mm文件中混用cpp直接使用即可,所以obj-c混cpp不是問題
3)在cpp中混用obj-c其實就是使用obj-c編寫的模塊是我們想要的。
如果模塊以類實現(xiàn),那么要按照cpp class的標準寫類的定義,頭文件中不能出現(xiàn)obj-c的東西,包括#import cocoa的。實現(xiàn)文件中,即類的實現(xiàn)代碼中可以使用obj-c的東西,可以import,只是后綴是mm。
如果模塊以函數(shù)實現(xiàn),那么頭文件要按c的格式聲明函數(shù),實現(xiàn)文件中,c++函數(shù)內(nèi)部可以用obj-c,但后綴還是mm或m。
總結(jié):只要cpp文件和cpp include的文件中不包含obj-c的東西就可以用了,cpp混用obj-c的關(guān)鍵是使用接口,而不能直接使用實現(xiàn)代 碼,實際上cpp混用的是obj-c編譯后的o文件,這個東西其實是無差別的,所以可以用。obj-c的編譯器支持cpp
33.響應(yīng)者鏈是什么
響應(yīng)者鏈是Application Kit事件處理架構(gòu)的中心機制。它由一系列鏈接在一起的響應(yīng)者對象組成,事件或者動作消息可以沿著這些對象進行傳 遞。如圖6-20顯示的那樣,如果一個響應(yīng)者對象不能處理某個事件或動作-也就是說,它不響應(yīng)那個消息,或者不認識那個事件,則將該消息重新發(fā)送給鏈中的 下一個響應(yīng)者。消息沿著響應(yīng)者鏈向上、向更高級別的對象傳遞,直到最終被處理(如果最終還是沒有被處理,就會被拋棄)。
當(dāng)Application Kit在應(yīng)用程序中構(gòu)造對象時,會為每個窗口建立響應(yīng)者鏈。響應(yīng)者鏈中的基本對象是NSWindow對象及其視圖層次。在視圖層次中級別較低的視圖將比級別更高的視圖優(yōu)先獲得處理事件或動作消息的機會。NSWindow中保有一個第一響應(yīng)者的引用,它通常是當(dāng)前窗口中處于選擇狀態(tài)的視圖,窗口通常把響應(yīng)消息的機會首先給它。對于事件消息,響應(yīng)者鏈通常以發(fā)生事件的窗口對應(yīng)的NSWindow對象作為結(jié)束,雖然其它對象也可以作為下一個響應(yīng)者被加入到NSWindow對象的后面。
34..UIscrollVew用到了什么設(shè)計模式?還能再foundation庫中找到類似的嗎?
組合模式composition,所有的container view都用了這個模式
觀察者模式observer,所有的UIResponder都用了這個模式。
模板(Template)模式,所有datasource和delegate接口都是模板模式的典型應(yīng)用
- .timer的間隔周期準嗎?為什么?怎樣實現(xiàn)一個精準的timer?
NSTimer可以精確到50-100毫秒.
NSTimer不是絕對準確的,而且中間耗時或阻塞錯過下一個點,那么下一個點就pass過去了
此份面試題包含40個題目,是現(xiàn)在網(wǎng)上能搜索到的一個比較熱的一份,但是答案并不是很詳細和完整,基本答案來著cocoaChina,和一些自己的補充。
34.Difference between shallow copy and deep copy?
淺復(fù)制和深復(fù)制的區(qū)別?
答案:淺層復(fù)制:只復(fù)制指向?qū)ο蟮闹羔槪粡?fù)制引用對象本身。
深層復(fù)制:復(fù)制引用對象本身。
意思就是說我有個A對象,復(fù)制一份后得到A_copy對象后,對于淺復(fù)制來說,A和A_copy指向的是同一個內(nèi)存資源,復(fù)制的只不過是是一個指針,對象本身資源
還是只有一份,那如果我們對A_copy執(zhí)行了修改操作,那么發(fā)現(xiàn)A引用的對象同樣被修改,這其實違背了我們復(fù)制拷貝的一個思想。深復(fù)制就好理解了,內(nèi)存中存在了
兩份獨立對象本身。
用網(wǎng)上一哥們通俗的話將就是:
淺復(fù)制好比你和你的影子,你完蛋,你的影子也完蛋
深復(fù)制好比你和你的克隆人,你完蛋,你的克隆人還活著。
35.What is advantage of categories? What is difference between implementing a category and inheritance?
類別的作用?繼承和類別在實現(xiàn)中有何區(qū)別?
答案:category 可以在不獲悉,不改變原來代碼的情況下往里面添加新的方法,只能添加,不能刪除修改。
并且如果類別和原來類中的方法產(chǎn)生名稱沖突,則類別將覆蓋原來的方法,因為類別具有更高的優(yōu)先級。
類別主要有3個作用:
(1)將類的實現(xiàn)分散到多個不同文件或多個不同框架中。
(2)創(chuàng)建對私有方法的前向引用。
(3)向?qū)ο筇砑臃钦絽f(xié)議。
繼承可以增加,修改或者刪除方法,并且可以增加屬性。
36.Difference between categories and extensions?
類別和類擴展的區(qū)別。
答案:category和extensions的不同在于后者可以添加屬性。另外后者添加的方法是必須要實現(xiàn)的。
extensions可以認為是一個私有的Category。
37.Difference between protocol in objective c and interfaces in java?
oc中的協(xié)議和java中的接口概念有何不同?
答案:OC中的代理有2層含義,官方定義為 formal和informal protocol。前者和Java接口一樣。
informal protocol中的方法屬于設(shè)計模式考慮范疇,不是必須實現(xiàn)的,但是如果有實現(xiàn),就會改變類的屬性。
其實關(guān)于正式協(xié)議,類別和非正式協(xié)議我很早前學(xué)習(xí)的時候大致看過,也寫在了學(xué)習(xí)教程里
“非正式協(xié)議概念其實就是類別的另一種表達方式“這里有一些你可能希望實現(xiàn)的方法,你可以使用他們更好的完成工作”。
這個意思是,這些是可選的。比如我門要一個更好的方法,我們就會申明一個這樣的類別去實現(xiàn)。然后你在后期可以直接使用這些更好的方法。
這么看,總覺得類別這玩意兒有點像協(xié)議的可選協(xié)議。"
現(xiàn)在來看,其實protocal已經(jīng)開始對兩者都統(tǒng)一和規(guī)范起來操作,因為資料中說“非正式協(xié)議使用interface修飾“,
現(xiàn)在我們看到協(xié)議中兩個修飾詞:“必須實現(xiàn)(@requied)”和“可選實現(xiàn)(@optional)”。
38.What are KVO and KVC?
答案:kvc:鍵 - 值編碼是一種間接訪問對象的屬性使用字符串來標識屬性,而不是通過調(diào)用存取方法,直接或通過實例變量訪問的機制。
很多情況下可以簡化程序代碼。apple文檔其實給了一個很好的例子。
kvo:鍵值觀察機制,他提供了觀察某一屬性變化的方法,極大的簡化了代碼。
具體用看到嗯哼用到過的一個地方是對于按鈕點擊變化狀態(tài)的的監(jiān)控。
比如我自定義的一個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];
}
}
對于系統(tǒng)是根據(jù)keypath去取的到相應(yīng)的值發(fā)生改變,理論上來說是和kvc機制的道理是一樣的。
對于kvc機制如何通過key尋找到value:
“當(dāng)通過KVC調(diào)用對象時,比如:[self valueForKey:@”someKey”]時,程序會自動試圖通過幾種不同的方式解析這個調(diào)用。首先 查找對象是否帶有 someKey 這個方法,如果沒找到,會繼續(xù)查找對象是否帶有someKey這個實例變量(iVar),如果還沒有找到,程序會繼續(xù) 試圖調(diào)用 -(id) valueForUndefinedKey:這個方法。如果這個方法還是沒有被實現(xiàn)的話,程序會拋出一個 NSUndefinedKeyException異常錯誤。
(cocoachina.com注:Key-Value Coding查找方法的時候,不僅僅會查找someKey這個方法,還會查找 getsomeKey這個方法,前面加一個get,或者_someKey以及_getsomeKey這幾種形式。同時,查找實例變量的時候也會不僅僅查找 someKey這個變量,也會查找_someKey這個變量是否存在。)
設(shè)計valueForUndefinedKey:方法的主要目的是當(dāng)你使用-(id)valueForKey方法從對象中請求值時,對象能夠在錯誤發(fā)生前,有最后的機會響應(yīng)這個請求。這樣做有很多好處,下面的兩個例子說明了這樣做的好處。“
來至cocoa,這個說法應(yīng)該挺有道理。
因為我們知道button卻是存在一個highlighted實例變量.因此為何上面我們只是add一個相關(guān)的keypath就行了,
可以按照kvc查找的邏輯理解,就說的過去了。
39.What is purpose of delegates?
代理的作用?
答案:代理的目的是改變或傳遞控制鏈。允許一個類在某些特定時刻通知到其他類,而不需要獲取到那些類的指針。可以減少框架復(fù)雜度。
另外一點,代理可以理解為java中的回調(diào)監(jiān)聽機制的一種類似。
40.What are mutable and immutable types in Objective C?
oc中可修改和不可以修改類型。
答案:可修改不可修改的集合類。這個我個人簡單理解就是可動態(tài)添加修改和不可動態(tài)添加修改一樣。
比如NSArray和NSMutableArray。前者在初始化后的內(nèi)存控件就是固定不可變的,后者可以添加等,可以動態(tài)申請新的內(nèi)存空間。
41.When we call objective c is runtime language what does it mean?
我們說的oc是動態(tài)運行時語言是什么意思?
答案:多態(tài)。 主要是將數(shù)據(jù)類型的確定由編譯時,推遲到了運行時。
這個問題其實淺涉及到兩個概念,運行時和多態(tài)。
簡單來說,運行時機制使我們直到運行時才去決定一個對象的類別,以及調(diào)用該類別對象指定方法。
多態(tài):不同對象以自己的方式響應(yīng)相同的消息的能力叫做多態(tài)。意思就是假設(shè)生物類(life)都用有一個相同的方法-eat;
那人類屬于生物,豬也屬于生物,都繼承了life后,實現(xiàn)各自的eat,但是調(diào)用是我們只需調(diào)用各自的eat方法。
也就是不同的對象以自己的方式響應(yīng)了相同的消息(響應(yīng)了eat這個選擇器)。
因此也可以說,運行時機制是多態(tài)的基礎(chǔ)?~~~
42.what is difference between NSNotification and protocol?
通知和協(xié)議的不同之處?
答案:協(xié)議有控制鏈(has-a)的關(guān)系,通知沒有。
首先我一開始也不太明白,什么叫控制鏈(專業(yè)術(shù)語了~)。但是簡單分析下通知和代理的行為模式,我們大致可以有自己的理解
簡單來說,通知的話,它可以一對多,一條消息可以發(fā)送給多個消息接受者。
代理按我們的理解,到不是直接說不能一對多,比如我們知道的明星經(jīng)濟代理人,很多時候一個經(jīng)濟人負責(zé)好幾個明星的事務(wù)。
只是對于不同明星間,代理的事物對象都是不一樣的,一一對應(yīng),不可能說明天要處理A明星要一個發(fā)布會,代理人發(fā)出處理發(fā)布會的消息后,別稱B的
發(fā)布會了。但是通知就不一樣,他只關(guān)心發(fā)出通知,而不關(guān)心多少接收到感興趣要處理。
因此控制鏈(has-a從英語單詞大致可以看出,單一擁有和可控制的對應(yīng)關(guān)系。
43.What is push notification?
什么是推送消息?
答案:太簡單,不作答~~~~~~~~~~
這是cocoa上的答案。
其實到不是說太簡單,只是太泛泛的一個概念的東西。就好比說,什么是人。
推送通知更是一種技術(shù)。
簡單點就是客戶端獲取資源的一種手段。
普通情況下,都是客戶端主動的pull。
推送則是服務(wù)器端主動push。
44.Polymorphism?
關(guān)于多態(tài)性
答案:多態(tài),子類指針可以賦值給父類。
這個題目其實可以出到一切面向?qū)ο笳Z言中,
因此關(guān)于多態(tài),繼承和封裝基本最好都有個自我意識的理解,也并非一定要把書上資料上寫的能背出來。
最重要的是轉(zhuǎn)化成自我理解。
45.Singleton?
對于單例的理解
答案:11,12題目其實出的有點泛泛的感覺了,可能說是編程語言需要或是必備的基礎(chǔ)。
基本能用熟悉的語言寫出一個單例,以及可以運用到的場景或是你編程中碰到過運用的此種模式的框架類等。
進一步點,考慮下如何在多線程訪問單例時的安全性。
46.What is responder chain?
說說響應(yīng)鏈
答案: 事件響應(yīng)鏈。包括點擊事件,畫面刷新事件等。在視圖棧內(nèi)從上至下,或者從下之上傳播。
可以說點事件的分發(fā),傳遞以及處理。具體可以去看下touch事件這塊。因為問的太抽象化了
嚴重懷疑題目出到越后面就越籠統(tǒng)。
47.Difference between frame and bounds?
frame和bounds有什么不同?
答案:frame指的是:該view在父view坐標系統(tǒng)中的位置和大小。(參照點是父親的坐標系統(tǒng))
bounds指的是:該view在本身坐標系統(tǒng)中 的位置和大小。(參照點是本身坐標系統(tǒng))
48.Difference between method and selector?
方法和選擇器有何不同?
答案:selector是一個方法的名字,method是一個組合體,包含了名字和實現(xiàn).
詳情可以看apple文檔。
49.Is there any garbage collection mechanism in Objective C.?
OC的垃圾回收機制?
答案: OC2.0有Garbage collection,但是iOS平臺不提供。
一般我們了解的objective-c對于內(nèi)存管理都是手動操作的,但是也有自動釋放池。
但是差了大部分資料,貌似不要和arc機制搞混就好了。
求更多~~
50.NSOperation queue?
答案:存放NSOperation的集合類。
操作和操作隊列,基本可以看成java中的線程和線程池的概念。用于處理ios多線程開發(fā)的問題。
網(wǎng)上部分資料提到一點是,雖然是queue,但是卻并不是帶有隊列的概念,放入的操作并非是按照嚴格的先進現(xiàn)出。
這邊又有個疑點是,對于隊列來說,先進先出的概念是Afunc添加進隊列,Bfunc緊跟著也進入隊列,Afunc先執(zhí)行這個是必然的,
但是Bfunc是等Afunc完全操作完以后,B才開始啟動并且執(zhí)行,因此隊列的概念離亂上有點違背了多線程處理這個概念。
但是轉(zhuǎn)念一想其實可以參考銀行的取票和叫號系統(tǒng)。
因此對于A比B先排隊取票但是B率先執(zhí)行完操作,我們亦然可以感性認為這還是一個隊列。
但是后來看到一票關(guān)于這操作隊列話題的文章,其中有一句提到
“因為兩個操作提交的時間間隔很近,線程池中的線程,誰先啟動是不定的。”
瞬間覺得這個queue名字有點忽悠人了,還不如pool~
綜合一點,我們知道他可以比較大的用處在于可以幫組多線程編程就好了。
51.What is lazy loading?
答案:懶漢模式,只在用到的時候才去初始化。
也可以理解成延時加載。
我覺得最好也最簡單的一個列子就是tableView中圖片的加載顯示了。
一個延時載,避免內(nèi)存過高,一個異步加載,避免線程堵塞。
52.Can we use two tableview controllers on one viewcontroller?
是否在一個視圖控制器中嵌入兩個tableview控制器?
答案:一個視圖控制只提供了一個View視圖,理論上一個tableViewController也不能放吧,
只能說可以嵌入一個tableview視圖。當(dāng)然,題目本身也有歧義,如果不是我們定性思維認為的UIViewController,
而是宏觀的表示視圖控制者,那我們倒是可以把其看成一個視圖控制者,它可以控制多個視圖控制器,比如TabbarController
那樣的感覺。
53.Can we use one tableview with two different datasources? How you will achieve this?
一個tableView是否可以關(guān)聯(lián)兩個不同的數(shù)據(jù)源?你會怎么處理?
答案:首先我們從代碼來看,數(shù)據(jù)源如何關(guān)聯(lián)上的,其實是在數(shù)據(jù)源關(guān)聯(lián)的代理方法里實現(xiàn)的。
因此我們并不關(guān)心如何去關(guān)聯(lián)他,他怎么關(guān)聯(lián)上,方法只是讓我返回根據(jù)自己的需要去設(shè)置如相關(guān)的數(shù)據(jù)源
- 因此,我覺得可以設(shè)置多個數(shù)據(jù)源啊,但是有個問題是,你這是想干嘛呢?想讓列表如何顯示,不同的數(shù)據(jù)源分區(qū)塊顯示?