李洪強經典面試題49-Objective-C

李洪強經典面試題49-Objective-C

面試筆試都是必考語法知識的。請認真複習和深刻研究OC。

Objective-C

方法和選擇器有何不一樣?(Difference between method and selector?)

  • selector是一個方法的名字,method是一個組合體,包含了名字和實現.

Core Foundation的內存管理

  • 凡是帶有Create、Copy、Retain等字眼的函數,建立出來的對象,都須要在最後作一次release
  • 好比CFRunLoopObserverCreate release函數:CFRelease(對象);

malloc和New的區別

  • new 是c++中的操做符,malloc是c 中的一個函數css

  • new 不止是分配內存,並且會調用類的構造函數,同理delete會調用類的析構函數,而malloc則只分配內存,不會進行初始化類成員的工做,一樣free也不會調用析構函數ios

  • 內存泄漏對於malloc或者new均可以檢查出來的,區別在於new能夠指明是那個文件的那一行, 而malloc沒有這些信息。c++

  • new 和 malloc效率比較面試

  • new能夠認爲是malloc加構造函數的執行。objective-c

  • new出來的指針是直接帶類型信息的。編程

你是否接觸過OC中的反射機制?簡單聊一下概念和使用

  • class反射
  • 經過類名的字符串形式實例化對象
    Class class NSClassFromString@(@"student");
    Student *stu = [[class alloc ]init];
  • 將類名變爲字符串
    Class class =[Student class];
    NSString *className = NSStringFromClass(class);
  • SEL的反射
  • 經過方法的字符串形式實例化方法
    SEL selector = NSSelectorFromClass(@"setName");
    [stu performSelector:selector withObject:@"Mike"];
  • 將方法變成字符串
    NSStringFomrSelector(@selector*(setName:))

什麼是SEL?如何聲明一個SEL?經過那些方法可以,調用SEL包裝起來的方法?

  • SEL就是對方法的一種包裝。包裝的SEL類型數據它對應相應的方法地址,找到方法地址就能夠調用方法。在內存中每一個類的方法都存儲在類對象中,每一個方法都有一個與之對應的SEL類型的數據,根據一個SEL數據就能夠找到對應的方法地址,進而調用方法。api

  • SEL s1 = @selector(test1); // 將test1方法包裝成SEL對象 數組

  • SEL s2 = NSSelectorFromString(@"test1"); // 將一個字符串方法轉換成爲SEL對象安全

  • 調用方法有兩種方式:多線程

  • 1.直接經過方法名來調用 [person text]

  • 2.間接的經過SEL數據來調用 SEL aaa=@selector(text); [person performSelector:aaa];

協議中<NSObject>是什麼意思?子類繼承了父類,那麼子類會遵照父類中遵照的協議嗎?協議中可以定義成員變量?如何約束一個對象類型的變量要存儲的地址是遵照一個協議對象?

  • 遵照NSObject協議
  • 能,可是隻在頭文件中聲明,編譯器是不會自動生成實例變量的。須要本身處理getter和setter方法
  • id<xxx>

NS/CF/CG/CA/UI這些前綴分別是什麼含義

  • 函數歸屬於屬於cocoa Fundation框架
  • 函數歸屬於屬於core Fundation框架
  • 函數歸屬於屬於CoreGraphics.frameworks框架
  • 函數歸屬於屬於CoreAnimation.frameworks框架
  • 函數歸屬於屬於UIkit框架

面向對象都有哪些特徵以及你對這些特徵的理解。

  • 繼承:繼承是從已有類獲得繼承信息建立新類的過程。提供繼承信息的類被稱爲父類(超類、基類);獲得繼承信息的類被稱爲子類(派生類)。 繼承讓變化中的軟件系統有了必定的延續性,同時繼承也是封裝程序中可變因素的重要手段。

  • 封裝:封裝是把數據和操做數據的方法綁定起來,對數據的訪問只能經過已定義的接口。咱們在類中編寫的方法就是對實現細節的一種封裝;咱們編寫一個類就是對數據和數據操做的封裝。能夠說,封裝就是隱藏一切可隱藏的東西,只向外界提供最簡單的編程接口。

  • 多態性:多態性是指容許不一樣子類型的對象對同一消息做出不一樣的響應。簡單的說就是用一樣的對象引用調用一樣的方法可是作了不一樣的事情。多態性分爲編譯時的多態性和運行時的多態性。方法重載(overload)實現的是編譯時的多態性(也稱爲前綁定),而方法重寫(override)實現的是運行時的多態性(也稱爲後綁定)。運行時的多態是面向對象最精髓的東西,要實現多態須要作兩件事:1. 方法重寫(子類繼承父類並重寫父類中已有的或抽象的方法);2. 對象造型(用父類型引用引用子類型對象,這樣一樣的引用調用一樣的方法就會根據子類對象的不一樣而表現出不一樣的行爲)。

  • 抽象:抽象是將一類對象的共同特徵總結出來構造類的過程,包括數據抽象和行爲抽象兩方面。抽象只關注對象有哪些屬性和行爲,並不關注這些行爲的細節是什麼。

