有一部分是自己看到感覺不錯之後總結的:
本篇的面試題是我認為比較好的iOS開發基礎知識點,希望大家看過這後在理解的基礎上掌握而不是死記硬背。死記硬背很快也會忘記的。
深拷貝同淺拷貝的區別:淺拷貝是指針拷貝,對一個對象進行淺拷貝,相當於對指向對象的指針進行復制,產生一個新的指向這個對象的指針,那麼就是有兩個指針指向同一個對象,這個對象銷毀後兩個指針都應該置空。深拷貝是對一個對象進行拷貝,相當於對對象進行復制,產生一個新的對象,那麼就有兩個指針分別指向兩個對象。當一個對象改變或者被銷毀後拷貝出來的新的對象不受影響。
實現深拷貝需要實現NSCoying協議,實現- (id)copyWithZone:(NSZone *)zone 方法。當對一個property屬性含有copy修飾符的時候,在進行賦值操作的時候實際上就是調用這個方法。
父類實現深拷貝之後,子類只要重寫copyWithZone方法,在方法內部調用父類的copyWithZone方法,之後實現自己的屬性的處理
父類沒有實現深拷貝,子類除了需要對自己的屬性進行處理,還要對父類的屬性進行處理。
NSNotification是通知,也是一對多的使用場景。在某些情況下,KVO和NSNotification是一樣的,都是狀態變化之後告知對方。NSNotification的特點,就是需要被觀察者先主動發出通知,然後觀察者注冊監聽後再來進行響應,比KVO多了發送通知的一步,但是其優點是監聽不局限於屬性的變化,還可以對多種多樣的狀態變化進行監聽,監聽范圍廣,使用也更靈活。
delegate 是代理,就是我不想做的事情交給別人做。比如狗需要吃飯,就通過delegate通知主人,主人就會給他做飯、盛飯、倒水,這些操作,這些狗都不需要關心,只需要調用delegate(代理人)就可以了,由其他類完成所需要的操作。所以delegate是一對一關系。
block是delegate的另一種形式,是函數式編程的一種形式。使用場景跟delegate一樣,相比delegate更靈活,而且代理的實現更直觀。
KVO一般的使用場景是數據,需求是數據變化,比如股票價格變化,我們一般使用KVO(觀察者模式)。delegate一般的使用場景是行為,需求是需要別人幫我做一件事情,比如買賣股票,我們一般使用delegate。
Notification一般是進行全局通知,比如利好消息一出,通知大家去買入。delegate是強關聯,就是委托和代理雙方互相知道,你委托別人買股票你就需要知道經紀人,經紀人也不要知道自己的顧客。Notification是弱關聯,利好消息發出,你不需要知道是誰發的也可以做出相應的反應,同理發消息的人也不需要知道接收的人也可以正常發出消息。
請看這兩篇博文 KVC KVO
dispatch_async(dispatch_get_main_queue(), ^{
//需要執行的方法
});
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue]; //主隊列
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
//需要執行的方法
}];
[mainQueue addOperation:operation];
[self performSelector:@selector(method) onThread:[NSThread mainThread] withObject:nil waitUntilDone:YES modes:nil];
[self performSelectorOnMainThread:@selector(method) withObject:nil waitUntilDone:YES];
[[NSThread mainThread] performSelector:@selector(method) withObject:nil];
[[NSRunLoop mainRunLoop] performSelector:@selector(method) withObject:nil];
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES];
-(void)timerMethod
{
//調用類方法
[[self class] staticMethod];
}
-(void)invalid
{
[timer invalid];
timer = nil;
}
typedef struct objc_object *id
id可以理解為指向對象的指針。所有oc的對象 id都可以指向,編譯器不會做類型檢查,id調用任何存在的方法都不會在編譯階段報錯,當然如果這個id指向的對象沒有這個方法,該崩潰還是會崩潰的。
NSObject *指向的必須是NSObject的子類,調用的也只能是NSObjec裡面的方法否則就要做強制類型轉換。
不是所有的OC對象都是NSObject的子類,還有一些繼承自NSProxy。NSObject *可指向的類型是id的子集。
封裝、繼承、多態
設計模式6個原則
設計一個類的功能,如何劃分粒度(單一職責)
接口隔離。
如果有一個鳥類,有飛的動作,一個鴕鳥繼承它是合適的嗎(裡氏替換)
類之間的依賴如何依賴偶合度最小(依賴倒轉)
高層依賴低層,低層不能依賴高層。依賴接口,不能依賴具體的類。
如果A要調用C函數,但C是B的成員類,應該如何設計?(迪米特)
如何設計類,能做到只增加代碼,而不修改代碼,有哪些經驗(開放封閉)
通過設計模式解決。
這些面試題都是 Objective-C基礎面試題,一起來看看。
1、#import和#include的區別,@class代表什麼?
@class一般用於頭文件中需要聲明該類的某個實例變量的時候用到,在m文件中還是需要使用#import
而#import比起#include的好處就是不會引起重復包含
2、談談Object-C的內存管理方式及過程?
1.當你使用new,alloc和copy方法創建一個對象時,該對象的保留計數器值為1.當你不再使用該對象時,你要負責向該對象發送一條release或autorelease消息.這樣,該對象將在使用壽命結束時被銷毀.
2.當你通過任何其他方法獲得一個對象時,則假設該對象的保留計數器值為1,而且已經被設置為自動釋放,你不需要執行任何操作來確保該對象被清理.如果你打算在一段時間內擁有該對象,則需要保留它並確保在操作完成時釋放它.
3.如果你保留了某個對象,你需要(最終)釋放或自動釋放該對象.必須保持retain方法和release方法的使用次數相等.
3、Object-C有私有方法嗎?私有變量呢?
objective-c – 類裡面的方法只有兩種, 靜態方法和實例方法. 這似乎就不是完整的面向對象了,按照OO的原則就是一個對象只暴露有用的東西. 如果沒有了私有方法的話, 對於一些小范圍的代碼重用就不那麼順手了. 在類裡面聲名一個私有方法
@interface Controller : NSObject { NSString *something; }
+ (void)thisIsAStaticMethod;
– (void)thisIsAnInstanceMethod;
@end
@interface Controller (private) -
(void)thisIsAPrivateMethod;
@end
@private可以用來修飾私有變量
在Objective‐C中,所有實例變量默認都是私有的,所有實例方法默認都是公有的
4、Object-C有多繼承嗎?沒有的話用什麼代替?cocoa 中所有的類都是NSObject 的子類
多繼承在這裡是用protocol 委托代理 來實現的
你不用去考慮繁瑣的多繼承 ,虛基類的概念.
ood的多態特性 在 obj-c 中通過委托來實現.
5、內存管理 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的)
6、淺拷貝和深拷貝區別是什麼
簡單的來說就是,在有指針的情況下,淺拷貝只是增加了一個指針指向已經存在的內存,而深拷貝就是增加一個指針並且申請一個新的內存,使這個增加的指針指向這個新的內存,采用深拷貝的情況下,釋放內存的時候就不會出現在淺拷貝時重復釋放同一內存的錯誤
7、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
8、Objective-C中類別和類擴展的區別。
答案:category和extensions的不同在於後者可以添加屬性。另外後者添加的方法是必須要實現的。
extensions可以認為是一個私有的Category。
9、我們說的Objective-C是動態運行時語言是什麼意思?
答案:多態。 主要是將數據類型的確定由編譯時,推遲到了運行時。
這個問題其實淺涉及到兩個概念,運行時和多態。
簡單來說,運行時機制使我們直到運行時才去決定一個對象的類別,以及調用該類別對象指定方法。
多態:不同對象以自己的方式響應相同的消息的能力叫做多態。意思就是假設生物類(life)都用有一個相同的方法-eat;
那人類屬於生物,豬也屬於生物,都繼承了life後,實現各自的eat,但是調用是我們只需調用各自的eat方法。
也就是不同的對象以自己的方式響應了相同的消息(響應了eat這個選擇器)。
因此也可以說,運行時機制是多態的基礎?
10、Objective-C堆和棧的區別?
管理方式:對於棧來講,是由編譯器自動管理,無需我們手工控制;對於堆來說,釋放工作由程序員控制,容易產生memory leak。
申請大小:
棧:在Windows下,棧是向低地址擴展的數據結構,是一塊連續的內存的區域。這句話的意思是棧頂的地址和棧的最大容量是系統預先規定好的,在 WINDOWS下,棧的大小是2M(也有的說是1M,總之是一個編譯時就確定的常數),如果申請的空間超過棧的剩余空間時,將提示overflow。因 此,能從棧獲得的空間較小。
堆:堆是向高地址擴展的數據結構,是不連續的內存區域。這是由於系統是用鏈表來存儲的空閒內存地址的,自然是不連續的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬內存。由此可見,堆獲得的空間比較靈活,也比較大。
碎片問題:對於堆來講,頻繁的new/delete勢必會造成內存空間的不連續,從而造成大量的碎片,使程序效率降低。對於棧來講,則不會存在這個問題,因為棧是先進後出的隊列,他們是如此的一一對應,以至於永遠都不可能有一個內存塊從棧中間彈出
分配方式:堆都是動態分配的,沒有靜態分配的堆。棧有2種分配方式:靜態分配和動態分配。靜態分配是編譯器完成的,比如局部變量的分配。動態分配由alloca函數進行分配,但是棧的動態分配和堆是不同的,他的動態分配是由編譯器進行釋放,無需我們手工實現。
分配效率:棧是機器系統提供的數據結構,計算機會在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執行,這就決定了棧的效率比較高。堆則是C/C++函數庫提供的,它的機制是很復雜的。