《iOS知識點梳理-ObjectC語言》

知識點總結(jié)中,如有幸被您觀看,更有可能看到不足,期待指出交流

前言

這個是高手,這個是高手,這個是高手

方法和選擇器的不同
  • selector 是一個方法的名字,method是一個組合體,包含了名字和實現(xiàn)
core foundation的內(nèi)存管理
  • 凡是帶有create, copy, retain 等字眼的函數(shù),創(chuàng)建出來的對象, 都需要在最后做一次release
  • 比如 CFRunLoopObserverCreate release函數(shù): CFRelease(對象)
malloc和new的區(qū)別
  • new 是c++的操作符, malloc是c中的一個函數(shù)
  • new 不止是是分配內(nèi)存,而且會調(diào)用類的構(gòu)造函數(shù),同理delete會調(diào)用類的析構(gòu)函數(shù),而malloc則只分配內(nèi)存,不會進行初始化類成員的工作,同樣free也不會調(diào)用析構(gòu)函數(shù)
  • new可以認為是malloc加構(gòu)函數(shù)的執(zhí)行
  • new 出來的指針是直接帶類型信息的
OC中的反射機制
  • class反射
  • 通過類名的字符串形式實例化對象
Class class  NSClassFromString@(@"student");
student *stu = [[class alloc] init];
  • 將類名變成字符串
Class class = [Student class];
NSString *className = NSStringFromClass(class);
  • SEL的反射
  • 通過方法的支付創(chuàng)新是實例化方法
    SEL selector = NSSelectorFromClass(@"setName");
    [stu performSelector:selector withObject:@"Mike"];
  • 將方法變成字符串
    NSStringFromSelector(@selector(*setName:))
SEL 理解和調(diào)用

理解:

  • SEL 就是對方法的一種包裝.包裝的SEL類型數(shù)據(jù)它對應相應方法地址,找到方法地址就可以調(diào)用方法.在內(nèi)存中每個類的方法都儲存在類對象中,每個方法都有一個與之對應的SEL類型數(shù)據(jù),根據(jù)一個SEL數(shù)據(jù)就可一個找到對應的方法地址,進而調(diào)用方法
  • SEL s1 = @selector(tet1); // 將test1方法包裝成SEL對象
  • SEL s2 = NSSelectorFromString(@"test1"); // 將一個字符串方法轉(zhuǎn)換成SEL對象

調(diào)用:

  • 直接通過方法名來調(diào)用
  • 間接的通過SEL數(shù)據(jù)來調(diào)用 SEL aaa = @selector(text);[person performSelector:aaa];
協(xié)議中<NSObject>是什么意思?子類繼承了父業(yè),那么子類會遵守父類中遵守的協(xié)議嗎?協(xié)議中能夠定義成員變量?如何約束一個對象類型的變量要存儲的地址是一個遵守一個協(xié)議對象?
  • 遵守NSObject協(xié)議
  • 能,但是只在頭文件中聲明,編譯器是不會自動生成實例變量的.需要自己處理getter和setter方法
  • id<XXX>
NS/CF/CG/CA/UI 這些前綴的含義
  • 函數(shù)歸屬于 cocoa Fundation 框架
  • 函數(shù)歸屬于 core Fundation 框架
  • 函數(shù)歸屬于 coreGrahics.frameWorks 框架
  • 函數(shù)歸屬于 UIKit 框架
面向?qū)ο蠖加心男┨卣饕约澳銓@些特征的理解
  • 繼承:繼承是從已有類得到繼承信息創(chuàng)建新類的過程.提供繼承信息的類被成為父類(超類,基類);得到繼承信息的類被成為子類(派生類).繼承讓變化中的軟件系統(tǒng)有一定的延續(xù)性,同時繼承也是封裝程序中可變因素的重要手段
  • 封裝:封裝是把數(shù)據(jù)和操作數(shù)據(jù)的方法綁定起來,對數(shù)據(jù)的訪問只能通過已定義的接口.我們在類中編寫的方法就是對實現(xiàn)細節(jié)的一種封裝;我們編寫一個類就是對數(shù)據(jù)和數(shù)據(jù)操作的封裝.可以說,封裝就是隱藏一切可隱藏的東西,只向外界提供最簡單的編程接口
  • 多態(tài)性:多態(tài)性是指允許不同子類型的對象對統(tǒng)一消息做出不同的響應.簡單的說就是用同樣的對象調(diào)用同樣的方法但是做了不同的事情.多態(tài)性分為編譯時的多態(tài)性和運行時的多態(tài)性.方法重載(overload)實現(xiàn)的是編譯時的多態(tài)性(也成為前綁定),而方法重寫(override)實現(xiàn)的是運行時的多態(tài)性(也稱后綁定).運行時的多態(tài)是面向?qū)ο笞罹璧臇|西,要實現(xiàn)多態(tài)需要做兩件事:1.方法重寫(子類繼承父類并重寫父類中已有的或抽象的方法);2.對象造型(用父類型引用引用子類對象,這樣同樣的引用調(diào)用同樣的方法就會根據(jù)子類對象和不同而表現(xiàn)出不同的行為)
  • 抽象:抽象是將一類對象的共同點特征總結(jié)出來構(gòu)造類的過程,包括數(shù)據(jù)抽象和行為抽象兩方面.抽象只關(guān)注對象有哪些屬性和行為,并不關(guān)注這些行為的細節(jié)是什么.