咱們說的Objective-C是動態運行時語言是什麼意思? (When we call objective c is runtime language what does it mean?)

  • 主要是將數據類型的肯定由編譯時,推遲到了運行時。這個問題其實淺涉及到兩個概念,運行時和多態。

  • 簡單來講, 運行時機制使咱們直到運行時纔去決定一個對象的類別,以及調用該類別對象指定方法。

  • 多態:不一樣對象以本身的方式響應相同的消息的能力叫作多態。

  • 意思就是假設生物類(life)都擁有一個相同的方法-eat;那人類屬於生物,豬也屬於生物,都繼承了life後,實現各自的eat,可是調用是咱們只需調用各自的eat方法。也就是不一樣的對象以本身的方式響應了相同的消 息(響應了eat這個選擇器)。所以也能夠說,運行時機制是多態的基礎.

readwrite, readonly, assign, retain, copy, nonatomic屬性的做用?

  • readwrite 是可讀可寫特性;須要生成getter方法和setter方法;
  • readonly 是隻讀特性 只會生成getter方法 不會生成setter方法 ,不但願屬性在類外改變;
  • assign 是賦值特性,setter方法將傳入參數賦值給實例變量;僅設置變量時; assign用於簡單數據類型,如NSInteger,double,bool;
  • retain 表示持有特性,setter方法將傳入參數先保留,再賦值,傳入參數的引用計數retaincount會+1;
  • copy 表示賦值特性,setter方法將傳入對象複製一份;須要徹底一份新的變量時;
  • nonatomic 非原子操做,決定編譯器生成的setter getter是不是原子操做;
  • atomic表示多線程安全,通常使用 nonatomic。

簡述NotificationCenter、KVC、KVO、Delegate?並說明它們之間的區別?(重點)

  • KVO(Key-Value- Observing):一對多, 觀察者模式,鍵值觀察機制,它提供了觀察某一屬性變化的方法,極大簡化了代碼。
  • KVC(Key-Value-Coding):是鍵值編碼, 一個對象在調用setValue的時候,

    • 檢查是否存在相應key的set方法,存在就調用set方法。

    • set方法不存在,就查找_key的成員變量是否存在,存在就直接賦值。

    • 若是_key沒找到,就查找相同名稱的key,存在就賦值。

    • 若是沒有就調用valueForUndefinedkey和setValue:forUndefinedKey。
  • Delegate: 一般發送者和接收者的關係是直接的一對一的關係。

    • 代理的目的是改變或傳遞控制鏈。容許一個類在某些特定時刻通知到其餘類,而不須要獲取到那些類的指針。

    • 能夠減小框架複雜度。消息的發送者(sender)告知接收者(receiver)某個事件將要發生,delegate贊成然而後發送者響應事件,delegate機制使得接收者能夠改變發送者的行爲。

  • Notification: 觀察者模式, 一般發送者和接收者的關係是間接的多對多關係。 消息的發送者告知接收者事件已經發生或者將要發送,僅此而已,接收者並不能反過來影響發送者的行爲。

  • 區別

    • 效率確定是delegate比NSNotification高。
    • delegate方法比notification更加直接,須要關注返回值,因此delegate方法每每包含should這個很傳神的詞。相反的,notification最大的特點就是不關心結果。因此notification每每用did這個詞彙。
    • 兩個模塊之間聯繫不是很緊密,就用notification傳值,例如多線程之間傳值用notificaiton。
    • delegate只是一種較爲簡單的回調,且主要用在一個模塊中,例如底層功能完成了,須要把一些值傳到上層去,就事先把上層的函數經過delegate傳到底層,而後在底層call這個delegate,它們都在一個模塊中,完成一個功能,例如說 NavgationController 從 B 界面到A 點返回按鈕 (調用popViewController方法) 能夠用delegate比較好。

懶加載(What is lazy loading ?)

  • 就是懶加載,只在用到的時候纔去初始化。也能夠理解成延時加載。我以爲最好也最簡單的一個列子就是tableView中圖片的加載顯示了, 一個延時加載, 避免內存太高,一個異步加載,避免線程堵塞提升用戶體驗

OC有多繼承嗎?沒有的話能夠用什麼方法替代?

  • 多繼承即一個子類能夠有多個父類,它繼承了多個父類的特性。
  • Object-c的類沒有多繼承,只支持單繼承,若是要實現多繼承的話,能夠經過類別和協議的方式來實現。
  • protocol(協議)能夠實現多個接口,經過實現多個接口能夠完成多繼承;
  • Category(類別)通常使用分類,用Category去重寫類的方法,僅對本Category有效,不會影響到其餘類與原有類的關係。

