簡述OC中內(nèi)存管理機制。與retain配對使用的方法是dealloc還是release,為什么?需要與alloc配對使用的方法是dealloc還是release,為什么?readwrite,readonly,assign,retain,copy,nonatomic 、atomic、strong、weak、unsafe_unretained屬性的作用?
OC使用了一種叫做引用計數(shù)的機制來管理對象,如果對一個對象使用了alloc、[Mutable]copy,retain,那么你必須使用相應的realease或者autorelease。也可以理解為自己生成的對象,自己持有。非自己生成的對象,自己也能持有。不在需要自己持有的對象時釋放。非自己持有的對象無法釋放。生成并持有對象,持有對象,釋放對象,廢棄對象;
readwrite(默認):可讀可寫,表示既有g(shù)etter方法,也有setter方法;
readonly:表示只有g(shù)etter方法,沒有setter方法;
nonatomic:不考慮線程安全;
atomic(默認):線程操作安全;
strong(默認):ARC下和MRC下retain一樣;
weak(ARC下):和(MRC下)assign類似,區(qū)別是當weak指向的內(nèi)存釋放掉后自動置為nil,防止野指針。
unsafe_unretained聲明一個弱引用,但不會自動置為nil,可能會出現(xiàn)野指針。
線程安全下的setter和getter方法:
-(NSString *)value
{
@synchronized(self){
return [[_value retain] autorelease];
}
}
-(void)setValue:(NSString *)aValue
{
@synchronized(self){
[aValue retain];//新對象先retain
[_value release];//釋放舊對象
_value = aValue;//對象賦值
}
}
類變量的@protected ,@private,@public,@package,聲明各有什么含義?
上面的幾個聲明表明的時類成員的作用域;
@private作用范圍只能在自身類(外界既不可訪問,又不能繼承);@protected作用范圍在自身類和子類,如果什么都不加修飾【默認】,(外界不可訪問,但是可以繼承);
@public作用范圍最大,可以在任何地方被訪問(外界即可訪問,又可以繼承);
@package作用范圍在某個框架內(nèi)
線程是什么?進程是什么?二者有什么區(qū)別和聯(lián)系?
線程是CPU獨立運行和獨立調(diào)度的基本單位(可以理解為一個進程中執(zhí)行的代碼片段),進程是資源分配的基本單位(進程是一塊包含了某些資源的內(nèi)存區(qū)域)。進程是線程的容器,真正完成代碼執(zhí)行的是線程,而進程則作為線程的執(zhí)行環(huán)境。一個程序至少包含一個進程,一個進程至少包含一個線程,一個進程中的多個線程共享當前進程所擁有的資源。
談談你對多線程開發(fā)的理解?iOS中有幾種實現(xiàn)多線程的方法?
好處:
1、使用線程可以把程序中占據(jù)時間長的任務放到后臺去處理,如圖片、視頻的下載
2、發(fā)揮多核處理器的優(yōu)勢,并發(fā)執(zhí)行讓系統(tǒng)運行的更快、更流暢,用戶體驗更好
缺點:
1、大量的線程降低代碼的可讀性,
2、更多的線程需要更多的內(nèi)存空間
3、當多個線程對同一個資源出現(xiàn)爭奪的時候要注意線程安全的問題。
iOS有三種多線程編程的技術(shù):
//NSThread(兩種創(chuàng)建方式)
[NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil];
NSThread *myThread = [[NSThread alloc] initWithTarget:self selector:@selector(doSomething:) object:nil];
[myThread start];
//NSOperationQueue
NSOperationQueue *oprationQueue = [[NSOperationQueue alloc] init];
oprationQueue addOperationWithBlock:^{
//這個block語句塊在子線程中執(zhí)行
}
//Grand Central Dispatch (GCD)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 耗時的操作
dispatch_async(dispatch_get_main_queue(), ^{
// 更新界面
});
});
PS:不顯式的創(chuàng)建線程的方法:
用NSObject的類方法 performSelectorInBackground:withObject: 創(chuàng)建一個線程:
[obj performSelectorInBackground:@selector(doSomething) withObject:nil];
線程同步和異步的區(qū)別?iOS中如何實現(xiàn)多線程的同步?
同步:一個線程要等待上一個線程執(zhí)行完之后才能執(zhí)行當前的線程,生活中的例子(上廁所)。
異步:同時去做兩件或者多件事。比如邊聽歌邊看報。
原子操作(atomic)、加鎖(NSLock、NSRecursive、NSConditionLock)、@synchronized
GCD串行隊列,GCD當中的屏障,NSOperationQueue設(shè)置最大并發(fā)數(shù)為maxConcurrentOperationCount = 1
獲取一臺設(shè)備唯一標識的方法有哪些?
MAC地址,udid,keychain,open udid,廣告標識IDFA-identifierForIdentifier
iOS類是否可以多繼承?如果沒有,那可以用其他方法實現(xiàn)嗎?簡述實現(xiàn)過程
不可以,可以通過消息轉(zhuǎn)發(fā)、delegate和protocol和類別來實現(xiàn)類似多繼承
堆和棧的區(qū)別?
棧區(qū)(stack)--由編譯器自動分配釋放,存放函數(shù)的參數(shù)值、局部變量的值。
堆區(qū)(heap)--一般由程序員分配釋放。
全局區(qū)(靜態(tài)區(qū))(static)--全局變量和靜態(tài)變量。程序結(jié)束后由系統(tǒng)釋放。
文字常量區(qū)--常量字符串存放在這里。程序結(jié)束后由系統(tǒng)釋放。
程序代碼區(qū)—存放函數(shù)體的二進制文件。
棧:只要棧的剩余空間大于所申請空間,系統(tǒng)將為程序提供內(nèi)存,否則將報異常提示棧溢 出。
堆:首先應該知道操作系統(tǒng)有一個記錄空閑內(nèi)存地址的鏈表,當系統(tǒng)收到程序的申請時,會遍歷該鏈表,尋找第一個空間大于所申請空間的堆結(jié)點,然后將該結(jié)點從空閑結(jié)點鏈表中刪除,并將該結(jié)點的空間分配給程序,另外,對于大多數(shù)系統(tǒng),會在這塊內(nèi)存空間中的首地址處記錄本次分配的大小,這樣,代碼中的delete語句才能正確的釋放本內(nèi)存空間。另外,由于找到的堆結(jié)點的大小不一定正好等于申請的大小,系統(tǒng)會自動的將多余的那部分重新放入空閑鏈表中。
iOS本地數(shù)據(jù)存儲都有哪幾種方式?iOS如何實現(xiàn)復雜對象的存儲?
NSKeyedArchiver(歸檔)采用歸檔的形式來保存數(shù)據(jù),該數(shù)據(jù)對象需要遵守NSCoding協(xié)議,并且該對象對應的類必須提供encodeWithCoder:和initWithCoder:方法;
NSUserDefaults:用來保存應用程序設(shè)置和屬性、用戶保存的數(shù)據(jù)。用戶再次打開程序或開機后這些數(shù)據(jù)仍然存在。NSUserDefaults可以存儲的數(shù)據(jù)類型包括:NSData、NSString、NSNumber、NSDate、NSArray、NSDictionary;
Write寫入方式:永久保存在磁盤中;
SQLite(FMDB、CoreData) ;
NSCoding + NSKeyedArchiver實現(xiàn)復雜對象的存儲;
iOS的動態(tài)性
iOS的動態(tài)性來自三個方面:動態(tài)類型、動態(tài)綁定、動態(tài)載入、SEL類型
1、動態(tài)類型<弱類型>(id):在代碼的運行階段判斷代碼的類型,使用id類型可以讓應用在“運行時”使用任何類型來替換。動態(tài)類型讓程序更加靈活,但是會使數(shù)據(jù)的統(tǒng)一性降低和代碼的可讀性。我們常用靜態(tài)類型<強類型>(如NSString),使用靜態(tài)類型編譯器可以完全分析你的代碼,這讓代碼的性能和可預知性更高。
2、動態(tài)綁定:讓代碼在運行時判斷需要調(diào)用什么方法,而不是在編譯時。動態(tài)類型和動態(tài)綁定使得選擇哪個接收者已經(jīng)調(diào)用什么方法都放到運行時去完成。
3、動態(tài)載入:應用程序可以根據(jù)需要加載可執(zhí)行代碼以及資源,而不是 在啟動時就加載所有資源。
4、SEL類型 iOS在編譯的時候會根據(jù)方法的名字(包括參數(shù)序列),生成一個用來區(qū)分這個方法的唯一的ID,這個ID是SEL類型的,SEL的本質(zhì)就是類方法的編號[函數(shù)地址]。(類似C語言里面的函數(shù)指針,但是OC的類不能直接使用函數(shù)指針,這樣只能做一個@selector語法來取。注意:@selector是查找當前類(含子類)的方法。)
深拷貝和淺拷貝的理解?
深拷貝拷貝的是內(nèi)容,淺拷貝拷貝的是指針。深拷貝和淺拷貝最大的區(qū)別就是子類對象的地址是否改變,如果子類對象的地址改變那么就是深拷貝。
怎樣實現(xiàn)一個singleton的類?
static SingletonSample * instance;
+( SingletonSample *)sharedInstance{
@synchronized(self){//這個東西其實就是 一個加鎖。如果self 其他線程訪問,則會阻塞。這樣做一般是用來對單例 進行一個死鎖的保護
if (!instance) {
instance = [[super allocWithZone:NULL] init];
}
}
return instance;
}
//第二種方式
+ (SingletonSample *) sharedInstance
{
static SingletonSample *instance;
static dispatch_once_t onceToken; // 鎖
dispatch_once (& onceToken, ^ { // 最多調(diào)用一次,
instance = [[self alloc] init];
});
return instance;
}
RunLoop是什么?
一個RunLoop就是一個時間處理的循環(huán),用來不停的調(diào)度工作以及處理輸入時間。使用runloop的目的是讓你的線程在有工作的時候忙于工作,而沒工作的時候處于休眠狀態(tài)。runloop的設(shè)計是為了減少cpu無謂的空轉(zhuǎn);
簡述應用程序按Home鍵進入后臺時的生命周期,以及從后臺回到前臺時的生命周期?
應用程序的狀態(tài):
Not running 未運行,程序沒啟動
Inactive 未激活,程序在前臺運行,不過沒接受到事件,沒有事件處理的狀態(tài)下通常處于這個狀態(tài)。
Active 激活 程序在前臺并且接收到了事件
Backgound 后臺 程序在后臺而且能執(zhí)行代碼,大多數(shù)程序進入這個狀態(tài)后會在在這個狀態(tài)上停留一會。
Suspended 掛起 程序在后臺不能執(zhí)行代碼。
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions
//告訴代理進程啟動但還沒進入狀態(tài)保存
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
// 告訴代理啟動基本完成程序準備開始運行
- (void)applicationWillResignActive:(UIApplication *)application
// 當應用程序?qū)⒁敕腔顒訝顟B(tài)執(zhí)行,在此期間,應用程序不接收消息或事件,比如來電話了
- (void)applicationDidBecomeActive:(UIApplication *)application
// 當應用程序入活動狀態(tài)執(zhí)行,這個剛好跟上面那個方法相反
- (void)applicationDidEnterBackground:(UIApplication *)application
// 當程序被推送到后臺的時候調(diào)用。所以要設(shè)置后臺繼續(xù)運行,則在這個函數(shù)里面設(shè)置即可
- (void)applicationWillEnterForeground:(UIApplication *)application
//當程序從后臺將要重新回到前臺時候調(diào)用,這個剛好跟上面的那個方法相反。
- (void)applicationWillTerminate:(UIApplication *)application
//當程序?qū)⒁顺鍪潜徽{(diào)用,通常是用來保存數(shù)據(jù)和一些退出前的清理工作。這個需要要設(shè)置UIApplicationExitsOnSuspend的鍵值。
- (void)applicationDidFinishLaunching:(UIApplication*)application
//當程序載入后執(zhí)行
描述應用程序的啟動順序?
1、程序入口main函數(shù)創(chuàng)建UIApplication實例和UIApplication代理實例
2、在UIApplication代理實例中重寫啟動方法,設(shè)置第一ViewController
3、在第一ViewController中添加控件,實現(xiàn)對應的程序界面。
為什么很多內(nèi)置類如UITableViewControl的delegate屬性都是assign而不是retain?請舉例
防止循環(huán)引用,
Student * str=[];
Teacher *teacher=[[Teacher alloc] init];
Student * student=[[Student alloc] init];
teacher.delegate=student;
student.delegate= teacher;
在teacher中dealloc會release當前的Delegate,就會觸發(fā)student對象release,繼而也會導致student執(zhí)行dealloc,在student中也會release自己的delegate,產(chǎn)生循環(huán)了。
簡述你對UIView、UIWindow和CALayer的理解?
UIView繼承于UIResponder, UIResponder繼承于NSObject,UIView可以響應用戶事件。CALayer繼承于NSObject,所以CALayer不能響應事件;
UIView構(gòu)建界面,UIView側(cè)重于對內(nèi)容的管理,CALayer側(cè)重于對內(nèi)容的繪制。
UIView是用來顯示內(nèi)容的,可以處理用戶事件;CALayer是用來繪制內(nèi)容的,對內(nèi)容進行動畫處理,依賴與UIView來進行顯示,不能處理用戶事件;
簡述NotificationCenter、KVC、KVO、Delegate?并說明它們之間的區(qū)別?
Notification:觀察者模式,controller向defaultNotificationCenter添加自己的 notification,其他類注冊這個notification就可以收到通知,這些類可以在收到通知時做自己的操作(多觀察者默認隨機順序發(fā)通知給 觀察者們,而且每個觀察者都要等當前的某個觀察者的操作做完才能輪到他來操作,可以用NotificationQueue的方式安排觀察者的反應順序,也 可以在添加觀察者中設(shè)定反映時間,取消觀察需要在viewDidUnload 跟dealloc中都要注銷);
KVC鍵值編碼,可以直接通過字符串的名字(key)來間接訪問屬性的機制,而不是通過調(diào)用getter和setter方法訪問;
KVO:觀測指定對象的屬性,當指定對象的屬性更改之后會通知相應的觀察者;
delegate:一對一,delegate遵循某個協(xié)議并實現(xiàn)協(xié)議聲明的方法;
分別描述類別(categories)和延展(extensions)是什么?以及兩者的區(qū)別?繼承和類別在實現(xiàn)中有何區(qū)別?為什么Category只能為對象添加方法,卻不能添加成員變量?
category類目:在不知道源碼的情況下為一個類擴展方法,extension:為一個類聲明私有方法和變量。
繼承是創(chuàng)建了一個新的類,而類別只是對類的一個擴展,還是之前的類。
類目的作用就是為已知的類添加方法;
談談你對MVC的理解?為什么要用MVC?在Cocoa中MVC是怎么實現(xiàn)的?你還熟悉其他的OC設(shè)計模式或別的設(shè)計模式嗎?
MVC是Model-VIew-Controller,就是模型-視圖-控制器, MVC把軟件系統(tǒng)分為三個部分:Model,View,Controller。
Cocoa中所有的控件、窗口等都繼承自 UIView,對應MVC中的 V。UIView及其子類主要負責UI的實現(xiàn),而UIView所產(chǎn)生的事件都可以采用委托的方式,交給UIViewController實現(xiàn)。對于不同的 UIView,都有相應的UIViewController 對應MVC中的C。比如在iPhone OS上常用的UITableView,它所對應的Controller就是UITableViewController。至于MVC中的M,那需要根據(jù)用 戶自己的需求來實現(xiàn)了。
MVC可以幫助確保幫助實現(xiàn)程序最大程度的可重用性。各MVC元素彼此獨立運作,通過分開這些元素,可以構(gòu)建可維護,可獨立更新的程序組建。
單例模式,delegate設(shè)計模式,target-action設(shè)計模式,觀察者模式,MVVM
說說響應鏈
當事件發(fā)生的時候,響應鏈首先被發(fā)送給第一個響應者(往往是事件發(fā)生的視圖,也就是用戶觸摸屏幕的地方)。事件將沿著響應者鏈一直向下傳遞,直到被接受并作出處理。一般來說,第一響應這是個視圖對象或者其子類,當其被觸摸后事件就交由它處理,如果他不處理,時間就會被傳遞給視圖控制器對象;
UIViewController(如果存在),然后是它的父視圖對象(superview),以此類推知道頂層視圖。接下來會沿著頂層視圖(top view)到窗口(UIwindow 對象) 再到程序的(UIApplication對象),如果整個過程都沒有響應這個事件,則該事件被丟棄,一般情況下,在響應鏈中只要有對象處理事件,事件就會被傳遞 ;
典型的響應路線圖如: First Responser --> The Window -->The Applicationn --> App Delegate
什么是沙盒(sandbox)?沙盒包含哪些文件,描述每個文件的使用場景。如何獲取這些文件的路徑?如何獲取應用程序包中文件的路徑?
iOS應用程序只能在為該改程序創(chuàng)建的文件系統(tǒng)中讀取文件,不可以去其它地方訪問,此區(qū)域被成為沙盒,所以所有的非代碼文件都要保存在此,例如圖像,圖標,聲音,映像,屬性列表,文本文件等。
默認情況下,每個沙盒含有3個文件夾:Documents, Library 和 tmp。
Documents:蘋果建議將程序中建立的或在程序中瀏覽到的文件數(shù)據(jù)保存在該目錄下,iTunes備份和恢復的時候會包括此目錄
Library:存儲程序的默認設(shè)置或其它狀態(tài)信息;
Library/Caches:存放緩存文件,iTunes不會備份此目錄,此目錄下文件不會在應用退出刪除
tmp:提供一個即時創(chuàng)建臨時文件的地方。
iTunes在與iPhone同步時,備份所有的Documents和Library文件。iPhone在重啟時,會丟棄所有的tmp文件!
談談對性能優(yōu)化的看法,如何做?
從用戶體驗出發(fā):
1、程序logging不要太長、
2、相同數(shù)據(jù)不做重復獲取、
3、昂貴資源要重用(cell、sqlite、date),
4、良好的編程習慣和程序設(shè)計:選擇正確的集合對象和算法來進行編程、選擇適合的數(shù)據(jù)存儲格式(plist、SQLite)、優(yōu)化SQLite查詢語句
5、數(shù)據(jù)資源方面的優(yōu)化(緩存和異步加載)
解決方案:
? 能夠發(fā)現(xiàn)問題
? 利用log或工具分析問題原因
? 假設(shè)問題原因
? 改進代碼和設(shè)計