Object-C,動態(tài)運行時語言
  • 主要是將數(shù)據(jù)類型的確定由編譯時,推遲到運行時.這個問題其實淺涉及到兩個概念,運行時和多態(tài)
  • 簡單的來說,運行時機使我們直到運行時才去確定一個對象的類別,以及調(diào)用該類別對象指定方法.
  • 多態(tài):不同對象以自己的方式響應相同的消息的能力叫多態(tài)
    -意思就是建設生物類(list)都用用一個相同的方法-eat,人類屬于生物,豬也屬于生物,都繼承了list后,實現(xiàn)各自的-eat,但是調(diào)用使我們只需要調(diào)用各自的eat方法.也就是不同的對象都以自己的方式響應了相同的消息(響應了eat這個選擇器).因此也可以說,運行時機制是多態(tài)的基礎.
readwrite,readonly,assign,retain,copy,nonatomic屬性的作用?
  • readwrite 是可讀可寫特性,需要生成getter防范和setter方法
  • readonly 是只讀特性 只會生成getter方法, 不會生成setter方法,不希望屬性在類外改變
  • assign 是賦值特性, setter 方法將傳入?yún)?shù)賦值給實例變量;僅設置變量時,assign用于簡單數(shù)據(jù)類型,如NSInteger,double,bool;
  • retain 表示持有特性,setter方法將傳入?yún)?shù)先保留,再賦值,傳入?yún)?shù)的引用計數(shù)retaincount會+1
  • copy 便是賦值特性,setter方法會傳入對象復制一份;需要完全一份新的變量時;
  • nonatomic 非原子性操作,確定編譯器生成的seter getter 是否需要要原子操作;
  • atomic 表示多線程安全, 一般使用 nonatiomic;
NotificationCenter,kvc,kvo,Delegate,區(qū)別
  • KVO(Key-Value-Observing):一對多,觀察者模式,鍵值觀察機制,他提供了觀察某一屬性變化的方法,極大簡化了代碼
  • KVC(Key-Value-Coding):是鍵值編碼,一個對象在調(diào)用setValue
    -- 檢查是否存在相應key的set方法,車載就調(diào)用set方法
    -- set方法不存在的,就查找_key的成員變量是否存在,存在就直接賦值
    -- 如果_key沒有找到,就查找相同名稱的key,存在就賦值
    -- 如果沒有就調(diào)用valueForUndefinedkey和setValue:forUndefinedKey.
  • Delegate:通常發(fā)送者和接受者的關(guān)系是直接的一對一關(guān)系
    -- 代理的目的是改變或者傳遞控制鏈.允許一個類在某些特定時刻通知到其他類,而不需要要獲取到那些類的指針.
    -- 可以減少框架復雜度.消息的發(fā)送者告知接收者某個事件將要發(fā)生,delegate同意然后發(fā)送響應事件,delegate機制使得接受者可以改變發(fā)送者的行為
  • Notification:觀察者模式,通常發(fā)送者和接受者的關(guān)系是間接的多對多關(guān)系.消息的發(fā)送者告知接受者事件已經(jīng)發(fā)生或者將要發(fā)送,僅此而已,接收者并不能反過來影響發(fā)送者的行為
  • 區(qū)別
    -- 效率肯定是delegate比NSNotification高.
    -- delegate方法比notification更加直接,需要關(guān)注返回值,所以delegate方法往往包含should這個很傳神的詞.相反的,notification最大的特色就是不關(guān)心結(jié)果.所以notification往往用did這個詞匯.
    -- 倆個模塊之間聯(lián)系不是很緊密,就用notificaiton傳值,例如多線程之間傳值用notification.
    -- delegate 只是一種較為簡單的回調(diào),而且主要用在一個模塊當中,例如底層功能完成了,需要把一些值傳到上層去,就事先吧上層的函數(shù)通過delegate傳到底層,然后在底層call這個delegate,它們都在一個模塊中,完成一個功能,例如說 NavgationController 從 B 界面 到 A 點返回按鈕(調(diào)用popViewController方法)可以用delegate比較好
懶加載
  • 懶加載,只在用到的時候才回去初始化.也可以理解成延時加載.我覺得最好也最簡單的一個例子就是tableView中圖片的加載顯示了,一個延時加載,避免內(nèi)存過高,一個異步加載,避免線程堵塞提高用戶體驗
OC有多繼承嗎,沒有的話可以用什么方法代替
  • 多繼承即一個子類可以有多個父類,它繼承了多個父類的特性
  • Object-C的類沒有多繼承,只有支持單繼承,如果要實現(xiàn)多繼承的話,可以通過類別和協(xié)議的方式來實現(xiàn)
  • protocol(協(xié)議)可以實現(xiàn)多個接口,通過實現(xiàn)多個接口可以完成多繼承:
  • Category(類別)一般使用分類,用Category去重寫類的方法,僅對本Category有效,不會影響到其他類與原有類的關(guān)系
