ios基礎面試題

1。  include與#import的區別、#import與@class的區別

include程序員

include <> :用於對系統文件的引用,編譯器會在系統文件目錄下去查找該文件。web

#include "xx.h":用於對用戶自定義的文件的引用,編譯器首先會去用戶目錄下查找,而後去安裝目錄,最後去系統目錄查找。

注:使用include要注意重複引用的問題:服務器

class A,class B都引用了class C,class D若引用class A與class B,就會報重複引用的錯誤。網絡

import

功能與include基本相同,不過它避免了重複引用的問題。因此在OC中咱們基本用的都是import。session

@class
@class就是告訴編譯器有這個類存在,可是類是如何實現的不用告訴編譯器.若.m文件用到了這個類,仍是要在.m文件彙總import這個類的。
既然這樣,爲何不直接在頭文件中import呢,舉個例子:
class A引用了class B,class B引用了class C…. , class A,B,C…的頭文件又import了不少文件,那麼 import了A的話,編譯器就須要編譯大量的文件,編譯時間就會增長。
併發

難道頭文件中都是用@class嗎?固然不是,有時也是須要#import的,那麼何時該用什麼呢?
(1)通常若是有繼承關係的用#import,如B是A的子類那麼在B中聲明A時用#import;
異步

(2) 另外就是若是有循環依賴關係,如:A->B,B->A這樣相互依賴時,若是在兩個文件的頭文件中用#import分別聲明對方,那麼就會出現頭文件循環利用的錯誤,這時在頭文件中用@class聲明就不會出錯;async

(3)還有就是自定義代理的時候,若是在頭文件中想聲明代理的話如@interface SecondViewController:UIViewController時應用#import否則的話會出錯誤,注意XXXXDelegate是自定義的。編輯器

區別:模塊化

當咱們在代碼中使用兩次#include的時候會報錯:由於#include至關於拷貝頭文件中的聲明內容,因此會報重複定義的錯誤

可是使用兩次#import的話,不會報錯,因此他能夠解決重複導入的問題,他會作一次判斷,若是已經導入一次就不導入了

2、#import與@class的區別
1.import會包含這個類的全部信息,包括實體變量和方法,而@class只是告訴編譯器,其後面聲明的名稱是類的名稱,至於這些類是如何定義的,暫時不用考慮,後面會再告訴你。

2.在頭文件中, 通常只須要知道被引用的類的名稱就能夠了。 不須要知道其內部的實體變量和方法,因此在頭文件中通常使用@class來聲明這個名稱是類的名稱。 而在實現類裏面,由於會用到這個引用類的內部的實體變量和方法,因此須要使用#import來包含這個被引用類的頭文件。

3.在編譯效率方面考慮,若是你有100個頭文件都#import了同一個頭文件,或者這些文件是依次引用的,如A–>B, B–>C, C–>D這樣的引用關係。當最開始的那個頭文件有變化的話,後面全部引用它的類都須要從新編譯,若是你的類有不少的話,這將耗費大量的時間。而是用@class則不會。

4.若是有循環依賴關係,如:A–>B, B–>A這樣的相互依賴關係,若是使用#import來相互包含,那麼就會出現編譯錯誤,若是使用@class在兩個類的頭文件中相互聲明,則不會有編譯錯誤出現。

因此,通常來講,@class是放在interface中的,只是爲了在interface中引用這個類,把這個類做爲一個類型來用的。 在實現這個接口的實現類中,若是須要引用這個類的實體變量或者方法之類的,仍是須要import在@class中聲明的類進來.

舉個例子說明一下。

在ClassA.h中

import ClassB.h 至關於#include整個.h頭文件。若是有不少.m文件#import ClassA.h,那麼編譯的時候這些文件也會#import ClassB.h增長了不必的#import,浪費編譯時間。在大型軟件中,減小.h文件中的include是很是重要的。

若是
只是 ClassB 那就沒有include ClassB.h。僅須要在須要用到ClassB的.m文件中 #import ClassB.h

那麼何時能夠用呢?
若是ClassA.h中僅須要聲明一個ClassB的指針,那麼就能夠在ClassA.h中聲明
@ClassB

ClassB *pointer;

假設,有兩個類:ClassA和ClassB,兩個之間相互使用到,即構成了circular dependency(循環依賴)。若是在頭文件裏面只用#import把對方的頭文件包含進來(構成circular inclusions,循環包含),則編譯器會報錯:

Expected specifier-qualifier-list before ‘ClassA’

