1.簡述OC中內存管理機制
- 答:內存管理機制:使用引用計數管理,分為ARC和MRC,MRC需要程序員自己管理內存,ARC則不需要.但是并不是 所有對象在ARC環境下均不需要管理內存,子線程和循環引用并不是這樣.與retain配對使用的是release,retain代表引用計 數+1,release代表引用計數-1,當引用計數減為0時,對象則被系統自動銷毀.與alloc配對使用的是dealloc,alloc代表為對象開 辟內存空間,dealloc則代表銷毀對象的內存空間.
2.readwrite,readonly,assign,retain,copy,nonatomic,atomic,strong,weak的作用?
- 答:讀寫屬性:readonly和readwrite; 語義屬性:assign/retain/copy; 原子性:nonatomic.
① readwrite代表可讀,可寫,即有setter和getter方法,是默認屬性.readonly代表只可讀,即只有get方法,因為不會生成setter方法,所以它不可以和copy/retain/assign組合使用.
② weak和assign均是弱引用,assign修飾基本數據類型,weak修飾對象類型.strong和weak用于ARC下(ARC下的代理使用 weak,block塊使用copy).strong相當于retain.weak相當于assign;assign/retain/copy這些屬性用 于指定set訪問器的語義,也就是說,這些屬性決定了以何種方式對數據成員賦值.
assign,直接賦值,引用計數不改變,適用于基本數據類型.
retain,淺拷貝,使用的是原來的內存空間,只能適用于Objective-C對象類型,而不能適用于Core Foundation對象(retain會增加對象的引用計數,而基本數據和Core Foundation對象都沒有引用計數).
copy:對象的拷貝,新申請一塊內存空間,并把原始內容復制到那片空間.新對象的引用計數為1,此屬性只對那些遵循了NSCopy協議的對象類型有效.③nonatomic,非原子性訪問,不加同步,是異步操作.默認為atomic,原子操作,atomic是Objc使用的一種線程保護技術,基本上來 講,是防止在寫未完成的時候被另外一個線程讀取,造成數據錯誤,而這種機制是消耗系統內存資源的,所以在移動端,都選擇nonatomic.
-
另: 內存分為5個區,分別是棧區,堆區,全局區,文字常量區,程序代碼區.
- 棧區:由編譯器自動分配釋放,不需要管理內存.
- 堆區:一般有程序員分配釋放.
- 全局區:存放全局變量和靜態變量.
- 文字常量區:存放常量字符串.
- 程序代碼區:存放二進制代碼.
3.類變量的@protected,@private,@public,@package,聲明各有什么含義?
- @protected 受保護的.本類,子類可見.
- @private 私有的,類內可用
- @public 公有的,類內,子類,外部均可用
- @package 可見度在@protected和@public之間,這個類型最常用于框架類的實例變量.
4.線程是什么?進程又是什么?區別和聯系.
- 進程:正在運行的程序,負責程序的內存分配.
- 線程:線程是進程中一個獨立執行的控制單元(路徑),一個進程至少包含一條線程,即主線程.
創建線程的目的:開辟一條新的執行路徑,運行指定的代碼,與主線程的代碼實現同時執行.
5.對多線程開發的理解,iOS中有幾種實現多線程的方式.
- 多線程的使用場景:防止卡頓,可以同時完成多個任務,且不影響主線程,把耗時操作放在子線程中執行,但是會消耗內存.
- 實現多線程的方式
- ①NSThread(內存需要自己管理.觸發)
- ②NSOperationQueue(不再關注線程,當前可執行任務個數queue.maxConcurrentOperationCount)
- ③GCD
詳解三種實現多線程的方式:
GCD:
GCD里面包含了串行隊列、并行隊列、主隊列、全局隊列。
dispatch_queue_t q = dispatch_queue_create(“qqq”,DISPATCH_QUEUE_SERIAL);//創建一個串行隊列
dispatch_sync(q,^{
});//開啟同步任務
dispatch_async(q,^{
});//開啟異步任務
并行隊列:DISPATCH_QUEUE_CONCURRENT
主隊列:dispatch_queue_t q = dispatch_get_main_queue();
全局隊列:dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
NSThread
獲取當前線程:NSThread * current = [NSThread currentThread];
獲取主線程:NSThread * main = [NSThread mainThread];
使用NSThread創建線程的兩種方式:
- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument;
+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)argument;
暫停當前線程:
[NSThread sleepForTimeInterval:2];
NSOperationQueue
創建一個操作隊列:NSOperationQueue * queue = [[NSOperationQueue alloc]init];
添加NSOperation到NSOperationQueue中:[queue addOperation:operation];
添加一組operation:[queue addOperations:operations waitUntilFinished:NO];
添加一個block形式的operation:[queue addOperationWithBlock:^(){
}];
添加NSOperation的依賴對象:[operation2 addDependency:operation1];
設置隊列的最大操作數:[queue setMaxConcurrentOperationCount:1];
等待options完成:[operation waitUntilFinished];
暫停、繼續queue:[queue setSuspended:YES] [queue setSuspend:NO]
6.線程同步和異步的區別?ios中如何實現線程的同步?
- 同步:任務順序執行,下一個任務依賴于上一任務的完成.
- 異步:任務執行順序不定,一起執行.
- 實現:設置依賴:NSOpreationQueue GCD中的串行隊列.
7.iOS類是否可以多繼承,如果沒有,怎么實現?
- 不可以多繼承.
- 可以通過類目,延展,協議實現多繼承.
- 類目:類目也叫分類,英文category,在沒有原類.m文件的基礎上,給該類添加方法.類目里不能添加實例變量,不 能添加和原始類方法名相同的方法,否則會發生覆蓋.一個類可以添加多個類目,類目中的方法可以成為原始類的一部分,和原始類方法級別相同,可以被子類繼 承.
- 延展:Extension,是一種特殊形式的類目,主要是在一個類的.m里面聲明與實現.作用:就是給某類添加私有方法或者私有變量.
雖然延展是給一個類定義私有方法,但是OC沒有絕對的私有方法,其實還是可以調用的,延展里面聲明的變量只能在該類內部 使用,外界訪問不了.如果是新建文件建的的某類延展.h文件,則不能添加實例變量,如果括號里沒有類目名,則認為延展里面的方法為全都必須實現,如果有, 則可選實現.
類目寫的方法必須實現,延展寫的方法非必須.
8.棧和堆的區別?
- 棧:內存系統管理(系統開辟,系統釋放),先進后出.
- 堆:內存自己管理(自己開辟,自己釋放).先進先出.
9.iOS本地數據存儲都有幾種方式?
- ①.NSkeyedArchiver:采用歸檔的形式來保存數據,該數據對象需要遵守NSCoding協議,并且該對象 對應的類必須提供encodeWithCoder:和initWithCoder:方法.前一個方法告訴系統怎么對對象進行編碼,而后一個方法則是告訴系 統怎么對對象進行解碼.
- ②.NSUserDefaults:用來保存應用程序設置和屬性,用戶保存的數據.用戶再次打開程序或者開機后這些數據 仍然存在.NSUserDefaults可以存儲的數據類型包 括:NSData,NSString,NSNumber,NSDate,NSArray.NSDictionary,其他類型的數據需要先行轉換.
- ③.Write寫入方式:永久保存在磁盤中.具體:a.獲得文件保存的路徑.b.生成該路徑下的文件,c,往文件中寫入數據.d.從文件中讀出數據.
- ④.SQLite:采用SQLite數據庫來存儲數據,SQLite作為一種輕量級數據庫.具體:a.添加SQLite 相關的庫以及頭文件,b.使用數據庫存數數據:打開數據庫,編寫數據庫語句,執行,關閉數據庫.另:寫入數據庫,字符串可以采用char方式,而從數據庫 中取出char類型,當char類型有表示中文字符時,會出現亂碼,這是因為數據庫默認使用ascII編碼方式,所以想要正確從數據庫中取出中文,需要使 用NSString來接受從數據庫取出的字符串.
- ⑤.CoreData:原理是對SQLite的封裝,開發者不需要接觸sql語句,就可以對數據庫進行操作.
10.ios動態類型和動態綁定
- 多態:父類指針指向子類對象.
動態類型:只有在運行期,才能確定其真正類型.
動態加載:根據不同的條件,加載不同的資源.32和64位.
11.深拷貝和淺拷貝的理解.
- 深拷貝;拷貝的內容.
- 淺拷貝:拷貝的指針.
深拷貝如:
NSMutableDictionary * dic = [@{} mutableCopy];
NSMutableArray * ary = [@[] mutableCopy];
12.怎么實現一個singleton的類.
- 單例是一種設計模式,對象只有一個.缺點:對象不會被釋放,如果創建很多的話會占用很多內存,優點:可以當做工具類使用.
static SortDetailsModelDown * single = nil;
+(SortDetailsModelDown *)shareSortDetailsModelDown {
@synchronized(self){
if (!single) {
single = [[SortDetailsModelDown alloc]init]; }
} return single;
}
13.什么是安全釋放?
先釋放再置空.
14.RunLoop是什么?
事件循環,是線程里面的一個組件.主線程的RunLoop是自動開啟的.分為:計時源(timer source),事件源(輸入源):input source.防止CPU中斷(保證程序執行的線程不會被系統終止).
Runloop提供了一種異步執行代碼的機制,并不能并行執行任務,是事件接收和分發機制的一個實現.每一個線程都有其對應的RunLoop,但是默認非主線程的RunLoop是沒有運行的,需要為RunLoop添加至少一個事件源,然后run它.
一般情況下我們是沒有必要去啟動線程的RunLoop的,除非你在一個單獨的線程中需要長時間的檢測某個事件.
RunLoop,正如其名所示,是線程進入和被線程用來響應事件以及調用事件處理函數的地方.
input source傳遞異步事件,通常是來自其他線程和不同程序的消息.
timer source傳遞同步事件.
當有事件發生時,RunLoop會根據具體的事件類型通知應用程序作出響應.
當沒有事件發生時,RunLoop會進入休眠狀態,從而到達省電的目的.
當事件再次發生時,RunLoop會被重新喚醒,處理事件.
一般在開發中很少會主動創建RunLoop,而通常會把事件添加到RunLoop中.
15.什么是序列化和反序列化,可以用來做什么?如何在OC中實現復雜對象的存儲.
序列化和反序列化:歸檔和反歸檔,進行本地化,進行數據存儲.
CoreData:數據托管.有四種存儲方式:xml,sqlite,二進制,內存.
遵循NSCoding協議之后,進行歸檔即可實現復雜對象的存儲.
16.寫一個標準宏MIN,這個宏輸入兩個參數并返回較小的一個.
define MIN(A,B) (A)>(B)?(B):(A)
17.iPhone OS 有沒有垃圾回收機制,簡易闡述一下OC內存管理.
木有.引用計數,ARC和MRC,swift(自動引用計數).
18.簡述應用程序按HOME鍵進入后臺時的生命周期,以及從后臺進入前臺時的生命周期.
//前者:HOME->后臺
- (void)applicationWillResignActive:(UIApplication *)application
- (void)applicationDidEnterBackground:(UIApplication *)application
//后者:后臺->前臺
- (void)applicationWillEnterForeground:(UIApplication *)application
- (void)applicationDidBecomeActive:(UIApplication *)application
//另:各個程序運行狀態時代理的回調
//告訴代理進程啟動但還沒進入狀態保存
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions
//告訴代理啟動基本完成程序準備開始運行
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
//當應用程序將要入非活動狀態執行,在此期間,應用程序不接收消息或事件,比如來電話了
- (void)applicationWillResignActive:(UIApplication *)application
//當應用程序入活動狀態執行,這個剛好跟上面那個方法相反
- (void)applicationDidBecomeActive:(UIApplication *)application
//當程序被推送到后臺的時候調用。所以要設置后臺繼續運行,則在這個函數里面設置即可
- (void)applicationDidEnterBackground:(UIApplication *)application
//當程序從后臺將要重新回到前臺時候調用,這個剛好跟上面的那個方法相反。
- (void)applicationWillEnterForeground:(UIApplication *)application
//當程序將要退出是被調用,通常是用來保存數據和一些退出前的清理工作。這個需要要設置UIApplicationExitsOnSuspend的鍵值。
- (void)applicationWillTerminate:(UIApplication *)application
//當程序載入后執行
- (void)applicationDidFinishLaunching:(UIApplication*)application
在上面8個方法對應的方法中鍵入NSLog打印。
現在啟動程序看看執行的順序:
- 啟動程序
Log[40428:11303] willFinishLaunchingWithOptions
Log[40428:11303] didFinishLaunchingWithOptions
Log[40428:11303] applicationDidBecomeActive
- 按下home鍵
Log[40428:11303] applicationWillResignActive
Log[40428:11303] applicationDidEnterBackground
- 雙擊home鍵,再打開程序
Log[40428:11303] applicationWillEnterForeground
Log[40428:11303] applicationDidBecomeActive
19.ViewController的 alloc,loadView,viewDidLoad,viewWillAppear,viewDidUnload,dealloc,init分別是在 什么時候調用?在自定義ViewController的時候這幾個函數里面應該做什么工作?
- alloc:申請內存時調用.
- loadView:加載視圖時調用.
- viewDidLoad;視圖已經加載后調用.
- viewWillAppear:視圖將要出現時調用.
- viewDidUnload:視圖已經加載但是沒有加載出來時調用.
- dealloc:銷毀該視圖時調用.
- init;初始化該視圖時調用.
20.描述應用程序的啟動順序.
- a.程序入口main函數創建UIApplication實例和UIApplication代理實例.
- b.在UIApplication代理實例中重寫啟動方法,設置根ViewController
- c.在第一ViewController中添加控件,實現應用程序界面.