分別描述類別(categories)和延展(extensions)是什么?以及倆者的區(qū)別?繼承和類別在實現(xiàn)中有何區(qū)別?為什么category只能為對象添加方法,卻不能添加成員變量
  • 類別:在沒有原類.m文件的基礎上,給該類添加方法;
  • 延展: 一種特殊的類別,主要在一個類的.m文件里聲明和實現(xiàn)延展的作用,就是給某個類添加私有方法和私有變量.
    ** 倆個的區(qū)別: **
    -延展可以添加屬性并且他添加的方法是必須要實現(xiàn)的.延展可以認為是一個私有的類目
    -類別可以再不知道,不改變原來代碼的情況下往里面添加新的方法,只能添加,不能刪除
  • 并且如果類別和原來類中的方法產(chǎn)生名稱沖突,那么類別會覆蓋之前的防范,類別具有更高的優(yōu)先級
  • 集成可以增加,修改刪除方法,添加屬性
  • category 只能為對象添加方法,卻不能天啊及成員變量的原因:如果可以添加成員變量,添加的成員變量沒有辦法初始化
Object-C有是有方法嗎?私有變量呢?如果沒有的話,有沒有什么代替的方法?
  • Objective-c類里面的方法只有倆種,靜態(tài)方法和實例方法,但是可以通過把方法的聲明和定義都放在.m文件中.在Objective-C中,所有實例變量默認都是私有的,所有實例方法默認都是公有的
include和#import的區(qū)別?#import與@class的區(qū)別
  • import 指令是 Object-C針對 #include 的改進版本, #import 確保引用的文件只會被引用一次,這樣這不會陷入遞歸包含的問題了
  • import 與 @calss 二者的區(qū)別在于
    -- import 會鏈入該頭文件的全部信息,包括實例變量和方法等;而@class只是告訴編譯器,其后面聲明的名稱是類的名稱,至于這些類是如何定義的,暫時不用考慮
    -- 在頭文件中一般使用@class來聲明這個名稱是類的名稱,不需要知道其內(nèi)部的實體變量和方法
    -- 在實現(xiàn)類里面,因為會用到這個引用類的內(nèi)部的實體變量和方法,所以需要用#import來包含這個被引用類的頭文件
    -- 在編譯效率方面, 如果你有100個頭文件都#import了同一個文件,或者這些文件是依次應用的,如A->B,B->C,C->D,這樣的引用關(guān)系,如果你的類有很多的話,這將會耗費大量的時間.而@class則不會
    -- 如果有循環(huán)依賴關(guān)系,如A->B,B->A,這樣的相互依賴關(guān)系,如果使用#import來相互包含,那么就會出現(xiàn)編譯錯誤,如果使用@class在倆個類的頭文件中相互聲明,則不會有變異錯誤的出現(xiàn).
淺拷貝和深拷貝
  • 淺拷貝:只賦值指向?qū)ο蟮闹羔?而不復制引用對象本身.
  • 深復制:復制引用對象本身.深復制就好理解理解了,內(nèi)存中存在了兩份獨立對象本身,當修改A時,A_copy不變.
類變量的@protected,@private,@public,@package聲明有什么含義?

變量的作用域不同

  • @protected 該類和子類中訪問,是默認的
  • @private 只能在本類中訪問;
  • @public 任何地方都能訪問
  • @package 本包內(nèi)使用,跨包不能使用
Objective-C和C,C++之間的聯(lián)系和區(qū)別
  • Objective-C和C++都是C的面向?qū)ο蟮某?/li>
  • Object與C++的區(qū)別主要點:Object_C是完全動態(tài)的,支持在運行時動態(tài)類型決議,動態(tài)綁定以及動態(tài)轉(zhuǎn)載;而C++是部分動態(tài)的,編譯時靜態(tài)綁定,通過嵌入類(多重集成)和虛函數(shù)(虛表)來模擬實現(xiàn)
  • Objective-C在語言層次上辭職動態(tài)消息轉(zhuǎn)發(fā),其消息發(fā)送語法為[object function];而且C++ 為 objec->function(),兩者的語義也不同,在Objective-C里是發(fā)送消息到一個對象上,至于這個對象能不能響應消息以及是響應還是轉(zhuǎn)發(fā)消息都不會crash;而在C++里是說對象進行了某個操作,如果對象沒有這個操作的話,要么編譯會報錯(靜態(tài)綁定),要么程序會crash掉的 (動態(tài)綁定).
目標-動作機制
  • 目標是動作消息的接收者,一個控件,或者更為常見的是他的單元,以插座變量的形式保持其動作消息的目標.
  • 動作是控件發(fā)送給目標的消息,或者從目標的角度看,它是目標為了響應動作而實現(xiàn)的方法.程序需要某些機制來進行事件和指令的翻譯.這個機制就是目標-動作機制.
Objective-C優(yōu)點和缺點
  • 優(yōu)點:1.Cateogiey.2.posing.3動態(tài)識別4.指標計算;5.彈性信息傳遞;6.不是一個過度復雜的C衍生語言;7.Objective-C與C++可混合編程
  • 確定:1.不支持命名空間;2.不支持運算符重載;3.不支持多重繼承;4使用動態(tài)運行類型,所有的方法都是函數(shù)調(diào)用,所以很多編譯時優(yōu)化方法都用不到.(如內(nèi)聯(lián)函數(shù)等),性能低劣