或者

Expected specifier-qualifier-list before ‘ClassB’

爲了不循環包含,在ClassA.h文件裏面用@class classB把classB包含進來,一樣,在ClassB.h文件裏面用@class ClassA把ClassA包含進來。@class指令只是告訴編譯器,這是個類,保留個空間來存放指針就能夠了。

接下來,極可能在ClassA.m和ClassB.m中會有訪問包含進來對象的成員的狀況,這時必須讓編譯器知道更多信息,好比那個類有些什麼方法能夠調用,就必須用#import,再次把用到的類包含進來,告訴編譯器所須要的額外信息。

不然,編譯器會警告:

warning: receiver ‘ClassA’ is a forward class and corresponding @interface may not exist

還有另外一種狀況,使用有Categories的類,要在.h頭文件裏用#import把Categories包含進來。

總之,使用原則是:

頭文件裏面只#import超類 消息文件裏面#import須要發消息過去的類 其餘地方就用@class轉向聲明
 

import會包含這個類的全部信息,包括實體變量和方法(.h文件中),而@class只是告訴編譯器,其後面聲明的名稱是類的名稱,至於這些類是如何定義的,後面會再告訴你。
在頭文件中, 通常只須要知道被引用的類的名稱就能夠了。 不須要知道其內部的實體變量和方法,因此在頭文件中通常使用@class來聲明這個名稱是類的名稱。 而在實現類裏面,由於會用到這個引用類的內部的實體變量和方法,因此須要使用#import來包含這個被引用類的頭文件。

三。深、淺拷貝的基本概念以及他們的區別

一.通俗的說:
copy, mutableCopy
@interface A {
B *b;
}
淺拷貝只是拷貝對象自己,不會對裏面的子對象進一步拷貝
深拷貝會對子對象以及子對象的子對象進一步拷貝
二.深刻理解:
淺拷貝並不複製數據,只複製指向數據的指針,所以是多個指針指向同一份數據。 深拷貝會複製原始數據,每一個指針指向一份獨立的數據。經過下面的代碼, 能夠清楚地看出它們的區別:

struct Test{
char ptr;
};
void shallow_copy(Test &src, Test &dest){
dest.ptr = src.ptr;
}
void deep_copy(Test &src, Test &dest){
dest.ptr = (char)malloc(strlen(src.ptr) + 1);
memcpy(dest.ptr, src.ptr);
}
淺拷貝在構造和刪除對象時容易產生問題,所以使用時要十分當心。如無必要, 儘可能不用淺拷貝。當咱們要傳遞複雜結構的信息,而又不想產生另外一份數據時, 可使用淺拷貝,好比引用傳參。淺拷貝特別須要注意的就是析構時的問題, 當多個指針指向同一分內存時,刪除這些指針將致使屢次釋放同一內存而出錯。

實際狀況下是不多使用淺拷貝的,而智能指針是淺拷貝概念的加強。 好比智能指針能夠維護一個引用計數來代表指向某塊內存的指針數量, 只有當引用計數減至0時,才真正釋放內存。

大部分時候,咱們用的是深拷貝,特別是當拷貝的結構不大的時候。

一.什麼狀況使用 weak 關鍵字?

1)在ARC中,在有可能出現循環引用的時候,每每要經過讓其中一端使用weak來解決,好比:delegate代理屬性

2)自身已經對它進行一次強引用,沒有必要再強引用一次,此時也會使用weak,自定義IBOutlet控件屬性通常也使用weak;固然,也可使用strong。在下文也有論述:《IBOutlet連出來的視圖屬性爲何能夠被設置成weak?》

二.不一樣點:

1)weak 此特質代表該屬性定義了一種「非擁有關係」 (nonowning relationship)。爲這種屬性設置新值時,設置方法既不保留新值,也不釋放舊值。此特質同assign相似, 然而在屬性所指的對象遭到摧毀時,屬性值也會清空(nil out)。 而 assign 的「設置方法」只會執行鍼對「純量類型」 (scalar type,例如 CGFloat 或 NSlnteger 等)的簡單賦值操做。

2)assigin 能夠用非OC對象,而weak必須用於OC對象

@property 的本質是什麼?ivar、getter、setter 是如何生成並添加到這個類中的

@property 的本質是什麼?

@property = ivar + getter + setter;

下面解釋下:

「屬性」 (property)有兩大概念:ivar(實例變量)、存取方法(access method = getter + setter)。

