iOS面試題集錦


一、前言部分

文中的問題多收集整理自網絡,不保證100%准確,還望斟酌采納。 

1、怎樣防止指針的越界使用問題?  

答案:

1 .防止數組越界,必須讓指針指向一個有效的內存地址,   

2. 防止向一塊內存中拷貝過多的內容  

3. 防止使用空指針  

4 .防止改變const修改的指針  

5. 防止改變指向靜態存儲區的內容  

6. 防止兩次釋放一個指針  

7. 防止使用野指針. 

2、http請求方式有哪些?

答案:

      1)GET
  2)HEAD
  3)PUT
  4)DELETE
  5)POST
  6)OPTIONS

3、uiview的圓角屬性設置方法?

答案:

      1)m_mainImgView.layer.cornerRadius = 具體數值;

      2)m_mainImgView.layer.masksToBounds= YES;

4、masksToBounds屬性的作用是什么?

答案:

       決定子layer是否被當前layer的邊界剪切,默認是NO

5、描述iOS程序的運行流程 ?

答案:

      1. 系統調用app的main函數

      2. main函數調用UIApplicationMain.

      3. UIApplicationMain創建sharedapplication instance, UIApplication默認的instance.

      4. UIApplicationMain讀取Info.plist找到主nib文件, 加載nib,把shared applicationinstance 設為nib的owner.

      5. 通過nib文件,創建app的獨立UIWindows object.

      6. 通過nib,實例化了程序的AppDelegate object.

     7. app內部啟動結束,application:didFinishLaunchingWith-Options: 被設定成 wAppDelegate instance.

     8. AppDelegate向UIWindowinstance發makeKeyAndVisible消息, app界面展示給用戶. app准備好接收用戶的操作指令.

6、 iOS內存管理的方式有哪些?

答案:

      手動管理(MRC)   自動內存管理(ARC) 

7、 Object-C有多繼承嗎?沒有的話用什么代替?

答案:

       OC 本身是沒有多繼承的,但是我們可以通過協議來實現類似C++中的多繼承。

8、屬性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 

9、對於語句NSString*obj = [[NSData alloc] init]; obj在編譯時和運行時分別時什么類型的對象?

答案:
  編譯時是NSString的類型;運行時是NSData類型的對象

10、id 聲明的對象有什么特性?

答案:
   id 聲明的對象具有運行時的特性,即可以指向任意類型的objcetive-c的對象;

11、 原子(atomic)跟非原子(non-atomic)屬性有什么區別?

答案:
  1. atomic提供多線程安全。是防止在寫未完成的時候被另外一個線程讀取,造成數據錯誤
  2. non-atomic:在自己管理內存的環境中,解析的訪問器保留並自動釋放返回的值,如果指定了 nonatomic ,

  那么訪問器只是簡單地返回這個值。

12、 類別和類擴展的區別是什么? 

答案:

       category和extensions的不同在於 后者可以添加屬性。另外后者添加的方法是必須要實現的。
       extensions可以認為是一個私有的Category。

13、 在iOS應用中如何保存數據?

答案:

     有以下幾種保存機制:
  1.通過web服務,保存在服務器上
  2.通過NSCoder固化機制,將對象保存在文件中
  3.通過SQlite或CoreData保存在文件數據庫中
 

14、Object-C有私有方法嗎?私有變量呢?

答案:

objective-c– 類里面的方法只有兩種, 靜態方法和實例方法. 這似乎就不是完整的面向對象了,按照OO的原則就是一個對象

只暴露有用的東西. 如果沒有了私有方法的話,對於一些小范圍的代碼重用就不那么順手了. 在類里面聲名一個私有方法

1 @interface Controller : NSObject { NSString *something; } 2 + (void)thisIsAStaticMethod; 3 – (void)thisIsAnInstanceMethod; 4 @end
5 @interface Controller (private) 
6 -(void)thisIsAPrivateMethod; 7 @end

@private可以用來修飾私有變量在Objective‐C中,所有實例變量默認都是私有的,所有實例方法默認都是公有的

15、關鍵字const什么含義?

答案:

  const意味着”只讀”,下面的聲明都是什么意思?
  const int a;
  int const a;
  const int *a;
  int * const a;
  int const * a const;

  前兩個的作用是一樣,a是一個常整型數。第三個意味着a是一個指向常整型數的指針(也就是,整型數是不可修改的,但指針可以)

    第四個意思a是一個 指向整型數的常指針(也就是說,指  針指向的整型數是可以修改的,但指針是不可修改的)。最后一個意味

  着a是一個指向常整型數的常指針(也就是說,指針指向 的整型數是不可修改的,同時指針也是不可修改的)。

  結論:
  關鍵字const的作用是為給讀你代碼的人傳達非常有用的信息,實際上,聲明一個參數為常量是為了告訴了用戶這個參數的應用目的

  如果你曾花很多時間清理其它人留下的垃圾,你就會很快學會感謝這點多余的信息。(當然,懂得用const的程序員很少會留下的

  垃圾讓別人來清理的。)通過給優化器一些附加的信息,使用關鍵字const也許能產生更緊湊的代碼。合理地使用關鍵字const

  可以使編譯器很自然地保護那些不希望被改變的參數,防止其被無意的代碼修改。簡而言之,這樣可以減少bug的出現。

  欲阻止一個變量被改變,可以使用 const 關鍵字。在定義該const 變量時,通常需要對它進行初始化,因為以后就沒有機會再

  去改變它了;
  2)對指針來說,可以指定指針本身為const,也可以指定指針所指的數據為 const,或二者同時指定為const;
  3)在一個函數聲明中,const可以修飾形參,表明它是一個輸入參數,在函數內部不能改變其值;
  4)對於類的成員函數,若指定其為const 類型,則表明其是一個常函數,不能修改類的成員變量;
  5)對於類的成員函數,有時候必須指定其返回值為const 類型,以使得其返回值不為“左值”。