C語言的函數(shù)調(diào)用和OC的消息機制有什么區(qū)別
  • 對于C語言.函數(shù)的調(diào)用在編譯的時候會決定調(diào)用哪個函數(shù).編譯完成之后直接順序執(zhí)行
  • OC的函數(shù)調(diào)用成為消息發(fā)送.屬于動態(tài)調(diào)用過程.在編譯的時候并不能解決真正的調(diào)用哪個函數(shù)(事實證明在編譯階段,OC可以調(diào)用任何函數(shù),即使這個函數(shù)并未實現(xiàn),只要申請過就不會報錯,而C語言在編譯階段就會報錯).只有在真正運行的時候才會根據(jù)函數(shù)的名稱找到對應的函數(shù)來調(diào)用.
什么是謂詞

謂詞就是通過NSPredicate給定的邏輯條件作為約束條件,完成對數(shù)據(jù)的篩選

// 定義謂詞對象,謂詞對象中包含了過濾條件
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"age<%d", 30];
// 可以使用&&進行多條件過濾
predicate= [NSPredicate preicateWithFormat:@"name='1'&&age > 40"];
array = [persons filteredArrayUsingPredicate:predicate];
// 包含語句的使用
predicate = [NSPredcate predicateWithFormat:@"self.nameIN{'1','2','3'}||sele.age IN{30,40}"]
/** 指定字符開頭和指定字符結(jié)尾,是否包含指定字符 */ 
// name已a開頭的
predicate = [NSPredicate predicateWithFormat:@"name BEGINSWITH'a'"];
// name 中包含字符a的
predicate = [NSPredicate redicateWithFormat:@"name Contains'a'"];
// like 進行匹配多個字符
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的區(qū)別
  • atomic提供多線程安全,房子讀寫未完成的時候被另外一個線程讀寫,造成數(shù)據(jù)錯誤
  • nonatomic在管理內(nèi)存的環(huán)境中,解析的訪問器保留并自動釋放返回值,若指定了nonatomic,那么訪問器只是簡單的返回這個值
常見的oc數(shù)據(jù)類型那些,和c的基本類型有啥區(qū)別
  • 常見的:NSInteger CGFloat NSString NSNumber NSArray NSDate
  • NSInteger 根據(jù)32或者64位系統(tǒng)確定本身是int還是long
  • CGFloat根據(jù)32或者64位系統(tǒng)確定本身是float還是double
  • NSString NSNumber NSArray NSDate 都是指針類型的對象,在堆中分配內(nèi)存,c語言中char int 等都是在棧中分配空間
id 和 nil 代表什么
  • id 類型的指針可以指向任何OC對象
  • nil 代表空值(空指針的值, 0)
nil和NULL的區(qū)別
  • 從oc的官方語法上面看,nil標識對象的指針即對象的引用為空
  • null表示指向基礎數(shù)據(jù)類型變量即c語言變量的指針為空
  • 在非arc中 倆個空可以互換,但是在arc中普通指針和對象引用被嚴格限制,不能互換
    nil,Nil,NULL和NSNull區(qū)別
  • nil和C語言的NULL相同,在objc/objc.h中定義.nil表示objective-C對象的值為空.在C語言中,指針的空值用NULL表示.在Objective-C中,nil對象調(diào)用任何方法表示什么也不執(zhí)行,也不會崩潰
  • Nil:那么對于我們Objective-C開發(fā)來說,Nil也就代表((void*)0).但是它是用來代表空類的,比如:Class myClass = Nil;
  • NULL:在C語言中,NULL是無類型的,只是一個宏,它代表空.這就是在C/C++中的空指針.對于我們Objective-C開發(fā)來說,NULL就表示((void*)0)
  • NSNull:NSNull集成于NSObject的類型.它是很特殊的類,它表示是空,什么也不是儲存,但是它確是對象,只是一個占位對象.使用場景就不一樣了.比如說服務端接口中讓我們在值為空的時,穿空.NSDictionry *parameter = @{@"arg1":@"value1",@"arg2",arg2.isEmpty?[NSNull null]:arg2};
    *NULL,nil,Nil這三者對于Objective-C中值是一樣的,都是(void )0,那么為什么要區(qū)分,又與NSNull之間有什么區(qū)別
  • NULL 是宏, 是對于C語言指針來使用的,表示空指針
  • nil 是宏, 是對于Objective-C中的類而使用的,表示類指向空
  • Nil 是宏,是對于Objective-C中的類而使用的,表示類指向空
  • NSNull 是類類型, 是用于表示空的占位對象,與JS或者服務端的null類似的含義
像一個nil對象發(fā)送消息會發(fā)生什么?
  • 像nil發(fā)送消息是完全有效的--只是在運行的時候不會有任何的作用
  • 如果一個方法返回值是一個對象,那么發(fā)送給nil的消息將返回0(nil)
  • 如果方法返回值為指針類型,其指針大小為小于或者等于sizeof(void*),float,double,long double 或者 longlong的整型標量, 發(fā)送給nil的消息將返回0(nil)
  • 如果方法返回值為指針類型,其指針大小為小于或者等于sizeof(void*),float,double,long double或者long long 的整型標量, 發(fā)送給nil的消息將返回0
    如果方法返回值為結(jié)構(gòu)體,正如在《Mac OS X ABI 函數(shù)調(diào)用指南》,發(fā)送給nil的消息將返回0,結(jié)構(gòu)體中各個字段的值都是0.其他的結(jié)構(gòu)體數(shù)據(jù)類型將不是用0填充的
  • 如果方法的返回值不是上述提到的幾種情況,那么發(fā)送給nil的消息的返回值將是未定義.self.和self->的區(qū)別
  • self.是調(diào)用get或者set方法
  • self是當前本身, 是一個指向當前對象的指針
  • self->是直接訪問成員變量