「屬性」 (property)做爲 Objective-C 的一項特性,主要的做用就在於封裝對象中的數據。 Objective-C 對象一般會把其所須要的數據保存爲各類實例變量。實例變量通常經過「存取方法」(access method)來訪問。其中,「獲取方法」 (getter)用於讀取變量值,而「設置方法」 (setter)用於寫入變量值。這個概念已經定型,而且經由「屬性」這一特性而成爲Objective-C 2.0的一部分。 而在正規的 Objective-C 編碼風格中,存取方法有着嚴格的命名規範。 正由於有了這種嚴格的命名規範,因此 Objective-C 這門語言才能根據名稱自動建立出存取方法。其實也能夠把屬性當作一種關鍵字,其表示:

編譯器會自動寫出一套存取方法,用以訪問給定類型中具備給定名稱的變量。 因此你也能夠這麼說:

@property = getter + setter;

例以下面這個類:

@interface Person : NSObject
@property NSString firstName;
@property NSString 
lastName;
@end
上述代碼寫出來的類與下面這種寫法等效:

@interface Person : NSObject

(NSString )firstName;
(void)setFirstName:(NSString 
)firstName;
(NSString )lastName;
(void)setLastName:(NSString 
)lastName; @end ivar、getter、setter 是如何生成並添加到這個類中的?
「自動合成」( autosynthesis)

完成屬性定義後,編譯器會自動編寫訪問這些屬性所需的方法,此過程叫作「自動合成」( autosynthesis)。須要強調的是,這個過程由編譯 器在編譯期執行,因此編輯器裏看不到這些「合成方法」(synthesized method)的源代碼。除了生成方法代碼 getter、setter 以外,編譯器還要自動向類中添加適當類型的實例變量,而且在屬性名前面加下劃線,以此做爲實例變量的名字。在前例中,會生成兩個實例變量,其名稱分別爲 _firstName與_lastName。也能夠在類的實現代碼裏經過 @synthesize語法來指定實例變量的名字.

@implementation Person
@synthesize firstName = _myFirstName;
@synthesize lastName = myLastName;
@end
我爲了搞清屬性是怎麼實現的,曾經反編譯過相關的代碼,大體生成了五個東西:

1)OBJCIVAR$類名$屬性名稱 :該屬性的「偏移量」 (offset),這個偏移量是「硬編碼」 (hardcode),表示該變量距離存放對象的內存區域的起始地址有多遠。

2)setter與getter方法對應的實現函數

3)ivar_list :成員變量列表

4)method_list :方法列表

5)prop_list :屬性列表

也就是說咱們每次在增長一個屬性,系統都會在ivar_list中添加一個成員變量的描述,在method_list中增長setter與getter方法的描述,在屬性列表中增長一個屬性的描述,而後計算該屬性在對象中的偏移量,而後給出setter與getter方法對應的實現,在setter方法中從偏移量的位置開始賦值,在getter方法中從偏移量開始取值,爲了可以讀取正確字節數,系統對象偏移量的指針類型進行了類型強轉.
補充:
Objective-C運行時定義了幾種重要的類型。
Class:定義Objective-C類
Ivar:定義對象的實例變量,包括類型和名字。
Protocol:定義正式協議。
objc_property_t:定義屬性。叫這個名字多是爲了防止和Objective-C 1.0中的用戶類型衝突,那時候尚未屬性。
Method:定義對象方法或類方法。這個類型提供了方法的名字(就是選擇器)、參數數量和類型,以及返回值(這些信息合起來稱爲方法的簽名),還有一個指向代碼的函數指針(也就是方法的實現)。
SEL:定義選擇器。選擇器是方法名的惟一標識符。
IMP:定義方法實現。這只是一個指向某個函數的指針,該函數接受一個對象、一個選擇器和一個可變長參數列表(varargs),返回一個對象