16、關鍵字volatile有什么含義?並給出三個不同例子?

答案:

  一個定義為volatile的變量是說這變量可能會被意想不到地改變,這樣,編譯器就不會去假設這個變量的值了。精確地說就是,

  優化器在用到這個變量時必須每次都小心地重新讀取這個變量的值,而不是使用保存在寄存器里的備份。

  下面是volatile變量的幾個例子:
  1) 並行設備的硬件寄存器(如:狀態寄存器)
  2) 一個中斷服務子程序中會訪問到的非自動變量(Non-automatic variables)
  3)多線程應用中被幾個任務共享的變量

17、一個參數既可以是const還可以是volatile嗎?解釋為什么。

答案:

  是的。一個例子是只讀的狀態寄存器。它是volatile因為它可能被意想不到地改變。它是const因為程序不應該試圖去修改它。

18、 一個指針可以是volatile 嗎?解釋為什么。

答案:
  可以是的。

  盡管這種情況並不常見,但它還是可以。一個例子就是:

  當一個中斷服務子程序企圖去修改一個指向一個buffer指針的時候。

19、static有什么作用?

答案:

  1)函數體內 static 變量的作用范圍為該函數體,不同於 auto 變量,該變量的內存只被分配一次,因此其值在下次調用時

  仍維持上次的值;
  2)在模塊內的 static 全局變量可以被模塊內所用函數訪問,但不能被模塊外其它函數訪問;
  3)在模塊內的 static 函數只可被這一模塊內的其它函數調用,這個函數的使用范圍被限制在聲明它的模塊內;
  4)在類中的 static 成員變量屬於整個類所擁有,對類的所有對象只有一份拷貝;
  5)在類中的 static 成員函數屬於整個類所擁有,這個函數不接收 this 指針,因而只能訪問類的static 成員變量。

20、#import 跟#include 又什么區別,@class呢, #import<> 跟 #import””又什么區別?

答案:
  #import是Objective-C導入頭文件的關鍵字,#include是C/C++導入頭文件的關鍵字, 使用#import頭文件會自動

  只導入一次,不會重復導入,相當於#include和#pragma once;@class告訴編譯器某個類的聲明,當執行時,

  才去查看類的實現文件,可以解決頭文件的相互包含;#import<>用來包含系 統的頭文件,#import””用來包含用

  戶頭文件。

21、線程和進程的區別?

答案:

  進程和線程都是由操作系統所體會的程序運行的基本單元,系統利用該基本單元實現系統對應用的並發性。進程和線程的主要差別

  在於它們是不同的操作系統資源管理方式。進程有獨立的地址空間,一個進程崩潰后,在保護模式下不會對其它進程產生影響,

  而線程只是一 個進程中的不同執行路  徑。線程有自己的堆棧和局部變量,但線程之間沒有單獨的地址空間,一個線程死掉就

  等於整個進程死掉,所以多進程的程序要比多線程的程 序健壯,但在進程切換時,耗費資源較大,效率要差一些。但對於一些要求

  同時進行並且又要共享某些變量的並發操作,只能用線程,不能用進程。

22、堆和棧的區別?

答案:

  管理方式:對於棧來講,是由編譯器自動管理,無需我們手工控制;對於堆來說,釋放工作由程序員控制,容易產生memoryleak。
  申請大小:
  棧:在Windows下,棧是向低地址擴展的數據結構,是一塊連續的內存的區域。這句話的意思是棧頂的地址和棧的最大容量是系統

  預先規定好的,在 WINDOWS下,棧的大小是2M(也有的說是1M,總之是一個編譯時就確定的常數),如果申請的空間超過棧的

  余空間時,將提示overflow。因 此,能從棧獲得的空間較小。
  堆:堆是向高地址擴展的數據結構,是不連續的內存區域。這是由於系統是用鏈表來存儲的空閑內存地址的,自然是不連續的,

  而鏈表的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬內存。由此可見,堆獲得的空間比較靈活,

  也比較大。
  碎片問題:對於堆來講,頻繁的new/delete勢必會造成內存空間的不連續,從而造成大量的碎片,使程序效率降低。對於棧來講,

  則不會存在這個問題,因為棧是先進后出的隊列,他們是如此的一一對應,以至於永遠都不可能有一個內存塊從棧中間彈出
  分配方式:堆都是動態分配的,沒有靜態分配的堆。棧有2種分配方式:靜態分配和動態分配。靜態分配是編譯器完成的,比如局部

  變量的分配。動態分配由alloca函數進行分配,但是棧的動態分配和堆是不同的,他的動態分配是由編譯器進行釋放,無需我們

  手工實現。
  分配效率:棧是機器系統提供的數據結構,計算機會在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的

  指令執行,這就決定了棧的效率比較高。堆則是C/C++函數庫提供的,它的機制是很復雜的。

23、介紹一下Object-C的內存管理機制?

答案:

  1)當你使用new,alloc和copy方法創建一個對象時,該對象的保留計數器值為1.當你不再使用該對象時,你要負責向該對象發送一條

  release或autorelease消息.這樣,該對象將在使用壽命結束時被銷毀.
  2)當你通過任何其他方法獲得一個對象時,則假設該對象的保留計數器值為1,而且已經被設置為自動釋放,你不需要執行任何操作來

   確保該對象被清理.如果你打算在一段時間內擁有該對象,則需要保留它並確保在操作完成時釋放它.
  3)如果你保留了某個對象,你需要(最終)釋放或自動釋放該對象.必須保持retain方法和release方法的使用次數相等.為什么很多

  內置的類,如TableViewController的delegate的屬性是assign不是retain。

  循環引用
  所有的引用計數系統,都存在循環應用的問題。例如下面的引用關系:
     1)對象a創建並引用到了對象b.
     2)對象b創建並引用到了對象c.
     3)對象c創建並引用到了對象b.
  這時候b和c的引用計數分別是2和1。當a不再使用b,調用release釋放對b的所有權,因為c還引用了b,所以b的引用計數為1,

  b不會被釋放。b不釋放,c的引用計數就是1,c也不會被釋放。從此,b和c永遠留在內存中。這種情況,必須打斷循環引用

  通過其他規則來維護引用關系。比如,我們常見的delegate往往是assign方式的屬性而不是retain方式 的屬性,

  賦值不會增加引用計數,就是為了防止delegation兩端產生不必要的循環引用。如果一個UITableViewController對象a

  通過retain獲取了UITableView對象b的所有權,這個UITableView對象b的delegate又是a,如果這個delegate是retain方式的,

  那基本上就沒有機會釋放這兩個對象了。自己在設計使用delegate模式時,也要注意這點。