類方法和實例方法的本質(zhì)區(qū)別和聯(lián)系
屏幕快照 2018-12-14 下午5.37.31.png
_block/weak修飾符區(qū)別
  • _block在arc和mrc環(huán)境下都能使用,可以修飾對象,也能修飾基本數(shù)據(jù)類型
  • _weak只能在arc環(huán)境下使用,只能修飾對象(NSString),不能修飾基本數(shù)據(jù)
  • _block對象可以在block中重新賦值, _weak不行
寫一個NSString類的實現(xiàn)
NSString *str = [[NSString alloc]initWithCString:nullTerminatedCString encodeing:encoding];
為什么標準頭文件都有類似以下的結(jié)構(gòu)
ifndef __INCvx Worksh
define __INCvx Worksh
ifdef __cplusplus
ectern "C"{
endif
ifdef __cplusplus
}
endif
endif

顯然,頭文件中的編譯宏#ifndef INCvxWorksh,#define INCvxWorksh,#endif 的作用是防止該頭文件唄重復引用

init和intwithobject區(qū)別(語法)
  • 后者給屬性賦值
@property的本質(zhì)是什么?ibar,getter,setter是如何生成并添加到這個類中的

@property的本質(zhì):
@property = ivar(實例變量) + getter (取方法) + setter(存方法)
屬性(peoperty)兩大概念:
ivar(實例變量),存取方法(access method = getter + setter)
ivar,getter,setter如何生成并添加到類中:
這是編譯器自動合成的,通過@synthesize關(guān)鍵字指定,若不指定,默認為這是編譯器自動合成的,通過@synthesize關(guān)鍵字指定,若不指定,默認為@shnthesize propertyName = _propertyName;若手動實現(xiàn)了getter/setter方法,則不會自動合成.
現(xiàn)在編譯器已經(jīng)默認為我們添加@synthesize propertyName = propertyName;因此不再需要手動添加,除非你真的要改變成員變量
生成getter方法時,會判斷當前屬性名是否有
,比如聲明屬性@property(nonatiomic,copy) NSString *_name; 那么所生成的成員變量就會變成name,如果我們要手動生成getter方法,就要判斷是否以開頭了.不過,命名都要有規(guī)范,是不允許色林屬性是使用開頭的,不規(guī)范的命名,在使用runtime的時候,會帶來很多不方便

這個寫法會出什么問題:@property(copy)NSMutableArray *array;
  • 沒有指明未nonatiomic,因此就是atomic原子操作,會影響性能.該屬性使用同步鎖,會在創(chuàng)建時生成一些額外的代碼用于幫助編寫多線程程序,這會帶來性能問題,通過聲明nonatomic可以節(jié)省這些雖然很小但是不必要的額外開銷.在我們的應用程序中,幾乎都是使用nonatiomic來聲明的,因為使用atomic并不能保證絕對的線程安全,對于要絕對保證線程安全的操作,還需要使用更高級的方式來處理,比如NSSpinLock,@syncronized等
  • 因為使用的是 copy,所得到的實際是NSArray類型,它是不可變的,若在使用中使用了增,刪,改操作,就會crash
@protocol和category中如何使用@property
  • 在protocol中使用@property只會生成setter和getter方法聲明,我們使用屬性的目的是希望遵守我協(xié)議的對象能實現(xiàn)該屬性
  • category 使用@property也只是會生成stter和getter方法的聲明,如果我們真的需要給category增加屬性的實現(xiàn),需要借助于運行時的兩個函數(shù)
    -- objc_setAssociatedObject
    -- objc_getAssociatedObject
@property中有哪些屬性關(guān)鍵字
  • 原子性(atomic, nonationmic)
  • 讀寫(readwrite, redonly)
  • 內(nèi)存管理(assign,strong,weak,unsafe_unretaied,copy)
  • getter, setter
isa指針問題
  • isa: 是一個Calss類型的指針,每個是你對象有個isa的指針,他指向?qū)ο蟮念?而Class里也有個isa的指針,指向meteCalss(元類).元類保存了類方法的李彪.當類方法被調(diào)用時,先會從本身查找類方法的實現(xiàn),如果沒有,元類會先從他父類查找該方法.同時注意的是:元類(meteCalss)也是類,它也是對象.元類也有isa指針,它的isa指針最終指向一個根元類(root meteClass).根元類的isa指向本身,這樣就行程了一個封閉的內(nèi)循環(huán)
如何訪問并修改一個類的私有屬性
  • 一種是通過KVC獲取
  • 通過runtime訪問并修改私有屬性
如何為Class定義一個對外只讀對內(nèi)可讀寫的屬性

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

Objective-C中,meta-Class指的什么?

meta-class是Class對象的類,為這個Class類儲存類方法,當一個類發(fā)送消息時,就會去這個類對應的metaClass中查找那個消息,每個Class都有不同的meta-class,所有的meta-class都使用基類的meta-class(假如類繼承NSObject,那么他對應的meta-class也是NSObject)作為他們的類