分別描述類別(categories)和延展(extensions)是什麼?以及二者的區別?繼承和類別在實現中有何區別?爲何Category只能爲對象添加方法,卻不能添加成員變量?

  • 類別: 在沒有原類.m文件的基礎上,給該類添加方法;
  • 延展:一種特殊形式的類別,主要在一個類的.m文件裏聲明和實現延展的做用,就是給某類添加私有方法或是私有變量。
  • 兩個的區別:
    • 延展能夠添加屬性而且它添加的方法是必需要實現的。延展能夠認爲是一個私有的類目。
    • 類別能夠在不知道,不改變原來代碼的狀況下往裏面添加新的方法,只能添加,不能刪除修改。
    • 而且若是類別和原來類中的方法產生名稱衝突,則類別將覆蓋原來的方法,由於類別具備更高的優先級。
    • 繼承能夠增長,修改刪除方法,添加屬性。
  • Category只能爲對象添加方法,卻不能添加成員變量的緣由:若是能夠添加成員變量,添加的成員變量沒有辦法初始化

Objective-C有私有方法麼?私有變量呢?如多沒有的話,有沒有什麼代替的方法?

  • objective-c類裏面的方法只有兩種,靜態方法和實例方法.可是能夠經過把方法的聲明和定義都放在.m文件中來實現一個表面上的私有方法。有私有變量,能夠經過@private來修飾,或者把聲明放到.m文件中。在Objective‐C中,全部實例變量默認都是私有的, 全部實例方法默認都是公有的

include與#import的區別? #import與@class的區別?

  • import指令是Object-C針對#include的改進版本,#import確保引用的文件只會被引用一次,這樣你就不會陷入遞歸包含的問題中。

  • import與@class兩者的區別在於:

    • import會鏈入該頭文件的所有信息,包括實例變量和方法等;而@class只是告訴編譯器,其後面聲明的名稱是類的名稱,至於這些類是如何定義的,暫時不用考慮。

    • 在頭文件中通常使用@class來聲明這個名稱是類的名稱,不須要知道其內部的實體變量和方法.
    • 而在實現類裏面,由於會用到這個引用類的內部的實體變量和方法,因此須要使用#import來包含這個被引用類的頭文件。
    • 在編譯效率方面,若是你有100個頭文件都#import了同一個頭文件,或者這些文件是依次引用的,如A–>B, B–>C, C–>D這樣的引用關係。當最開始的那個頭文件有變化的話,後面全部引用它的類都須要從新編譯,若是你的類有不少的話,這將耗費大量的時間。而是用@class則不會。
    • 若是有循環依賴關係,如:A–>B, B–>A這樣的相互依賴關係,若是使用#import來相互包含,那麼就會出現編譯錯誤,若是使用@class在兩個類的頭文件中相互聲明,則不會有編譯錯誤出現。

淺複製(拷貝)和深複製的區別? (Difference between shallow copy and deep copy?)

  • 淺複製(copy):只複製指向對象的指針,而不復制引用對象自己。

  • 深複製(mutableCopy):複製引用對象自己。深複製就好理解了,內存中存在了兩份獨立對象自己, 當修改A時,A_copy不變。

類變量的@protected,@private,@public,@package聲明各有什麼含義?

變量的做用域不一樣。

  • @protected 該類和子類中訪問,是默認的;
  • @private 只能在本類中訪問;
  • @public 任何地方都能訪問;
  • @package 本包內使用,跨包不能夠

Objective-C與C、C+++之間的聯繫和區別?

  • Objective-C和C++都是C的面向對象的超集。
  • Object與C++的區別主要點:Objective-C是徹底動態的,支持在運行時動態類型決議(dynamic typing),動態綁定(dynamic binding)以及動態裝載(dynamic loading);而C++是部分動態的,編譯時靜態綁定,經過嵌入類(多重繼承)和虛函數(虛表)來模擬實現。
  • Objective-C 在語言層次上支持動態消息轉發,其消息發送語法爲 [object function]; 並且C++ 爲 object->function()。 二者的語義也不一樣,在 Objective-C 裏是說發送消息到一個對象上,至於這個對象能不能響應消息以及是響應仍是轉發消息都不會 crash; 而在 C++ 裏是說對象進行了某個操做,若是對象沒有這個操做的話,要麼編譯會報錯(靜態綁定),要麼程序會 crash 掉的(動態綁定)。

目標-動做機制

  • 目標是動做消息的接收者。一個控件,或者更爲常見的是它的單元,以插座變量的形式保有其動做消息的目標。
  • 動做是控件發送給目標的消息,或者從目標的角度看,它是目標爲了響應動做而實現的方法. 程序須要某些機制來進行事件和指令的翻譯。這個機制就是目標-動做機制。

Objective-C優勢和缺點

  • 優勢:1.Cateogies 2.Posing 3.動態識別 4.指標計算 5.彈性訊息傳遞 6.不是一個過分複雜的C衍生語言 7.Objective-C與C++可混合編程

  • 缺點:1.不支持命名空間 2.不支持運算符重載 3.不支持多重繼承 4.使用動態運行時類型,全部的方法都是函數調用,因此不少編譯時優化方法都用不到。(如內聯函數等),性能低劣。

C語言的函數調用和oc的消息機制有什麼區別?

  • 對於C語言,函數的調用在編譯的時候會決定調用哪一個函數。編譯完成以後直接順序執行。
  • OC的函數調用成爲消息發送。屬於動態調用過程。在編譯的時候並不能決定真正調用哪一個函數(事實證實,在編譯階段,OC能夠調用任何函數,即便這個函數並未實現,只要申明過就不會報錯。而C語言在編譯階段就會報錯)。只有在真正運行的時候纔會根據函數的名稱找到對應的函數來調用。