24、定義屬性時,什么情況使用copy、assign、retain?

答案:  

  assign用於簡單數據類型,如NSInteger,double,bool,
  retain和copy用於對象,
  copy用於當a指向一個對象,b也想指向同樣的對象的時候,如果用assign,a如果釋放,再調用b會crash,如果用copy 的方式,

  a和b各自有自己的內存,就可以解決這個問題。retain 會使計數器加一,也可以解決assign的問題。
  另外:atomic和nonatomic用來決定編譯器生成的getter和setter是否為原子操作。在多線程環境下,原子操作是必要的,

  否則有可能引起錯誤的結果。加了atomic,setter函數會變成下面這樣: 

 if (property != newValue) {    [property release];    property = [newValue retain];  } 

25、對象是什么時候被release的?

答案:

  引用計數為0時。 autorelease實際上只是把對release的調用延遲了,對於每一個Autorelease,系統只是把該Object放入

  了當前的 Autoreleasepool中,當該pool被釋放時,該pool中的所有Object會被調用Release。對於每一個Runloop,

  系統會隱式創建一個Autoreleasepool,這樣所有的release pool會構成一個象CallStack一樣的一個棧式結構,

  在每一個Runloop結束時,當前棧頂的Autoreleasepool會被銷毀,這樣這 個pool里的每個Object

  (就是autorelease的對象)會被release。那什么是一個Runloop呢?一個UI事件,Timercall, delegate call,

   都會是一個新的Runloop

26、iOS有沒有垃圾回收機制?

答案:

       iOS在Objective-c 2.0之后,也提供了垃圾回收機制。但是在iOS移動終端設備中,並不支持垃圾回收機制。

        因此,iPhone並不能對內存進行自動垃圾回收處理(autorelease)。因此需要注意 垃圾回收機制並不是ARC,

        ARC也是需要管理內存的,只不過是隱式的管理內存,編譯器會再適當的地方自動插入retain,release和

        autorelease消息。 

27、介紹一下tableView的重用機制?

答案:

  查看UITableView頭文件,會找到NSMutableArray*  visiableCells,和NSMutableDictnery* reusableTableCells兩個結構。

  visiableCells內保存當前顯示的cells,reusableTableCells保存可重 用的cells。

  TableView顯示之初,reusableTableCells為空,那么 tableViewdequeueReusableCellWithIdentifier:CellIdentifier返回nil。

  開始的cell都是 通過[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]

  來創建,而且cellForRowAtIndexPath只是調用最大顯示cell數的 次數。比如:有100條數據,iPhone一屏最多顯示10個cell。

  程序最開始顯示TableView的情況是:

  1. 用[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]創建10次cell,

  並給cell指定同樣的重用標識(當然,可以為不同顯示類型的 cell指定不同的標識)。並且10個cell全部都加入到visiableCells數組,

  reusableTableCells為空。

  2. 向下拖動tableView,當cell1完全移出屏幕,並且cell11(它也是alloc出來的,原因同上)完全顯示出來的時候。cell11加入到

   visiableCells,cell1移出visiableCells,cell1加入到reusableTableCells。

  3. 接着向下拖動tableView,因為reusableTableCells中已經有值,所以,當需要顯示新的 cell,cellForRowAtIndexPath再次

  被調用的候,tableViewdequeueReusableCellWithIdentifier:CellIdentifier,返回cell1。 cell1加入到visiableCells,

  cell1移出reusableTableCells;cell2移出 visiableCells,cell2加入到reusableTableCells。之后再需要顯示的Cell就可以

  正常重用了。

28、ViewController 的loadView、viewDidLoad、viewDidUnload分別是什么時候調用的,在自定義

  ViewCointroller時在這幾個函數中應該做什么工作?

答案:

  由init、loadView、viewDidLoad、viewDidUnload、dealloc的關系說起
  1)init方法

  在init方法中實例化必要的對象(遵從LazyLoad思想)
  init方法中初始化ViewController本身

  2)loadView方法
  當view需要被展示而它卻是nil時,viewController會調用該方法。不要直接調用該方法。
  如果手工維護views,必須重載重寫該方法
  如果使用IB維護views,必須不能重載重寫該方法

  3)loadView和IB構建view
  你在控制器中實現了loadView方法,那么你可能會在應用運行的某個時候被內存管理控制調用。 如果設備內存不足的時候,

   view 控制器會收到didReceiveMemoryWarning的消息。默認的實現是檢查當前控制器的view是否在使用。 如果它的view

  不在當前正在使用的view hierarchy里面,且你的控制器實現了loadView方法,那么這個view將被release, loadView方法

  將被再次調用來創建一個新的view。

  4)viewDidLoad方法
  viewDidLoad 此方法只有當view從nib文件初始化的時候才被調用。
  重載重寫該方法以進一步定制view
  在iPhone OS 3.0及之后的版本中,還應該重載重寫viewDidUnload來釋放對view的任何索引
  viewDidLoad后調用數據Model

  5)viewDidUnload方法
  當系統內存吃緊的時候會調用該方法(注:viewController沒有被dealloc)
  內存吃緊時,在iPhone OS 3.0之前didReceiveMemoryWarning是釋放無用內存的唯一方式,但是OS 3.0及以后

  viewDidUnload方法是更好的方式在該方法中將所有IBOutlet(無論是property還是實例變量)置為nil

  (系統release view時已經將其release掉了)在該方法中釋放其他與view有關的對象、其他在運行時創建

  (但非系統必須)的對象、在viewDidLoad中被創建的對象、緩存數據等 release對象后,將對象置為nil(IBOutlet只需要將

  其置為nil,系統release view時已經將其release掉了)一般認為viewDidUnload是viewDidLoad的鏡像,因為當view被重新

  請求時,viewDidLoad還會重新被執行viewDidUnload中被release的對象必須是很容易被重新創建的對象(比如在

  viewDidLoad或其他方法中創建的對象),不要release用戶數據或其他很難被重新創建的對象

  6)dealloc方法
  viewDidUnload和dealloc方法沒有關聯,dealloc還是繼續做它該做的事情 