Objective-C的class是如何實現(xiàn)的,selector是如何轉(zhuǎn)換成C語言的函數(shù)調(diào)用的
  • 當一個類被正確的編譯過后,在這個編譯成功的類里面,存在一個變量用于保存這個類的信息.我們可以通過[NSClassFromString]或[obj class].這樣的機制允許我們在程序執(zhí)行的過程當中,可以Class來得到對象的類,也可以在程序執(zhí)行的階段動態(tài)的生成一個再編譯階段無法確定的一個對象.(isa指針)
  • @selector()基本可以等同C語言的中函數(shù)指針,只不過C語言中,可以把函數(shù)名直接賦給一個函數(shù)指針,而Object-C的類不能直接應用函數(shù)指針,這樣只能做一個@selector語言來取.
@interface foo
- (int)add:int val;
@end

SEL class_func; //定義一個類方法指針
class_func = @selector(add:int);
  • @selector 是查找當前類的方法, 而[object @selector(方法名:方法參數(shù)...)];是取object對應類的相應方法
  • 查詢類方法時,除了方法名,方法參數(shù)也查詢條件之一
  • 可以用字符串來找方法 SEL 變量名 = NSSelectorFromString(方法名字的字符串);
  • 可以運行中用SEL變量反向查出方法名字字符串.NSString *變量名 = NSStringFromSelect(SEL參數(shù))
  • 取到Selector的值以后,執(zhí)行seletor.SEL變量執(zhí)行.用performSelecor方法來執(zhí)行.[對象 performSelector:SEL變量 withObjet:參數(shù)1 withObject:參數(shù)2];
對于語言NSString *obj = [[NSData alloc] init]; 編譯時和運行時 obj 分別是什么類型
  • 編譯時是NSString 類型, 運行時是NSData類型
@synthesize和@dynamic分別什么作用
  • @property有倆個對應的詞,一個 是 @synthesize,一個是@dynamic.如果@synthesize 和 @dynamic都沒寫,那么默認的就是@synthesize var = _var;
    -@synthesieze 的語義是如果你沒有手動實現(xiàn) setter 方法和 getter 方法, 那么編譯器會自動為你加上這個倆個方法.
  • @dynamic 告訴編譯器:屬性的setter與getter方法由用戶自己實現(xiàn),不自動生成.(當然對于 readonly 的屬性只需提供getter即可).假如一個屬性被聲明為 @dynamic var,然后你沒有提供 @setter 方法和 @getter 方法,編譯的時候沒有問題,但是當程序運行到 instance.var = someVar, 由于缺 setter 方法會導致程序崩潰; 或者當運行到 someVar = var 時,由于缺getter方法同樣會導致崩潰.編譯時沒有問題,運行時才執(zhí)行相應的方法,這就是所謂的動態(tài)綁定.
NSString的時候用copy和strong的區(qū)別

OC中NSString為不可變字符串的時候,copy和strong都是只分配一次內(nèi)存,但是如果用copy的時候,需要先判斷字符串時候是不可變字符串,如果是不可變字符串,就不再分配控件,如果是可變字符串才分配控件.如果程序中用到NSString的地方特別多,每一次都要先進行判斷就會消耗性能,影響用戶體驗,用strong就不會再進行變短,所以,不可變字符串都可以直接用strong.

NSArray,NSSet,NSDictionary,與NSMutableArray,NSMutableSet, NSMutableDictionary的特性和作用(遇到copy修飾產(chǎn)生變化)

特性:

  • NSArray 表示不可變的數(shù)組, 是有序元數(shù)集,只能儲存對象類型,可通過索引直接訪問元數(shù),而且元數(shù)類型可以不一樣,但是不能進行增刪改,NSMutableArray是可變數(shù)組,能進行增刪改.通過索引查詢值很快,但是插入,刪除,等效率很低
  • NSSset標識不可變集合,具有穩(wěn)定性,互異性,無序性的特點,只能訪問而不嗯呢修改集合:NSMutableSet可變集合,可以對集合進行增刪改.集合通過值查詢很快,插入,刪除操作極快
  • NSDictionary 表示不可變字典,具有無序性的特點,每個key對應的值是唯一的,可通過key直接取值,NSMutableDictionary表示可變字典,能對字典進行增刪改,通過key查詢插入和刪除都很快.
    作用
  • 數(shù)組用于處理一組有序的數(shù)據(jù)集,比如常用的列表的dataSource要求有序,可通過索引直接訪問,效率高
  • 集合要求具有確定性,互異性,無序性,在iOS開發(fā)中是比較少使用到的,筆者也不清楚如何說明其作用
  • 字典是鍵值對數(shù)據(jù)集,操作字典效率極高,時間復雜度為常量,但是值是無序的,在iOS中,常見的JSON轉(zhuǎn)字典,字典轉(zhuǎn)模型就是之中的一種應用.