什麼是謂詞

謂詞就是經過NSPredicate給定的邏輯條件做爲約束條件,完成對數據的篩選。

//定義謂詞對象,謂詞對象中包含了過濾條件

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"age<%d",30];

//使用謂詞條件過濾數組中的元素,過濾以後返回查詢的結果

NSArray *array = [persons filteredArrayUsingPredicate:predicate];

//可使用&&進行多條件過濾

predicate = [NSPredicate predicateWithFormat:@"name='1' && age>40"];

array = [persons filteredArrayUsingPredicate:predicate];

//包含語句的使用

predicate = [NSPredicate predicateWithFormat:@"self.name IN {'1','2','4'} || self.age IN{30,40}"];

//指定字符開頭和指定字符結尾,是否包含指定字符

//name以a開頭的

predicate = [NSPredicate predicateWithFormat:@"name BEGINSWITH 'a'"];

//name以ba結尾的

predicate = [NSPredicate predicateWithFormat:@"name ENDSWITH 'ba'"];

//name中包含字符a的

predicate = [NSPredicate predicateWithFormat:@"name CONTAINS 'a'"];

//like進行匹配多個字符

//name中只要有s字符就知足條件

predicate = [NSPredicate predicateWithFormat:@"name like 's'"];

//?表明一個字符,下面的查詢條件是:name中第二個字符是s的

predicate = [NSPredicate predicateWithFormat:@"name like '?s'"];

C與OC混用

處理.m能夠識別c和oc,.mm能夠識別c c++ oc 可是cpp只能用c/c++

atomic和nonatomic的區別

  • atomic提供多線程安全,防止讀寫未完成的時候被另一個線程讀寫,形成數據錯誤。
  • nonatomic在本身管理內存的環境中,解析的訪問器保留並自動釋放返回值,若指定了nonatomic,那麼訪問器只是簡單的返回這個值。

常見的oc數據類型哪些,和c的基本類型有啥區別

  • 常見的:NSInteger CGFloat NSString NSNumber NSArray NSDate
  • NSInteger根據32或者64位系統決定自己是int仍是long
  • CGFloat根據32或者64位系統決定自己是float仍是double
  • NSString NSNumber NSArray NSDate都是指針類型的對象,在堆中分配內存,c語言中的char int 等都是在棧中分配空間

id和nil表明什麼

  • id類型的指針能夠指向任何OC對象
  • nil表明空值(空指針的值,0)

nil和NULL的區別?

  • 從oc的官方語法上看,nil表示對象的指針 即對象的引用爲空
  • null表示指向基礎數據類型變量 即c語言變量的指針爲空
  • 在非arc中 兩個空能夠互換,可是在arc中 普通指針和對象引用被嚴格限制,不能互換

nil、Nil、NULL和NSNull區別

  • nil和C語言的NULL相同,在objc/objc.h中定義。nil表示Objective-C對象的值爲空。在C語言中,指針的空值用NULL表示。在Objective-C中,nil對象調用任何方法表示什麼也不執行,也不會崩潰。
  • Nil:那麼對於咱們Objective-C開發來講,Nil也就表明((void *)0)。可是它是用於表明空類的. 好比:Class myClass = Nil;
  • NULL: 在C語言中,NULL是無類型的,只是一個宏,它表明空. 這就是在C/C++中的空指針。對於咱們Objective-C開發來講,NULL就表示((void*)0).
  • NSNull:NSNull是繼承於NSObject的類型。它是很特殊的類,它表示是空,什麼也不存儲,可是它倒是對象,只是一個佔位對象。使用場景就不同了,好比說服務端接口中讓咱們在值爲空時,傳空。NSDictionry *parameters = @{@"arg1" : @"value1",@"arg2" : arg2.isEmpty ? [NSNull null] : arg2};

  • NULL、nil、Nil這三者對於Objective-C中值是同樣的,都是(void *)0,那麼爲何要區分呢?又與NSNull之間有什麼區別:

  • NULL是宏,是對於C語言指針而使用的,表示空指針
  • nil是宏,是對於Objective-C中的對象而使用的,表示對象爲空
  • Nil是宏,是對於Objective-C中的類而使用的,表示類指向空
  • NSNull是類類型,是用於表示空的佔位對象,與JS或者服務端的null相似的含意

向一個nil對象發送消息會發生什麼?

  • 向nil發送消息是徹底有效的——只是在運行時不會有任何做用。

  • 若是一個方法返回值是一個對象,那麼發送給nil的消息將返回0(nil)

  • 若是方法返回值爲指針類型,其指針大小爲小於或者等於sizeof(void*),float,double,long double 或者long long的整型標量,發送給nil的消息將返回0。

-若是方法返回值爲結構體,正如在《Mac OS X ABI 函數調用指南》,發送給nil的消息將返回0。結構體中各個字段的值將都是0。其餘的結構體數據類型將不是用0填充的。

  • 若是方法的返回值不是上述提到的幾種狀況,那麼發送給nil的消息的返回值將是未定義的。

    self.和self->的區別

  • self.是調用get或者set方法
  • self是當前自己,是一個指向當前對象的指針
  • self->是直接訪問成員變量