29、ViewController的didReceiveMemoryWarning是在什么時候調用的?默認的操作是什么?

答案:

  當程序接到內存警告時View Controller將會收到這個消息:didReceiveMemoryWarning從iOS3.0開始,不需要重載這個函數,

  把釋放內存的代碼放到viewDidUnload中去。這個函數的默認實現是:檢查controller是否可以安全地釋放它的view(這里加粗的

  view指的是controller的view屬性),比如view本身沒有superview並且可以被很容易地重建(從nib或者loadView函數)。

  如果view可以被釋放,那么這個函數釋放view並調用viewDidUnload。你可以重載這個函數來釋放controller中使用的其他內存。

  但要記得調用這個函數的super實現來允許父類(一般是UIVIewController)釋放view。如果你的ViewController保存着

  view的子view的引用,那么,在早期的iOS版本中,你應該在這個函數中來釋放這些引用。而在iOS3.0或更高版本中,

  你應該在viewDidUnload中釋放這些引用。

30、列舉Cocoa中常見的集中多線程的實現,並談談多線程安全的幾種解決辦法,一般什么地方會用到多線程?

答案:

  NSOperation NSThread
  @sychonized 一般需要做多任務的處理時會用的多線程。

31、怎么理解MVC,在OC中MVC是怎么實現的?

答案:

  MVC設計模式考慮三種對象:模型對象、視圖對象、和控制器對象。模型對象代表特別的知識和專業技能,它們負責保有應用程序

  的數據和定義操作數據的 邏輯。視圖對象知道如何顯示應  用程序的模型數據,而且可能允許用戶對其進行編輯。控制器對象

  是應用程序的視圖對象和模型對象之間的協調者。

32、delegate和notification區別,分別在什么情況下使用?

答案:

  delegate針對one-to-one關系,並且reciever可以返回值給sender;

  notification 可以針對one-to-one/many/none,reciever無法返回值給sender;

  所以,delegate用於sender希望接受到reciever的某個功能反饋值,notification用於通知多個object某個事件。

33、談談對KVC(Key-Value-Coding)與KVO(Key-Value-Observing)(鍵-值-編碼 與 鍵-值-監看)的理解?

答案:

  當通過KVC調用對象時,比如:[self valueForKey:@”someKey”]時,程序會自動試圖通過幾種不同的方式解析這個調用。

  首先查找對象是否帶有 someKey 這個方法,如果沒找到,會繼續查找對象是否帶有someKey這個實例變量(iVar),

  如果還沒有找到,程序會繼續試圖調用 -(id)valueForUndefinedKey:這個方法。如果這個方法還是沒有被實現的話,

  程序會拋出一個 NSUndefinedKeyException異常錯誤。(Key-Value Coding查找方法的時候,不僅僅會查找someKey

  這個方法,還會查找getsomeKey這個方法,前面加一個get,或者_someKey以及 _getsomeKey這幾種形式。同時,

  查找實例變量的時候也會不僅僅查找someKey這個變量,也會查找_someKey這個變量是否存在。)設計valueForUndefinedKey:

  方法的主要目的是當你使用-(id)valueForKey方法從對象中請求值時,對象能夠在錯誤發生前,有最后的機會響應這個請求。

34、self.跟self的區別是什么?

答案:

  self. 表示對象的屬性 self 表示對象本身

35、id、nil分別代表什么?

答案: 

  1)id和void *並非完全一樣。在上面的代碼中,id是指向struct objc_object的一個指針,這個意思基本上是說,id是一個指向任何

  一個繼承了Object(或者NSObject)類的對象。需要注意的是id 是一個指針,所以你在使用id的時候不需要加星號。

  比如id foo=nil定義了一個nil指針,這個指針指向NSObject的一個任意子類。而id *foo=nil則定義了一個指針,這個

  指針指向另一個指針,被指向的這個指針指向NSObject的一個子類。 

  2)nil和C語言的NULL相同,在objc/objc.h中定義。nil表示一個Objctive-C對象,這個對象的指針指向空(沒有東西就是空)。

36、內存管理 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后,一定要在適當的時候進行釋放。

37、談談你對於索引計數的理解?

答案:

  retain值 = 索引計數(ReferenceCounting) NSArray對象會retain(retain值加一)任何數組中的對象。當NSArray被卸載

  (dealloc)的時候,所有數組中的對象會被執行一次釋放(retain值減一)。不僅僅是NSArray,任何收集類 (CollectionClasses)

  都執行類似操作。例如NSDictionary,甚至UINavigationController。Alloc/init建立的對象,索引計數為1。無需將其再次retain

  [NSArray array]和[NSDate date]等“方法”建立一個索引計數為1的對象,但是也是一個自動釋放對象所以是本地臨時對象,

  那么無所謂了。如果是打算在全Class中使用的變量(iVar),則必須retain它。缺省的類方法返回值都被執行了“自動釋放”方法。

  (*如上中的NSArray)在類中的卸載方法“dealloc”中,release所有未被平衡的NS對象。(*所有未被autorelease,

  而retain值為1的)