請把字符串2015-04-10格式化日期轉(zhuǎn)換為NSDate類型
NSString *timeStr = @"2015-04-10";
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"yyyy-MM-dd";
formatter.timeZone = [NSTimeZone defaultTimeZone];
NSDate *date = [formatter fateFromString:timeStr];
// 2015-04-09 16:00:00 + 0000
NSLog(@"%@", date);
在一個對象的方法里面:self.name=@object;和name=@object有什么不同
  • 這是老生常談的話題了,實質(zhì)上就是問setter方法賦值與成員變量賦值有什么不同.通過點語法self.name實質(zhì)上就是[self setName];兒name這里是成員變量,直接賦值
  • 一般來說,在對象的方法里成員變量和方法都是可以訪問的,我們通常會重寫seter方法來執(zhí)行某些額外的工作.比如說,外部傳一個模型過來,那么我會直接重寫setter方法,當模型傳過來時,也就因為這數(shù)據(jù)發(fā)生了變化,那么視圖也需要更新顯示,則在賦值新模型的同時也在刷新UI.這樣也不用在額外去提供其他方法了
怎樣使用performSelector傳入3個以上參數(shù),其中一個為結(jié)構(gòu)體
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;

因為系統(tǒng)提供的performSelector的api中,并沒有提供三個參數(shù).因此,我們只能傳數(shù)組或者字典,三十數(shù)組或者字典自有存入對象類型,而結(jié)構(gòu)體并不是對象類型,那怎么辦呢?沒有辦法,我們只能通過對象放入結(jié)構(gòu)最為屬性傳遞過去了

typedef 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
//  在堆上分配內(nèi)存,我們要手動釋放
 - (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];
// 在回調(diào)時得到正確的數(shù)據(jù)
- (void)call:(HYBObject *)obj {
    NSLog(@"%d %d", obj.arg3->a, obj.arg3->b);
}
objc中一個對象發(fā)送消息[obj foo]和objc_msgSend()函數(shù)之間有什么關(guān)系

實際上,編譯器在編譯的時候會轉(zhuǎn)換成objc_msgSedn,大概會像這樣:

(void(*))(id, SEL)
((void) objc_msgSend)
((id)obj, sel_registerName("foo"))

也就是說, [obj foo];在objc動態(tài)編譯時,會被轉(zhuǎn)換成:objc_msgSend(obj,@selector(foo));這樣的形式, 但是需要根據(jù)具體的參數(shù)類型返回值類型進行相應的類型轉(zhuǎn)換.

下面代碼輸出是什么
@implementation Son: Father

- (id)init {
    self = [super init];
    if (self) {
        NSLog(@"%@", NSStringFromClass([self class]));
        NSLog(@"%@", NSStringFromClass([super class]));
    }
    return self;
}

@end

結(jié)果:

NSStringFromClass([self class]) = Son
NSStringFromClass([super class]) = Son

解析:這個題目主要是考察關(guān)于Objective-C中對self和super的理解.我們都知道:self是類的隱藏參數(shù),指向當前調(diào)用方法的這個類的實例.那么super呢,很多人會想當然的認為"super"和self類似,應該是指向父類的指針吧!這是很普遍的一個誤區(qū).其實super是一個 magic keyword,他的本質(zhì)是個編譯器標識符,和self是指向同一個消息接受者!她們倆個的不同點在于:super告訴編譯器,調(diào)用class這個方法時,要去父類的方法,而不是本類里面的.上面的例子不管調(diào)用[self class]還是[super class],接受消息的對象都是當前 son *xxx 這個對象.當使用self調(diào)用方法時,會從當前類的方法列表中開始找,如果沒有,就從父類中再找;而當使用super時,則會從父類的方法列表中開始找.然后調(diào)用父類的這個方法.

若一個類有實例變量NSString *_foo, 調(diào)用setValue:forkey:時,可以foo還是_foo作為key
  • 兩者都可以
什么時候使用NSMutableArray,什么時候使用NSArray
  • 當數(shù)組在程序運行時,需要不斷的變化,使用NSMutableArray,當數(shù)組在初始化后,便不再改變的,使用NSArray.需要指出的是,使用NSArray只表明的是該數(shù)組在運行的時候不會發(fā)生改變,即不能往NSAarray的數(shù)組里面新增和刪除元素,但不表明其數(shù)組內(nèi)的元素的內(nèi)容不能發(fā)生改變.NSArray是線程安全的,NSMutableArray不是線程安全的,多線程使用到NSMutableArray需要注意
類NSObject的哪些方法經(jīng)常被使用
  • NSObject是Objective-C的基類,其由NSObject類以及一系列協(xié)議構(gòu)成.
  • 其中類方法alloc,class,description 對象方法 init, dealloc, - performSelector:withObject:afterDelay:等經(jīng)常被使用
什么是簡便構(gòu)造器
  • 簡便構(gòu)造方法一般由CocoaTouch框架提供,如NSNumber+numberWithBool + numberWithChar + numberWithDouble + numberWithFloat + numberWithInt
  • Foundation 下大部分類均有簡便構(gòu)造器方法,我們可以通過簡便構(gòu)造方法,活的系統(tǒng)給我們創(chuàng)建好的對象,并且不需要手動釋放
什么是構(gòu)造器方法,使用構(gòu)造器的特點
  • 構(gòu)造方法是對象初始化并且實例的方法
  • 一般構(gòu)造方法里對類進行一些初始化操作,方法必須要init開頭,接下來名稱要大寫,例如initWithName.initLayout
創(chuàng)建一個對象需要經(jīng)過哪三個步驟
  • 開辟內(nèi)存空間
  • 初始化參數(shù)
  • 返回內(nèi)存地址值
get方法的作用是什么
  • 為調(diào)用者返回對象內(nèi)部的成員變量