類方法和實例方法的本質區別和聯繫

類方法 實例方法
屬於類對象 屬於實例對象  
只能類對象調用 實例對象調用  
self是類對象 self是實例對象  
類方法能夠調用其餘類方法 實例方法能夠調用實例方法  
類方法不能訪問成員變量 實例方法能夠訪問成員變量  
類方法不能直接調用對象方法 實例方法能夠調用類方法  

_block/weak修飾符區別

  • _block在arc和mrc環境下都能用,能夠修飾對象,也能修飾基本數據類型
  • _weak只能在arc環境下使用,只能修飾對象(NSString),不能修飾基本數據類型(int)
  • _block對象能夠在block中從新賦值,_weak不行。

寫一個NSString類的實現

NSString *str = [[NSString alloc]initWithCString:nullTerminatedCString encoding:encoding];

爲何標準頭文件都有相似如下的結構?

ifndef __INCvxWorksh

define __INCvxWorksh

ifdef __cplusplus

extern "C" {

endif

ifdef __cplusplus

}

endif

endif

顯然,頭文件中的編譯宏「#ifndef INCvxWorksh、#define INCvxWorksh、#endif」 的做用是防止該頭文件被重複引用

init和initwithobject區別(語法)?
  • 後者給屬性賦值

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

@property的本質: @property = ivar(實例變量) + getter(取方法) + setter(存方法) 「屬性」 (property)有兩大概念:ivar(實例變量)、存取方法(access method = getter + setter) ivar、getter、setter如何生成並添加到類中: 這是編譯器自動合成的,經過@synthesize關鍵字指定,若不指定,默認爲@synthesize propertyName = _propertyName;若手動實現了getter/setter方法,則不會自動合成。 如今編譯器已經默認爲咱們添加@synthesize propertyName = _propertyName;所以再也不須要手動添加了,除非你真的要改爲員變量名。 生成getter方法時,會判斷當前屬性名是否有_,好比聲明屬性爲@property (nonatomic, copy) NSString *_name;那麼所生成的成員變量名就會變成__name,若是咱們要手動生成getter方法,就要判斷是否以_開頭了。 不過,命名都要有規範,是不容許聲明屬性是使用_開頭的,不規範的命名,在使用runtime時,會帶來不少的不方便的。

這個寫法會出什麼問題:@property (copy) NSMutableArray *array;

  • 沒有指明爲nonatomic,所以就是atomic原子操做,會影響性能。該屬性使用了同步鎖,會在建立時生成一些額外的代碼用於幫助編寫多線程程序,這會帶來性能問題,經過聲明nonatomic能夠節省這些雖然很小可是沒必要要額外開銷。在咱們的應用程序中,幾乎都是使用nonatomic來聲明的,由於使用atomic並不能保證絕對的線程安全,對於要絕對保證線程安全的操做,還須要使用更高級的方式來處理,好比NSSpinLock、@syncronized等
  • 由於使用的是copy,所獲得的實際是NSArray類型,它是不可變的,若在使用中使用了增、刪、改操做,則會crash

@protocol和category中如何使用 @property

•    在protocol中使用@property只會生成setter和getter方法聲明,咱們使用屬性的目的是但願遵照我協議的對象能實現該屬性 • category使用@property也是隻會生成setter和getter方法的聲明,若是咱們真的須要給category增長屬性的實現,須要藉助於運行時的兩個函數: • objc_setAssociatedObject • objc_getAssociatedObject

@property中有哪些屬性關鍵字?

  1. 原子性 (atomic,nonatomic)

  2. 讀寫(readwrite, readonly)

  3. 內存管理(assign, strong, weak, unsafe_unretained,copy)

  4. getter、setter

isa指針問題

  • isa:是一個Class 類型的指針. 每一個實例對象有個isa的指針,他指向對象的類,而Class裏也有個isa的指針, 指向meteClass(元類)。元類保存了類方法的列表。當類方法被調用時,先會從自己查找類方法的實現,若是沒有,元類會向他父類查找該方法。同時注意的是:元類(meteClass)也是類,它也是對象。元類也有isa指針,它的isa指針最終指向的是一個根元類(root meteClass).根元類的isa指針指向自己,這樣造成了一個封閉的內循環。

如何訪問並修改一個類的私有屬性?

  • 一種是經過KVC獲取
  • 經過runtime訪問並修改私有屬性

如何爲 Class 定義一個對外只讀對內可讀寫的屬性?

在頭文件中將屬性定義爲readonly,在.m文件中將屬性從新定義爲readwrite

Objective-C 中,meta-class 指的是什麼?

meta-class 是 Class 對象的類,爲這個Class類存儲類方法,當一個類發送消息時,就去這個類對應的meta-class中查找那個消息,每一個Class都有不一樣的meta-class,全部的meta-class都使用基類的meta-class(假如類繼承NSObject,那麼他所對應的meta-class也是NSObject)做爲他們的類