38、類別的作用是什么?

答案:

  有時我們需要在一個已經定義好的類中增加一些方法,而不想去重寫該類。比如,當工程已經很大,代碼量比較多,或者類中

  已經包住很多方法,已經有其他代碼調用了該類創建對象並使用該類的方法時,可以使用類別對該類擴充新的方法。注意:

  類別只能擴充方法,而不能擴充成員變量。

39、什么是委托(舉例)?

答案:

  委托代理(degegate),顧名思義,把某個對象要做的事情委托給別的對象去做。那么別的對象就是這個對象的代理,代替它

  來打理要做的事。反映到程序中,首先要明確一個對象的委托  方是哪個對象,委托所做的內容是什么。委托機制是一種設計

  模式,在很多語言中都用到的,這只是個通用的思想,網上會有很多關於這方面的介紹。那么在蘋果開發過程中,用到委托的

  程序實現思想如下,我主要拿如何在視圖之間傳輸信息做個例子。譬如:在兩個頁面(UIIview視圖對象)實現傳值,

  用委托(delegate)可以很好做到!
  方法:
     

 1 //類A
 2 @interface A:UIView  3         id transparendValueDelegate;  4  @property(nomatic, retain) idtransparendValueDelegate;  5 @end
 6 
 7 @implemtion A  8 @synthesize transparendValueDelegate  9 -(void)Function 10 { 11       NSString* value = @"hello"; 12       //讓代理對象執行transparendValue動作
13  [transparendValueDelegate transparendValue:value]; 14 } 15 @end
16 
17 //類B
18 @interface B:UIView 19       NSString* value; 20 @end
21 
22 @implemtion B 23 -(void)transparendValue:(NSString*)fromValue 24 { 25       value = fromValue; 26       NSLog(@"the value is %@",value); 27 } 28 @end
29 
30 //下面的設置A代理委托對象為B 31 //在定義A和B類對象處:
32 
33 A* a = [[A alloc] init]; 34 B* b = [[B alloc] init]; 35 a. transparendValueDelegate = b;//設置對象a代理為對象b

 這樣在視圖A和B之間可以通過委托來傳值!

下面這個例子委托有兩類:
1、一個視圖類對象的代理對象為父視圖,子視圖用代理實現讓父視圖顯示別的子視圖
2、同一父視圖下的一個子視圖為另一個子視圖的代理對象,讓另一個子視圖改變自身背景色為給定的顏色
===============================================
規范格式如下:

 1 @protocol TransparendValueDelegate;  2 
 3 @interface A:UIView  4 id< TransparendValueDelegate > m_dTransparendValueDelegate;  5 @property(nomatic, retain) id m_dTransparendValueDelegate;  6 @end
 7 //代理協議的聲明
 8 @protocol TransparendValueDelegat<NSObject>
 9 { 10       -(void)transparendValue:(NSString*)fromValue; 11 
12 } 

40、frame 和 bounds 的區別 ,bound的大小改變frame 改變嗎?

答案:

  frame:該view在父view坐標系統中的位置和大小。(參照點是,父親的坐標系統)

  bounds:該view在本地坐標系統中的位置和大小。(參照點是,本地坐標系統)

41、異步請求最大數目是多大,為什么只能這么多?

答案:

       這個數量是跟cpu有關的,並發性取決於cpu核數,每個核只能 同時處理一個任務.4核cpu理論上可以並發處理4個任務,

  如果按http來算就是4個請求,但是cpu是搶占式資源,所以一般來說並發量是要根據任務的 耗時和cpu的繁忙度來計算4個左右

  只是個經驗值你開10個短耗時的任務和幾個長耗時任務的效率是不同的- -..一般來說估算這個量的最大效率估算公示是cpu

  核數*2-1,這個公式是當時對集群進行壓測得到的結論.cpu搶占時間跟任務時長…開啟這個數量的 線程可以最大化的榨干cpu

  一個道理。cpu不可能都被搶去做connection.iOS是cpu密集型的消耗?。這個大概知道就行了,也不會有人特 別在意吧…

  cpu核數*2-1那個是做淘寶的java團隊壓測得到的線程最優數?,放在iOS上也多少適用…一般來說不超過這個量就好,

  線程不是起的越多越好,線程數就是…cpu來決定的

42、 什么是coredata ?

答案:

  coredata是蘋果提供一套數據保存框架,其基於SQlite

43、 什么是NSManagedObject模型?

答案:

  NSManagedObject是NSObject的子類 ,也是coredata的重要組成部分,它是一個通用的類,實現了

  core data 模型層所需的基本功能,用戶可通過子類化NSManagedObject,建立自己的數據模型。

44、 什么是NSManagedobjectContext ?

答案:

  NSManagedobjectContext對象負責應用和數據庫之間的交互。

45、什么時候使用NSMutableArray,什么時候使用NSArray?

答案:

  當數組在程序運行時,需要不斷變化的,使用NSMutableArray,當數組在初始化后,便不再改變的

       使用NSArray。需要指出的是,使用NSArray只表明的是該數組在運行  時不發生改變,即不能往

      NSAarry的數組里新增和刪除元素,但不表明其數 組內的元素的內容不能發生改變。NSArray是線程安

      全的,NSMutableArray不是線程安全的,多線程使用到NSMutableArray需 要注意。 

46、 @property 后面可以有哪些修飾符?

答案:

讀 、寫性修飾符:readwrite | readonly

setter相關修飾符:assign | retain | copy

原子性修飾符:atomic | nonatomic

getter和setter修飾符

47、怎么用 copy 關鍵字?

答案:

對於字符串和block的屬性一般使用copy  
字符串使用copy是為了外部把字符串內容改了,不影響該屬性

48、 如何重寫帶 copy 關鍵字的 setter?

答案:

以上面的為例 @property (copy) NSstring *str;