5.GCD底層三種隊列

  • Serial:一個接着一個執行
  • Concurrent:可讓多個任務併發執行(自動開啓多個線程同時執行任務)
  • Main dispatch queue:是系統建立好準們用來存儲在主線程中執行任務的隊列,添加到主隊列中的任務只能在主線程中執行,使用的時候只須要直接去拿就能夠了;主隊列只能夠異步執行,不然會形成死鎖;
  • 三種隊列的使用方法都是:a.定製任務,b.將任務添加到隊列中,GCD會自動將隊列的任務取出,放到對應的線程中執行,任務的執行遵循隊列的FIFO原則;
    dispatch_queue_t queue = dispatch_get_main_queue();
    for (int i =0;i<10;i++){
    dispatch_async(queue,^{
    [self longtimeOperation:i];
    });
    }

    6.CALayer和UIView的關係

    • UIView和UIView簡單點說就是MVC的關係,UIView是CALayer就是M,負責繪圖單元的就是V;由於聽從單一職責原則,CALayer負責存儲數據,UIView就是負責管理CALayer樹的職責就是存儲數據的樹,以供你修改,作動畫和渲染等使用。UIView樹的話,先看UIView繼承了什麼,UIView繼承了UIResponder,UIResponder是負責一些觸摸事件的類,因此UIView樹主要的職責就是作觸摸的傳遞,這個工做能夠分爲2部分,1部分是尋找你點擊到的那個view,另一部分是把你的觸摸方法傳遞下去。在這裏的話UIView樹實際上是充當了責任鏈職責。

      7.@synthesize和@dynamic有什麼區別?

    • @synthesize是告訴編譯器自動生成get和set方法,而@dynamic則是告訴編譯器不須要生成屬性的get和set方法,對應的方法會由咱們程序員手動去寫,避免編譯的時候由於不能找到屬性對應的get和set方法而報錯的狀況。
    • 在Xcode 6.0以後,每次使用@property申明屬性,其實都默認執行了@sysnthesize,若是不須要自動生成get set方法,能夠在屬性對應的.m文件中加上 「@dynamic 屬性名」便可.

      8.請簡單敘述AFNetWorking的實現原理:

    • 核心是NSURLConnection和NSOperation:NSURLConnection是Foundation URL加載系統的基石,一個NSURLConnection異步地加載一個NSURLRequest對象,調用delegate的NSURLResponse/NSHTTPURLResponse方法,請求的數據NSData被髮送到服務器或者從放服務器讀取;delegate還能夠用來處理其餘重定向響應以及存儲在共享的NSURLCache上.
      NSOperation是一個抽象類,AFNetWorking的核心就是將他們結合在一塊兒,AFURLConnectionOperation 做爲 NSOperation 的子類,遵循 NSURLConnectionDelegate 的方法,能夠從頭至尾監視請求的狀態,並儲存請求、響應、響應數據等中間狀態。
    • 以後升級版本AFNetWorking2.0:關鍵在於兼容了NSURLSession使用來替代了NSURLConnection的類,可是NSURLConnection並無被拋棄,
    • 模塊化 - 對於 AFNetworking 的主要批評之一是笨重。雖然它的構架使在類的層面上是模塊化的,但它的包裝並不容許選擇獨立的一些功能。隨着時間的推移,AFHTTPClient尤爲變得不堪重負(其任務包括建立請求、序列化 query string 參數、肯定響應解析行爲、生成和管理 operation、監視網絡可達性)。 在 AFNetworking 2.0 中,你能夠挑選並經過 CocoaPods subspecs 選擇你所須要的組件
    • 介紹一下NSURLConnectionOperation:AFURLConnectionOperation - NSOperation 的子類,負責管理 NSURLConnection 而且實現其 delegate 方法。
      AFHTTPRequestOperation - AFURLConnectionOperation 的子類,用於生成 HTTP 請求,能夠區別可接受的和不可接受的狀態碼及內容類型。2.0 版本中的最大區別是,你能夠直接使用這個類,而不用繼承它,緣由能夠在「序列化」一節中找到 AFHTTPRequestOperationManager - 包裝常見 HTTP web 服務操做的類,經過AFHTTPRequestOperation 由 NSURLConnection 支持。
    • AFURLSessionManager - 建立、管理基於 NSURLSessionConfiguration 對象的NSURLSession 對象的類,也能夠管理 session 的數據、下載/上傳任務,實現 session 和其相關聯的任務的 delegate 方法。由於 NSURLSession API 設計中奇怪的空缺,任何和NSURLSession 相關的代碼均可以用 AFURLSessionManager 改善。 AFHTTPSessionManager - AFURLSessionManager 的子類,包裝常見的 HTTP web 服務操做,經過 AFURLSessionManager 由 NSURLSession 支持。 總的來講:爲了支持新的 NSURLSession API 以及舊的未棄用且還有用的NSURLConnection,AFNetworking 2.0 的核心組件分紅了 request operation 和 session 任務。AFHTTPRequestOperationManager 和 AFHTTPSessionManager 提供相似的功能,在須要的時候(好比在 iOS 6 和 7 之間轉換),它們的接口能夠相對容易的互換。
相關文章
相關標籤/搜索