Objective-C 的class是如何實現的?Selector是如何被轉化爲 C 語言的函數調用的?

  • 當一個類被正確的編譯事後,在這個編譯成功的類裏面,存在一個變量用於保存這個類的信息。咱們能夠經過[NSClassFromString]或[obj class]。這樣的機制容許咱們在程序執行的過程中,能夠Class來獲得對象的類,也能夠在程序執行的階段動態的生成一個在編譯階段沒法肯定的一個對象。 (isa指針)
  • @selector()基本能夠等同C語言的中函數指針,只不過C語言中,能夠把函數名直接賦給一個函數指針,而Object-C的類不能直接應用函數指針,這樣只能作一個@selector語法來取.

    @interface foo -(int)add:int val; @end SEL class_func ; //定義一個類方法指針 class_func = @selector(add:int);
  • @selector是查找當前類的方法,而[object @selector(方法名:方法參數..) ] ;是取object對應類的相應方法.

  • 查找類方法時,除了方法名,方法參數也查詢條件之一.
  • 能夠用字符串來找方法 SEL 變量名 = NSSelectorFromString(方法名字的字符串);
  • 能夠運行中用SEL變量反向查出方法名字字符串。NSString *變量名 = NSStringFromSelector(SEL參數);

  • 取到selector的值之後,執行seletor。 SEL變量的執行.用performSelecor方法來執行.
    [對象 performSelector:SEL變量 withObject:參數1 withObject:參數2];

對於語句NSString *obj = [[NSData alloc] init]; ,編譯時和運行時obj分別是什麼類型?

  • 編譯時是NSString類型 ,運行時是NSData類型.

@synthesize和@dynamic分別有什麼做用?

- @property有兩個對應的詞,一個是 @synthesize,一個是 @dynamic。若是 @synthesize和 @dynamic都沒寫,那麼默認的就是@syntheszie var = _var; - @synthesize 的語義是若是你沒有手動實現 setter 方法和 getter 方法,那麼編譯器會自動爲你加上這兩個方法。 - @dynamic 告訴編譯器:屬性的 setter 與 getter 方法由用戶本身實現,不自動生成。(固然對於 readonly 的屬性只需提供 getter 便可)。假如一個屬性被聲明爲 @dynamic var,而後你沒有提供 @setter方法和 @getter 方法,編譯的時候沒問題,可是當程序運行到 instance.var = someVar,因爲缺 setter 方法會致使程序崩潰;或者當運行到 someVar = var 時,因爲缺 getter 方法一樣會致使崩潰。編譯時沒問題,運行時才執行相應的方法,這就是所謂的動態綁定。

NSString 的時候用copy和strong的區別?

OC中NSString爲不可變字符串的時候,用copy和strong都是隻分配一次內存,可是若是用copy的時候,須要先判斷字符串是不是不可變字符串,若是是不可變字符串,就再也不分配空間,若是是可變字符串才分配空間。若是程序中用到NSString的地方特別多,每一次都要先進行判斷就會耗費性能,影響用戶體驗,用strong就不會再進行判斷,因此,不可變字符串能夠直接用strong。

NSArray、NSSet、NSDictionary與NSMutableArray、NSMutableSet、NSMutableDictionary的特性和做用(遇到copy修飾產生的變化)

  • 特性:
  • NSArray表示不可變數組,是有序元素集,只能存儲對象類型,可經過索引直接訪問元素,並且元素類型能夠不同,可是不能進行增、刪、改操做;NSMutableArray是可變數組,能進行增、刪、改操做。經過索引查詢值很快,可是插入、刪除等效率很低。
  • NSSet表示不可變集合,具備肯定性、互異性、無序性的特色,只能訪問而不能修改集合;NSMutableSet表示可變集合,能夠對集合進行增、刪、改操做。集合經過值查詢很快,插入、刪除操做極快。
  • NSDictionary表示不可變字典,具備無序性的特色,每一個key對應的值是惟一的,可經過key直接獲取值;NSMutableDictionary表示可變字典,能對字典進行增、刪、改操做。經過key查詢值、插入、刪除值都很快。
  • 做用:
  • 數組用於處理一組有序的數據集,好比經常使用的列表的dataSource要求有序,可經過索引直接訪問,效率高。
  • 集合要求具備肯定性、互異性、無序性,在iOS開發中是比較少使用到的,筆者也不清楚如何說明其做用
  • 字典是鍵值對數據集,操做字典效率極高,時間複雜度爲常量,可是值是無序的。在ios中,常見的JSON轉字典,字典轉模型就是其中一種應用。

請把字符串2015-04-10格式化日期轉爲NSDate類型

NSString *timeStr = @"2015-04-10"; NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; formatter.dateFormat = @"yyyy-MM-dd"; formatter.timeZone = [NSTimeZone defaultTimeZone]; NSDate *date = [formatter dateFromString:timeStr]; // 2015-04-09 16:00:00 +0000 NSLog(@"%@", date);