-(void)setStr:(nsstring *)str{  _str = [str copy]; }

49、 如何讓自己的類用 copy 修飾符?

答案:

在使用字符串或block的時候用copy修飾,在網上有人覺得有另外一種理解問題的

方式就是理解成如何要自己的類也支持copy功能,這樣的話要答遵從NSCopying協議,然后實現

50、什么情況使用 weak 關鍵字,相比 assign 有什么不同? 

答案
assign 修飾 基本數據類型
weak 修飾 弱指針對象 

51、請簡要說明viewDidLoad和viewDidUnload何時調用 

答案: 

viewDidLoad在view從nib文件初始化時調用,loadView在controller的view為nil時調用。 

此方法在編程實現view時調用,view控制器默認會注冊memory warning notification, 

當view controller的任何view沒有用的時候,viewDidUnload會被調用,在這里實現將retain

的view release,如果是retain的IBOutlet view 屬性則不要在這里release,IBOutlet會負責release 。 

52、在一個對象的方法里面:self.name= “object”;和 name =”object” 有什么不同?

答案:

self.name =”object”:會調用對象的setName()方法;

name = “object”:會直接把object賦值給當前對象的name屬性。

53、請簡述self.name= nil的機制,以及與[name release]的區別?

答案:

self.name =nil;   //使用nil參數調用setName:方法

[name release] 生成的訪問器將自動釋放以前的name對象 

54、#import和#include的區別 @class?

答案:

@class一般用於頭文件中需要聲明該類的某個實例變量的時候用到,在m文 件中還是需要使用#import

而#import比起#include的好處就是不會引起交叉編譯

55、單件實例是什么?

答案:

Foundation 和 Application Kit 框架中的一些 類 只允 許創 建 單 件 對 象,即 這 些 類 在當前 進 程中的唯一 實 例。 

舉 例來 說 ,NSFileManager 和NSWorkspace 類 在使用時 都是基於 進 程 進 行 單 件 對 象的 實 例化。當向 這 些 

類請 求 實 例的 時 候,它 們會向您 傳遞單 一 實 例的一個引用,如果 該實 例 還 不存在, 則 首先 進 行 實 例的分配

和初始化。 單 件 對 象充當控制中心的角色, 負責 指引或 協調類 的各種服 務 。如果 類 在概念上只有一個 實 例(比如
NSWorkspace ),就 應該產 生 一個 單 件 實 例,而不是多個 實 例;如果將來某一天可能有多個 實 例,您可以使用 單 

件 實 例機制,而不是工廠方法或函數。

 56、簡單描述下 SDWebImage的原理,實現機制。

答案: 

  1. 入口 setImageWithURL:placeholderImage:options: 會先把 placeholderImage 顯示,然后 SDWebImageManager 根據 URL 開始處理圖片。

  2. 進入 SDWebImageManager-downloadWithURL:delegate:options:userInfo:,交給 SDImageCache 從緩存查找圖片是否已經下載 queryDiskCacheForKey:delegate:userInfo:.

  3. 先從內存圖片緩存查找是否有圖片,如果內存中已經有圖片緩存,SDImageCacheDelegate 回調 imageCache:didFindImage:forKey:userInfo: 到 SDWebImageManager。

  4. SDWebImageManagerDelegate 回調 webImageManager:didFinishWithImage: 到 UIImageView+WebCache 等前端展示圖片。

  5. 如果內存緩存中沒有,生成 NSInvocationOperation 添加到隊列開始從硬盤查找圖片是否已經緩存。

  6. 根據 URLKey 在硬盤緩存目錄下嘗試讀取圖片文件。這一步是在 NSOperation 進行的操作,所以回主線程進行結果回調 notifyDelegate:。

  7. 如果上一操作從硬盤讀取到了圖片,將圖片添加到內存緩存中(如果空閑內存過小,會先清空內存緩存)。SDImageCacheDelegate 回調 imageCache:didFindImage:forKey:userInfo:。進而回調展示圖片。

  8. 如果從硬盤緩存目錄讀取不到圖片,說明所有緩存都不存在該圖片,需要下載圖片,回調 imageCache:didNotFindImageForKey:userInfo:。

  9. 共享或重新生成一個下載器 SDWebImageDownloader 開始下載圖片。

  10. 圖片下載由 NSURLConnection 來做,實現相關 delegate 來判斷圖片下載中、下載完成和下載失敗。

  11. connection:didReceiveData: 中利用 ImageIO 做了按圖片下載進度加載效果。

  12. connectionDidFinishLoading: 數據下載完成后交給 SDWebImageDecoder 做圖片解碼處理。

  13. 圖片解碼處理在一個 NSOperationQueue 完成,不會拖慢主線程 UI。如果有需要對下載的圖片進行二次處理,最好也在這里完成,效率會好很多。

  14. 在主線程 notifyDelegateOnMainThreadWithInfo: 宣告解碼完成,imageDecoder:didFinishDecodingImage:userInfo: 回調給 SDWebImageDownloader。

  15. imageDownloader:didFinishWithImage: 回調給 SDWebImageManager 告知圖片下載完成。

  16. 通知所有的 downloadDelegates 下載完成,回調給需要的地方展示圖片。

  17. 將圖片保存到 SDImageCache 中,內存緩存和硬盤緩存同時保存。寫文件到硬盤也在以單獨 NSInvocationOperation 完成,避免拖慢主線程。

  18. SDImageCache 在初始化的時候會注冊一些消息通知,在內存警告或退到后台的時候清理內存圖片緩存,應用結束的時候清理過期圖片。

  19. SDWI 也提供了 UIButton+WebCache 和 MKAnnotationView+WebCache,方便使用。

  20. SDWebImagePrefetcher 可以預先下載圖片,方便后續使用。 

    從上面流程可以看出,當你調用setImageWithURL:方法的時候,他會自動去給你干這么多事,當你需要在某一具體時刻做事情的時候,

    你可以覆蓋這些方法。比如在下載某個圖片的過程中要響應一個事件,就覆蓋這個方法(對於初級來說,用sd_setImageWithURL:的若干個方法就可以實現很好的圖片緩存):