set方法的作用是什么,set的好處
  • 為調(diào)用者設置對象內(nèi)部的成員變量
    好處
  • 在成員變量的變化時候可以在方法里面做相應的操作,無需寫多余的方法
  • 不然數(shù)據(jù)暴露在外,保證了數(shù)據(jù)的安全性
  • 對這是的數(shù)據(jù)進行過濾
結(jié)構(gòu)體當中不能定義OC對象嗎
  • 不能,因為結(jié)構(gòu)體當中只能是類型的聲明不能進行分配空間
點語法本質(zhì)是什么,寫一個點語法的例子,并寫上注釋
  • 點語法的本質(zhì)是方法的調(diào)用, 而不是訪問成員變量, 當使用點語法時,編譯器會自動展開成相應的方法.切記點語法的本質(zhì)是轉(zhuǎn)換成相應的set和get方法,如果沒有set和get方法,則不能使用點語法.
  • 例如有一個Person類 通過@property定義了name和age屬性,在提供一個run方法.
Person *person = [Person new];
person.name = @"itcast";調(diào)用了person的setName方法
int age - person.age; // 調(diào)用了person的age方法
person.run // 調(diào)用了person的run方法
id類型是什么,instancetype是什么,有什么區(qū)別
  • id類型:萬能指針,能作為參數(shù),防范的返回類型
  • isntancetype:只能作為方法的范圍類型,并且返回的類型是當前定義類的類型.
成員變量名的命名以下劃線開頭的好處
  • 與get方法的方法名區(qū)分開來
  • 可以和一些其他的局部變量分開來,下劃線開頭的變量,通常都是類的成員變量
下面這段代碼有什么問題
@implementation Person
- (void)setAge:(int)newAge {
self.age = newAge;
}
@end

這個會造成死循環(huán),點語法是方法的調(diào)用,會一直走這個方法,_age = age;書寫也不規(guī)范應該是吧newAge改成age

截取字符串"20|http://www.bai.com"中,"I"字符前面和后面的數(shù)據(jù),分別輸出他們
NSString *str = @"20|http://ww.baidu.com";
NSSArray *array = [str componentsSeparatedByString:@"|"]:
// 打印前后的數(shù)據(jù)輸出
for (int i = 0; i <array.count; i ++) {
    NSLog(@"%d=%@", i,[array objectAtInde:i]);
}
寫一個完整的代碼,包括聲明,實現(xiàn)
// 創(chuàng)建
@protocol MyDelete
@required
- (void)eat:(NSString *)foodName;
@optional
- (void)run;
// 聲明
@interface person : NSObject<MyDelagete>
@end
// 實現(xiàn)
@implement person
- (void)eat:(NSString  *)foodName {
    NSLog(@"吃%@",foodName);
}
- (void)run {
    NSLog(@"run!");
}
@end
isKindOfClass,isMemberOfClass,selector作用分別是什么
  • isKindOfClass, 作用是,某個對象屬于某個類型或者繼承自某類型
  • isMemberOfClass:某個對象確切屬于某個類型
  • selector:通過方法名,獲取在內(nèi)存中函數(shù)的入口地址

請分別寫出SEL,id,@的意思

  • SEL是"selector"的一個類型,標識一個方法的名字---就是一個方法的入口地址
  • id是一個執(zhí)行任何一個集成了Object(或者NSObject)類的對象.需要注意的是id是一個指針,所以在使用id的時候不需要添加*
  • @是OC中的指令符號

unsigned int 和 int 有什么區(qū)別.假設int長度為65535,請寫出unsigned int 與int 的取值范圍

  • int:基本整型,當字節(jié)數(shù)為2事取值范圍為-32768~32767, 當字節(jié)數(shù)為4時,取值范圍負的2的31次方到2的31次方減一
    unsigned int: 無符號基本整型,當字節(jié)數(shù)為2時取值范圍為0~65535, 當字節(jié)數(shù)為4時,取值范圍為0到2的32次方減一
Foundation對象與Core Foundation 對象有什么區(qū)別
  • Foundation對象是OC的, Core Foundation 對象是C對象
  • 數(shù)據(jù)類型之間的轉(zhuǎn)換
    -- ARC:bridge_retained(持有對象所有權(quán),F->CF),bridge_transfer(釋放對象所有權(quán)CF->F)
    -- 非ARC:__bridge
編寫一個函數(shù),實現(xiàn)遞歸刪除地址路徑下的所有文件
+ (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(@"你打印的是目錄或者不存在");
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,665評論 1 32
  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 2,068評論 0 9
  • 37.cocoa內(nèi)存管理規(guī)則 1)當你使用new,alloc或copy方法創(chuàng)建一個對象時,該對象的保留計數(shù)器值為1...
    如風家的秘密閱讀 955評論 0 4
  • 每天都是一個人在清晨醒來,刷牙洗臉開始新的生活。想去看電影就去看電影,不用因為要合誰的拍子特意提前商量。一個人生活...
    海島遇火山閱讀 328評論 3 0
  • 星空對著他的愛人 把星云織就的絲巾系上她的脖頸 她笑了 這一刻她的笑明亮如億萬顆星 照亮了宇宙流逝的古今
    劉漢皇閱讀 243評論 0 3

友情鏈接更多精彩內(nèi)容