在一個對象的方法裏:self.name=@object;和name=@object有什麼不一樣

  • 這是老生常談的話題了,實質上就是問setter方法賦值與成員變量賦值有什麼不一樣。經過點語法self.name實質上就是[self setName:@object];。而name這裏是成員變量,直接賦值。
    通常來講,在對象的方法裏成員變量和方法都是能夠訪問的,咱們一般會重寫Setter方法來執行某些額外的工做。好比說,外部傳一個模型過來,那麼我會直接重寫Setter方法,當模型傳過來時,也就是意味着數據發生了變化,那麼視圖也須要更新顯示,則在賦值新模型的同時也去刷新UI。這樣也不用再額外提供其餘方法了。

怎樣使用performSelector傳入3個以上參數,其中一個爲結構體

- (id)performSelector:(SEL)aSelector; - (id)performSelector:(SEL)aSelector withObject:(id)object; - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;

由於系統提供的performSelector的api中,並無提供三個參數。所以,咱們只能傳數組或者字典,可是數組或者字典只有存入對象類型,而結構體並非對象類型,那麼怎麼辦呢?
沒有辦法,咱們只能經過對象放入結構做爲屬性來傳過去了:

ypedef struct HYBStruct { int a; int b; } *my_struct; @interface HYBObject : NSObject @property (nonatomic, assign) my_struct arg3; @property (nonatomic, copy) NSString *arg1; @property (nonatomic, copy) NSString *arg2; @end @implementation HYBObject // 在堆上分配的內存,咱們要手動釋放掉 - (void)dealloc { free(self.arg3); } @end

測試:

my_struct str = (my_struct)(malloc(sizeof(my_struct))); str->a = 1; str->b = 2; HYBObject *obj = [[HYBObject alloc] init]; obj.arg1 = @"arg1"; obj.arg2 = @"arg2"; obj.arg3 = str; [self performSelector:@selector(call:) withObject:obj]; // 在回調時獲得正確的數據的 - (void)call:(HYBObject *)obj { NSLog(@"%d %d", obj.arg3->a, obj.arg3->b); }

objc中向一個對象發送消息[obj foo]和objc_msgSend()函數之間有什麼關係?

實際上,編譯器在編譯時會轉換成objc_msgSend,大概會像這樣:
((void (*)(id, SEL))(void)objc_msgSend)((id)obj, sel_registerName("foo")); 也就是說,[obj foo];在objc動態編譯時,會被轉換爲:objc_msgSend(obj, @selector(foo));這樣的形式,可是須要根據具體的參數類型及返回值類型進行相應的類型轉換。

下面的代碼輸出什麼?

@implementation Son : Father - (id)init { self = [super init]; if (self) { NSLog(@"%@", NSStringFromClass([self class])); NSLog(@"%@", NSStringFromClass([super class])); } return self; } @end // 輸出 NSStringFromClass([self class]) = Son NSStringFromClass([super class]) = Son 這個題目主要是考察關於Objective-C中對self和super的理解。咱們都知道:self是類的隱藏參數,指向當前調用方法的這個類的實例。那super呢? 不少人會想固然的認爲「super和self相似,應該是指向父類的指針吧!」。這是很廣泛的一個誤區。其實 super是一個 Magic Keyword,它本質是一個編譯器標示符,和self 是指向的同一個消息接受者!他們兩個的不一樣點在於:super會告訴編譯器,調用class 這個方法時,要去父類的方法,而不是本類裏的。 上面的例子無論調用[self class]仍是[super class],接受消息的對象都是當前 Son *xxx 這個對象。 當使用self調用方法時,會從當前類的方法列表中開始找,若是沒有,就從父類中再找;而當使用super時,則從父類的方法列表中開始找。而後調用父類的這個方法。

若一個類有實例變量NSString *_foo,調用setValue:forKey:時,能夠以foo仍是_foo做爲key?

  • 二者均可以。

何時使用NSMutableArray,何時使用NSArray?

  • 當數組在程序運行時,須要不斷變化的,使用NSMutableArray,當數組在初始化後,便再也不改變的,使用NSArray。須要指出的是,使用NSArray只代表的是該數組在運行時不發生改變,即不能往NSAarry的數組裏新增和刪除元素,但不代表其數組內的元素的內容不能發生改變。NSArray是線程安全的,NSMutableArray不是線程安全的,多線程使用到NSMutableArray須要注意。

類NSObject的那些方法常常被使用?

  • NSObject是Objetive-C的基類,其由NSObject類及一系列協議構成。
  • 其中類方法alloc、class、 description 對象方法init、dealloc、– performSelector:withObject:afterDelay:等常常被使用

什麼是簡便構造方法?

  • 簡便構造方法通常由CocoaTouch框架提供,如NSNumber的 + numberWithBool: + numberWithChar: + numberWithDouble: + numberWithFloat: + numberWithInt:
  • Foundation下大部分類均有簡便構造方法,咱們能夠經過簡便構造方法,得到系統給咱們建立好的對象,而且不須要手動釋放。

什麼是構造方法,使用構造方法有什麼注意點。

什麼是構造方法:構造方法是對象初始化並一個實例的方法。

構造方法有什麼用: 通常在構造方法裏 對類進行一些初始化操做
注意點:方法開頭必須以init開頭,接下來名稱要大寫 例如 initWithName ,initLayout