1 SDWebImageManager *manager = [SDWebImageManager sharedManager]; 2 [manager downloadImageWithURL:imagePath2 options:SDWebImageRetryFailed progress:^(NSInteger receivedSize, NSInteger expectedSize) { 3         NSLog(@"顯示當前進度"); 4  } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { 5         NSLog(@"下載完成"); 6 
7 }];
View Code

57、層和UIView的區別是什么?

答案:

兩者最大的區別是,圖層不會直接渲染到屏幕上,UIView是iOS系統中界面元素的基礎,所有的界面元素都是繼承自它。

它本身完全是由CoreAnimation來實現的。它真正的繪圖部分,是由一個CALayer類來管理。UIView本身更像是一個CALayer的管理器。

一個UIView上可以有n個CALayer,每個layer顯示一種東西,增強UIView的展現能力。

58、What is lazy loading? 

答案:懶加載模式,只在用到的時候才去初始化,也可以理解成延時加載。我覺得最好也最簡單的一個列子就是tableView中圖片的加載顯示了。

一個延時載,避免內存過高,一個異步加載,避免線程堵塞。

59、簡敘TCP/UDP區別與聯系

TCP---傳輸控制協議,提供的是面向連接、可靠的字節流服務。當客戶和服務器彼此交換數據前,必須先在雙方之間建立一個TCP連接,

之后才能傳輸數據。TCP提供超時重發,丟棄重復數據,檢驗數據,流量控制等功能,保證數據能從一端傳到另一端。 

UDP---用戶數據報協議,是一個簡單的面向數據報的運輸層協議。UDP不提供可靠性,它只是把應用程序傳給IP層的數據報發送出去,

但是並不能保證它們能到達目的地。由於UDP在傳輸數據報前不用在客戶和服務器之間建立一個連接,且沒有超時重發等機制,

故而傳輸速度很快 TCP(Transmission Control Protocol,傳輸控制協議)是基於連接的協議,也就是說,在正式收發數據前,

必須和對方建立可靠的連接。一個TCP連接必須要經過三次“對話”才能建立起來,我們來看看這三次對話的簡單過程:

1.主機A向主機B發出連接請求數據包;

2.主機B向主機A發送同意連接和要求同步(同步就是兩台主機一個在發送,一個在接收,協調工作)的數據包;

3.主機A再發出一個數據包確認主機B的要求同步:“我現在就發,你接着吧!”,這是第三次對話。三次“對話”的目的是使數據包的發送和接收同步,

經過三次“對話”之后,主機A才向主機B正式發送數據。 

UDP(User Data Protocol,用戶數據報協議)是與TCP相對應的協議。它是面向非連接的協議,它不與對方建立連接,而是直接就把數據包發送過去! 

UDP適用於一次只傳送少量數據、對可靠性要求不高的應用環境, tcp協議和udp協議的差別 是否連接面向連接面向非連接 傳輸可靠性可靠不可靠 

應用場合傳輸大量數據少量數據速度慢快.

60、socket連接和http連接的區別

答案:

簡單說,你瀏覽的網頁(網址以http://開頭)都是http協議傳輸到你的瀏覽器的, 而http是基於socket之上的。

socket是一套完成tcp,udp協議的接口。

HTTP協議:簡單對象訪問協議,對應於應用層  ,HTTP協議是基於TCP連接的

tcp協議:    對應於傳輸層

ip協議:     對應於網絡層 
TCP/IP是傳輸層協議,主要解決數據如何在網絡中傳輸;而HTTP是應用層協議,主要解決如何包裝數據。

Socket是對TCP/IP協議的封裝,Socket本身並不是協議,而是一個調用接口(API),通過Socket,我們才能使用TCP/IP協議。

http連接:http連接就是所謂的短連接,即客戶端向服務器端發送一次請求,服務器端響應后連接即會斷掉;

socket連接:socket連接就是所謂的長連接,理論上客戶端和服務器端一旦建立起連接將不會主動斷掉;但是由於各種環境因素可能會是連接斷開,

比如說:服務器端或客戶端主機down了,網絡故障,或者兩者之間長時間沒有數據傳輸,網絡防火牆可能會斷開該連接以釋放網絡資源。

所以當一個socket連接中沒有數據的傳輸,那么為了維持連接需要發送心跳消息~~具體心跳消息格式是開發者自己定義的。

61、請描述URL

答案:

HTTP URL (URL是一種特殊類型的URI是他的子類,包含了用於查找某個資源的足夠的信息)的格式如下:
http://host[":"port][abs_path]
http表示要通過HTTP協議來定位網絡資源;host表示合法的Internet主機域名或者IP地址;port指定一個端口號,

為空則使用缺省端口80;abs_path指定請求資源的URI;如果URL中沒有給出abs_path,那么當它作為請求URI時,

必須以“/”的形式給出,通常這個工作瀏覽器自動幫我們完成。

62、什么是TCP連接的三次握手?

答案:

第一次握手:客戶端發送syn包(syn=j)到服務器,並進入SYN_SEND狀態,等待服務器確認;

第二次握手:服務器收到syn包,必須確認客戶的SYN(ack=j+1),同時自己也發送一個SYN包(syn=k),即SYN+ACK包,

此時服務器進入SYN_RECV狀態;
第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=k+1),此包發送完畢,客戶端和服務器進入

ESTABLISHED狀態,完成三次握手。握手過程中傳送的包里不包含數據,三次握手完畢后,客戶端與服務器才正式開始傳送數據。

理想狀態下,TCP連接一旦建立,在通信雙方中的任何一方主動關閉連接之前,TCP 連接都將被一直保持下去。斷開連接時服務器

