標籤:
//想面試的童鞋們來看看自己會多少, 老鳥可以無視直接繞過...
1. Object-c的類可以多重繼承麼?可以實現多個介面麼?Category是什麼?重寫一個類的方式用繼承好還是分類好?為什麼?與Extension(延展)的主要區別?
答: Object-c的類不可以多重繼承;可以實現多個介面,通過實現多個介面可以完成C++的多重繼承;Category是類別(分類, 類目),一般情況用分類好,用Category去重寫類的方法,僅對本Category有效,不會影響到其他類與原有類的關係。通常情況下Category只可以添加方法, 而Extension可以添加方法和屬性(都是私人的);但是Category可以通過runtime.h中objc_getAssociatedObject / objc_setAssociatedObject來訪問和產生關聯對象。通過這種方法來類比產生屬性。(需要重寫屬性的set和get方法)
2. #import 跟#include 又什麼區別,@class呢, #import<> 跟 #import””又什麼區別?
答:#import是Objective-C匯入標頭檔的關鍵字,#include是C/C++匯入標頭檔的關鍵字,使用#import標頭檔會自動只匯入一次,不會重複匯入(有條件編譯 if define);@class告訴編譯器某個類的聲明,當執行時,才去查看類的實現檔案,可以解決標頭檔的相互包含避免循環參考;#import<>用來包含系統的標頭檔,#import””用來包含使用者標頭檔。
3. 屬性readwrite,readonly,assign,retain,copy,nonatomic 各是什麼作用,在那種情況下用?
1. readwrite 是可讀可寫特性;需要產生getter方法和setter方法時;
2. readonly 是唯讀特性 只會產生getter方法 不會產生setter方法 ;不希望屬性在類外改變;
3. assign 是賦值特性,setter方法將傳入參數賦值給執行個體變數;僅設定變數時;
4. retain 表示持有特性,setter方法將傳入參數先保留,再賦值,傳入參數的retaincount會+1;
5. copy 表示賦值特性,setter方法將傳入對象複製一份;需要完全一份新的變數時;
6. nonatomic 非原子操作,決定編譯器產生的setter getter是否是原子操作,atomic表示多安全執行緒,一般使用nonatomic;atomic:設定成員變數的@property屬性時,預設為atomic,提供多安全執行緒。在多線程環境下,原子操作是必要的,否則有可能引起錯誤的結果。加了atomic,setter函數會變成下面這樣:
{lock}
if (property != newValue) {
[property release];
property = [newValue retain];
}
{unlock}
nonatomic:禁止多線程,變數保護,提高效能。
4.對於語句NSString*obj = [[NSData alloc] init]; obj在編譯時間和運行時分別是什麼類型的對象?
編譯時間是NSString的類型;運行時是NSData類型的對象
5.常見的object-c的資料類型有那些, 和C的基礎資料型別 (Elementary Data Type)有什麼區別?如:NSInteger和int
object-c的資料類型有NSString,NSNumber,NSArray,NSMutableArray,NSData等等,這些都是class,建立後便是對象,而C語言的基礎資料型別 (Elementary Data Type)int,只是一定位元組的記憶體空間,用於存放數值;NSInteger是基礎資料型別 (Elementary Data Type),並不是NSNumber的子類,當然也不是NSObject的子類。NSInteger是基礎資料型別 (Elementary Data Type)Int或者long的別名(NSInteger的定義typedef long NSInteger),它的區別在於,NSInteger會根據系統是32位還是64位來決定是本身是int還是long。
6.id 聲明的對象有什麼特性?
id 聲明的對象具有運行時的特性,即可以指向任意類型的objcetive-c的對象;
7.Objective-C如何進行記憶體管理的,說說你的看法和解決方案?OC有記憶體回收機智嗎?iOS有記憶體回收機智嗎?
Objective-C的記憶體管理主要有三種方式ARC(自動記憶體計數)、手動記憶體計數、記憶體池。
1. (Garbage Collection)(記憶體回收)自動記憶體計數:這種方式和java類似,在你的程式的執行過程中。始終有一個高人在背後準確地幫你收拾垃圾,你不用考慮它什麼時候開始工作,怎樣工作。你只需要明白,我申請了一段記憶體空間,當我不再使用從而這段記憶體成為垃圾的時候,我就徹底的把它忘記掉,反正那個高人會幫我收拾垃圾。遺憾的是,那個高人需要消耗一定的資源,在攜帶裝置裡面,資源是緊俏商品所以iPhone不支援這個功能。
解決: 通過alloc – initial方式建立的, 建立後引用計數+1, 此後每retain一次引用計數+1, 那麼在程式中做相應次數的release就好了.
2. (Reference Counted)手動記憶體計數:就是說,從一段記憶體被申請之後,就存在一個變數用於儲存這段記憶體被使用的次數,我們暫時把它稱為計數器,當計數器變為0的時候,那麼就是釋放這段記憶體的時候。比如說,當在程式A裡面一段記憶體被成功申請完成之後,那麼這個計數器就從0變成1(我們把這個過程叫做alloc),然後程式B也需要使用這個記憶體,那麼計數器就從1變成了2(我們把這個過程叫做retain)。緊接著程式A不再需要這段記憶體了,那麼程式A就把這個計數器減1(我們把這個過程叫做release);程式B也不再需要這段記憶體的時候,那麼也把計數器減1(這個過程還是release)。當系統(也就是Foundation)發現這個計數器變成了0,那麼就會調用記憶體回收程式把這段記憶體回收(我們把這個過程叫做dealloc)。順便提一句,如果沒有Foundation,那麼維護計數器,釋放記憶體等等工作需要你手工來完成。
解決:一般是由類的靜態方法建立的, 函數名中不會出現alloc或init字樣, 如[NSString string]和[NSArray arrayWithObject:], 建立後引用計數+0, 在函數出棧後釋放, 即相當於一個棧上的局部變數. 當然也可以通過retain延長對象的生存期.
3. (AutoRealeasePool)記憶體池:可以通過建立和釋放記憶體池控制記憶體申請和回收的時機.
解決:是由autorelease加入系統記憶體池, 記憶體池是可以嵌套的, 每個記憶體池都需要有一個建立釋放對, 就像main函數中寫的一樣. 使用也很簡單, 比如[[[NSString alloc]initialWithFormat:@”Hey you!”] autorelease], 即將一個NSString對象加入到最內層的系統記憶體池, 當我們釋放這個記憶體池時, 其中的對象都會被釋放.
8. Object C中建立線程的方法是什麼?如果在主線程中執行代碼,方法是什麼?如果想延時執行代碼、方法又是什麼?
線程建立有三種方法:使用NSThread建立、使用GCD的dispatch、使用子類化的NSOperation,然後將其加入NSOperationQueue;在主線程執行代碼,方法是performSelectorOnMainThread,如果想延時執行代碼可以用performSelector:onThread:withObject:waitUntilDone:
9.描述一下iOS SDK中如何?MVC的開發模式
MVC是模型、視圖、控制器開發模式,對於iOS SDK,所有的View都是視圖層的,它應該獨立於模型層,由視圖控制層來控制。所有的使用者資料都是模型層,它應該獨立於視圖。所有的ViewController都是控制層,由它負責控制視圖,訪問模型資料, 實現模型與視圖之間的通訊。
10.淺複製和深複製的區別?
答案:淺層複製:只複製指向對象的指標,而不複製引用對象本身。
深層複製:複製引用對象本身。意思就是說我有個A對象,複製一份後得到A_copy對象後,對於淺複製來說,A和A_copy指向的是同一個記憶體資源,複製的只不過是一個指標,對象本身資源還是只有一份,那如果我們對A_copy執行了修改操作,那麼發現A引用的對象同樣被修改,這其實違背了我們複製拷貝的一個思想。深複製就好理解了,記憶體中存在了兩份獨立對象本身。
11. 什麼是KVO和KVC?
答案:kvc:鍵 – 值編碼是一種間接訪問對象的屬性使用字串來識別屬性,而不是通過調用存取方法,直接或通過執行個體變數訪問的機制。
kvo:索引值觀察機制,他提供了觀察某一屬性變化的方法,極大的簡化了代碼。
比如我自訂的一個button
[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
{
if ([keyPath isEqualToString:@"highlighted"] ) {
[self setNeedsDisplay];
}
}
對於系統是根據keypath去取的到相應的值發生改變,理論上來說是和kvc機制的道理是一樣的。
對於kvc機制如何通過key尋找到value:
“當通過KVC調用對象時,比如:[self valueForKey:@”someKey”]時,程式會自動試圖通過幾種不同的方式解析這個調用。首先尋找對象是否帶有 someKey 這個方法,如果沒找到,會繼續尋找對象是否帶有someKey這個執行個體變數,如果還沒有找到,程式會繼續試圖調用 -(id) valueForUndefinedKey:這個方法。如果這個方法還是沒有被實現的話,程式會拋出一個NSUndefinedKeyException異常錯誤(crash)。
(Key-Value Coding尋找方法的時候,不僅僅會尋找someKey這個方法,還會尋找getsomeKey這個方法,前面加一個get,或者_someKey以及_getsomeKey這幾種形式。同時,尋找執行個體變數的時候也會不僅僅尋找someKey這個變數,也會尋找_someKey這個變數是否存在。)
設計valueForUndefinedKey:該方法的主要目的是當你使用-(id)valueForKey方法從對象中請求值時,對象能夠在錯誤發生前,有最後的機會響應這個請求.
12. 我們說的oc是動態運行時runtime語言是什麼意思?
答案:多態。 主要是將資料類型的確定由編譯時間,延遲到了運行時。
這個問題其實淺涉及到兩個概念,運行時和多態。
簡單來說,運行時機制使我們直到運行時才去決定一個對象的類別,以及調用該類別對象指定方法。多態:不同對象以自己的方式響應相同的訊息的能力叫做多態。意思就是假設生物類(life)都擁有一個相同的方法-eat;那人類屬於生物,豬也屬於生物,都繼承了life後,實現各自的eat,但是調用是我們只需調用各自的eat方法。也就是不同的對象以自己的方式響應了相同的訊息(響應了eat這個選取器).因此也可以說,運行時機制是多態的基礎.
13 什麼是推送訊息?
答案:第一步:把手機的bouldID(APP的唯一標識)和UDID(手機的唯一標識)發送給APNS
第二步:APNS接收到以後, 發送一個Token到使用者的手機上邊
第三步:使用者把Token發送給想要被推送的伺服器
第四步:伺服器把Token和要推送的訊息一塊發給APNS
第五步:APNS根據Token找到使用者, 把訊息以喚醒的方式推送過來
14. 寫一個單例建立方法的實現部分
答案:1.加鎖
+ (Singleton *)shareInstance
{
@synchronized(self){//給此方法加上一個同步鎖,限制相同時間兩個線程不能同時訪問
if (s == nil) {
s = [[Singleton alloc] init];
}
}
return s;
2.GCD
//建立一個單例
+ (instancetype)shareTotalDownloader{
static TotalDownloader *total = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
total = [[TotalDownloader alloc] init];
});
return total;
}
}
15. frame和bounds有什麼不同?
答案:frame指的是:該view在父view座標系統中的位置和大小。(參照點是父親的座標系統)
bounds指的是:該view在本身座標系統中 的位置和大小。(參照點是本身座標系統)
16. iOS開發你用過哪些動畫?
答案:常用的有:UIView動畫,CALayer動畫, Block動畫, 幀動畫(gif)等
17. 在iPhone應用中如何儲存資料?
答案:有以下幾種儲存機制:
1.通過遠程服務,儲存在伺服器上
2.通過NSUserDefault,將對象儲存在本地檔案中
3.通過SQlite或CoreData儲存在本地檔案資料庫中。
18. 談談對Block 的理解?並寫出一個使用Block執行UIVew動畫?
答案:Block是可以擷取其他函數局部變數的匿名函數,其不但方便開發,並且可以大幅提高應用的執行效率(多核心CPU可直接處理Block指令)
[UIView transitionWithView:self.view
duration:0.2
options:UIViewAnimationOptionTransitionFlipFromLeft
animations:^{ [[blueViewController view] removeFromSuperview]; [[self view] insertSubview:yellowViewController.view atIndex:0]; }
completion:NULL];
19. 在項目什麼時候選擇使用GCD,什麼時候選擇NSOperation?
項目中使用NSOperation的優點是NSOperation是對線程的高度抽象,在項目中使用它,會使項目的程式結構更好,子類化NSOperation的設計思路,是具有物件導向的優點(複用、封裝),使得實現是多線程支援,而介面簡單,建議在複雜項目中使用。
項目中使用GCD的優點是GCD本身非常簡單、易用,對於不複雜的多線程操作,會節省代碼量,而Block參數的使用,會是代碼更為易讀,建議在簡單項目中使用。
20. Block
1 使用block和使用delegate完成委託模式有什麼優點?
首先要瞭解什麼是委託模式,委託模式在iOS中大量應用,其在設計模式中是適配器模式中的對象適配器,Objective-C中使用id類型指向一切對象,使委託模式更為簡潔。瞭解委託模式的細節:
2.簡單說一下block和代理的區別
代理:需要寫協議,代理方法和設定代理對象 block需要定義block, 實現block,調用block
delegate:
1,“一對一”,對同一個協議,一個對象只能設定一個代理delegate,所以單例對象就不能用代理;
2,代理更注重過程資訊的傳輸:比如發起一個網路請求,可能想要知道此時請求是否已經開始、是否收到了資料、資料是否已經接受完成、資料接收失敗
block:
1:寫法更簡練,不需要寫protocol、函數等等
2,block注重結果的傳輸:比如對於一個事件,只想知道成功或者失敗,並不需要知道進行了多少或者額外的一些資訊
3,block需要注意防止循環參考:
(ARC中,Block中如果引用了__strong修飾符的自動變數,則相當於Block對該變數的引用計數+1, 在ARC下,由於__block抓取的變數一樣會被Block retain,所以必須用弱引用才可以解決循環參考問題,iOS 5之後可以直接使用__weak,之前則只能使用__unsafe_unretained了,__unsafe_unretained缺點是指標釋放後自己不會置空)
ARC:
__weak typeof(self) weakSelf = self;
[yourBlock:^(NSArray *repeatedArray, NSArray *incompleteArray) {
[weakSelf doSomething];
}];
非ARC:
__block typeof(self) weakSelf = self;
[yourBlock:^(NSArray *repeatedArray, NSArray *incompleteArray) {
[weakSelf doSomething];
}];
iOS開發面試題(中級)