建立一個對象須要通過那三個步驟?

  • 開闢內存空間
  • 初始化參數
  • 返回內存地址值

Get方法的做用是什麼?

Get方法的做用:爲調用者返回對象內部的成員變量

Set方法的做用是什麼?Set方法的好處?

  • Set方法的做用:爲外界提供一個設置成員變量值的方法。
  • Set方法的好處:
    • 不讓數據暴露在外,保證了數據的安全性
    • 對設置的數據進行過濾

結構體當中能定義oc對象嗎?

不能, 由於結構體當中只能是類型的聲明不能進行分配空間

點語法本質是什麼,寫一個點語法的例子,並寫上註釋

  • 點語法的本質是方法的調用,而不是訪問成員變量,當使用點語法時,編譯器會自動展開成相應的方法。切記點語法的本質是轉換成相應的set和get方法,若是沒有set和get方法,則不能使用點語法。
  • 例若有一個Person類 經過@property定義了name和age屬性,再提供了一個run方法。
  • Person *person = [Person new];
  • person.name=@」itcast」;//調用了person的setName方法
  • int age = person.age; // 調用了person的age方法
  • person.run //調用了person的run方法

id類型是什麼,instancetype是什麼,有什麼區別?

  • id類型:萬能指針,能做爲參數,方法的返回類型。
  • instancetype:只能做爲方法的範圍類型,而且返回的類型是當前定義類的類類型。

成員變量名的命名如下劃線開頭的好處?

  • 與get方法的方法名區分開來;
  • 能夠和一些其餘的局部變量區分開來,下劃線開頭的變量,一般都是類的成員變量。

這段代碼有什麼問題嗎:

@implementation Person - (void)setAge:(int)newAge { self.age = newAge; } @end 會死循環,會重複調用本身!self.age 改成_age便可; 而且書寫不規範:setter方法中的newAge應該爲age

截取字符串」20 | http://www.baidu.com」中,」|」字符前面和後面的數據,分別輸出它們。

NSString * str = @"20 | http://www.baidu.com"; NSArray *array = [str componentsSeparatedByString:@"|"]; //這是分別輸出的截取後的字符串 for (int i = 0; i<[array count]; ++i) { NSLog(@"%d=%@",i,[array objectAtIndex:i]); }

寫一個完整的代理,包括聲明,實現

//建立 @protocol MyDelagate @required -(void)eat:(NSString *)foodName; @optional -(void)run; @end //聲明 @interface person: NSObject< MyDelagate> //實現 @implementation person -(void)eat:(NSString *)foodName; { NSLog(@"吃:%@!",foodName);} -(void)run { NSLog(@"run!");} @end

isKindOfClass、isMemberOfClass、selector做用分別是什麼

  • isKindOfClass,做用是,某個對象屬於某個類型或者繼承自某類型

  • isMemberOfClass:某個對象確切屬於某個類型

  • selector:經過方法名,獲取在內存中的函數的入口地址

請分別寫出SEL、id、@的意思?

  • SEL是「selector」的一個類型,表示一個方法的名字-------就是一個方法的入口地址

  • id是一個指向任何一個繼承了Object(或者NSObject)類的對象。須要注意的是id是一個指針,因此在使用id 的時候不須要加*。

  • @:OC中的指令符

unsigned int 和int 有什麼區別。假設int長度爲65535,請寫出unsigned int與 int的取值範圍

int:基本整型,當字節數爲2時 取值範圍爲-32768~32767,當字節數爲4時 取值範圍
負的2的31次方 到 2的31次方減1
unsigned int:無符號基本整型,當字節數爲2時 取值範圍爲0~65535,當字節數爲4時 取值範圍爲0到2的32次方減1

Foundation對象與Core Foundation對象有什麼區別

  • Foundation對象是OC的,Core Foundation對象是C對象
  • 數據類型之間的轉換
    • ARC:bridge_retained(持有對象全部權,F->CF)、bridge_transfer(釋放對象有所權CF->F)
    • 非ARC: __bridge

編寫一個函數,實現遞歸刪除指定路徑下的全部文件。

+ (void)deleteFiles:(NSString *)path;{ // 1.判斷文件仍是目錄 NSFileManager * fileManger = [NSFileManager defaultManager]; BOOL isDir = NO; BOOL isExist = [fileManger fileExistsAtPath:path isDirectory:&isDir]; if (isExist) { // 2. 判斷是否是目錄 if (isDir) { NSArray * dirArray = [fileManger contentsOfDirectoryAtPath:path error:nil]; NSString * subPath = nil; for (NSString * str in dirArray) { subPath = [path stringByAppendingPathComponent:str]; BOOL issubDir = NO; [fileManger fileExistsAtPath:subPath isDirectory:&issubDir]; [self deleteFiles:subPath]; } }else{ NSLog(@"%@",path); [manager removeItemAtPath:filePath error:nil]; } }else{ NSLog(@"你打印的是目錄或者不存在"); } }

文章若有問題,請留言,我將及時更正。

相關文章
相關標籤/搜索