和客戶端均可以主動發起斷開TCP連接的請求,斷開過程需要經過“四次握手”(過程就不細寫了,就是服務器和客戶端交互,最終確定斷開) 

63、簡述 NULL、nil、Nil、NSNull 的區別? 

答案:

1、NULL是C語言中的空指針。

2、nil是OC中指向空對象的指針。

3、Nil是OC指向類的空指針。

4、NSNull是在數組或字典集合對象中表示空值對象。  

64、什么是指針的釋放? 

答案:

1 釋放該指針指向的內存,只有堆上的內存才需要我們手工釋放,棧上不需要. 

2 將該指針重定向為NULL. 

65、HTTP協議詳解

答案:

HTTP是一個屬於應用層的面向對象的協議,由於其簡捷、快速的方式,適用於分布式超媒體信息系統。目前在WWW中使用的是HTTP/1.0的第六版,

HTTP/1.1的規范化工作正在進行之中,http(超文本傳輸協議)是一個基於請求與響應模式的、無狀態的、應用層的協議,常基於TCP的連接方式,

HTTP1.1版本中給出一種持續連接的機制,絕大多數的Web開發,都是構建在HTTP協議之上的Web應用。

HTTP協議的主要特點可概括如下:
1.支持客戶/服務器模式。
2.簡單快速:客戶向服務器請求服務時,只需傳送請求方法和路徑。請求方法常用的有GET、HEAD、POST。每種方法規定了客戶與服務器聯系的類型不同。

由於HTTP協議簡單,使得HTTP服務器的程序規模小,因而通信速度很快。
3.靈活:HTTP允許傳輸任意類型的數據對象。正在傳輸的類型由Content-Type加以標記。
4.無連接:無連接的含義是限制每次連接只處理一個請求。服務器處理完客戶的請求,並收到客戶的應答后,即斷開連接。采用這種方式可以節省傳輸時間。
5.無狀態:HTTP協議是無狀態協議。無狀態是指協議對於事務處理沒有記憶能力。缺少狀態意味着如果后續處理需要前面的信息,則它必須重傳,

這樣可能導致每次連接傳送的數據量增大。另一方面,在服務器不需要先前信息時它的應答就較快。 

66、簡敘RunLoop 與RunTime的區別

答案: 

一.RunLoop:  

       Runloop是事件接收和分發機制的一個實現。  

       Runloop提供了一種異步執行代碼的機制,不能並行執行任務。 

       在主隊列中,Main RunLoop直接配合任務的執行,負責處理UI事件、定時器以及其他內核相關事件。 

1).RunLoop的主要目的:  

       保證程序執行的線程不會被系統終止。   

2).什么時候使用Runloop ?  

     當需要和該線程進行交互的時候才會使用Runloop.  

     每一個線程都有其對應的RunLoop,但是默認非主線程的RunLoop是沒有運行的,需要為RunLoop

     添加至少一個事件源,然后去run它。 一般情況下我們是沒有必要去啟用線程的RunLoop的,除非你在

     一個單獨的線程中需要長久的檢測某個事件。主線程默認有Runloop。當自己啟動一個線程,如果只是用於

     處理單一的事件,則該線程在執行完之后就退出了。 所以當我們需要讓該線程監聽某項事務時,就得讓線程一

     直不退出,runloop就是這么一個循環,沒有事件的時候,一直卡着,有事件來臨了,執行其對應的函數。

     RunLoop,正如其名所示,是線程進入和被線程用來相應事件以及調用事件處理函數的地方.需要在代碼中使用控制

     語句實現RunLoop的循環,也就是說,需要代碼提供while或者for循環來驅動RunLoop.在這個循環中,使用一個runLoop

     對象[NSRunloop currentRunloop]執行接收消息,調用對應的處理函數.  Runloop接收兩種源事件:input sources和timer sources。

    input sources 傳遞異步事件,通常是來自其他線程和不同的程序中的消息; timer sources(定時器) 傳遞同步事件(重復執行或者在

    特定時間上觸發)。除了處理input sources,Runloop 也會產生一些關於本身行為的notificaiton。注冊成為Runloop的observer,

   可以接收到 這些notification,做一些額外的處理。(使用CoreFoundation來成為runloop的observer)。 

Runloop工作的特點:  

       1>當有時間發生時,Runloop會根據具體的事件類型通知應用程序作出相應的反應;  

       2>當沒有事件發生時,Runloop會進入休眠狀態,從而達到省電的目的;  

       3>當事件再次發生時,Runloop會被重新喚醒,處理事件.  

提示:一般在開發中很少會主動創建Runloop,而通常會把事件添加到Runloop中. 

二.Runtime:  

RunTime簡稱運行時。就是系統在運行的時候的一些機制,其中最主要的是消息機制。對於C語言,函數的調用在編譯的時候會決

定調用哪個函數(C語言的函數調用請看這里 )。編譯完成之后直接順序執行,無任何二義性。OC的函數調用成為消息發送。

屬於動態調用過程。在編譯的時候並不能決定真正調用哪個函數(事實證明,在編譯階段,OC可以調用任何函數,即使這個函

數並未實現,只要申明過就不會報錯。而C語言在編譯階段就會報錯)。只有在真正運行的時候才會根據函數的名稱找到對應的函數來調用。

舉例說明:
比如你[obj makeText];
則運行時就這樣的:首先,編譯器將代碼[obj makeText];轉化為objc_msgSend(obj, @selector (makeText));,在objc_msgSend函數

中。首先通過obj的isa指針找到obj對應的class。在Class中先去cache中 通過SEL查找對應函數method(猜測cache中method列表是以

SEL為key通過hash表來存儲的,這樣能提高函數查找速度),若 cache中未找到。再去methodList中查找,若methodlist中未找到,

則取superClass中查找。若能找到,則將method加 入到cache中,以方便下次查找,並通過method中的函數指針跳轉到對應的函數

中去執行。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM