高頻問(wèn)題:
OOM:
監(jiān)控可以用didReceiveMemoryWarning
也可以類似flex ,通過(guò)malloc_get_all_zones可以獲取所有堆區(qū)的對(duì)象,通過(guò)objc_getClass獲取對(duì)應(yīng)的對(duì)象名,通過(guò)class_getInstanceSize獲取單個(gè)對(duì)象的大小。進(jìn)行引用分析,獲取當(dāng)前內(nèi)存占用
Facebook的方案是排除法,判斷終止進(jìn)程原因,排除已知原因
騰訊的做法是OOMDetector
可以通過(guò)malloc_logger實(shí)現(xiàn)對(duì)于malloc/free的監(jiān)控,記錄內(nèi)存
AutoreleasePool與ARC的關(guān)系?
AutoreleasePool可以理解為一個(gè)對(duì)象,在ARC環(huán)境下,這個(gè)對(duì)象本身也是自動(dòng)計(jì)數(shù)的,當(dāng)這個(gè)pool的引用計(jì)數(shù)為0時(shí),就被清掉了,這是手動(dòng)聲明時(shí)候的情況,當(dāng)系統(tǒng)自動(dòng)為我們建立AutoreleasePool以及在runloop結(jié)束時(shí)釋放就是系統(tǒng)的事情了。但同時(shí)AutoreleasePool不同于一般的對(duì)象指針,它可以持有多個(gè)對(duì)象,當(dāng)pool被release的時(shí)候,其會(huì)向其持有的所有對(duì)象發(fā)送release消息,在非ARC環(huán)境下用來(lái)延長(zhǎng)對(duì)象的作用域是很有效的。我們知道ARC只是編譯器在幫我們自動(dòng)添加retain和release,而并非垃圾回收器,這樣以來(lái),就會(huì)不可避免的產(chǎn)生一些內(nèi)存問(wèn)題,
http://blog.sunnyxx.com/2014/10/15/behind-autorelease/
.a 和 .framework 的區(qū)別是什么?
.a 是單純的二進(jìn)制文件,.framework是二進(jìn)制問(wèn)價(jià)+資源文件。
其中.a 不能直接使用,需要 .h文件配合,而.framework則可以直接使用。
.framework = .a + .h + sorrceFile(資源文件)
RunLoop
所以,RunLoop 實(shí)際上就是一個(gè)對(duì)象,這個(gè)對(duì)象管理了其需要處理的事件和消息,并提供了一個(gè)入口函數(shù)來(lái)執(zhí)行上面 Event Loop 的邏輯。線程執(zhí)行了這個(gè)函數(shù)后,就會(huì)一直處于這個(gè)函數(shù)內(nèi)部 “接受消息->等待->處理” 的循環(huán)中,直到這個(gè)循環(huán)結(jié)束(比如傳入 quit 的消息),函數(shù)返回。
線程和 RunLoop 之間是一一對(duì)應(yīng)的,其關(guān)系是保存在一個(gè)全局的 Dictionary 里。線程剛創(chuàng)建時(shí)并沒(méi)有 RunLoop,如果你不主動(dòng)獲取,那它一直都不會(huì)有。RunLoop 的創(chuàng)建是發(fā)生在第一次獲取時(shí),RunLoop 的銷毀是發(fā)生在線程結(jié)束時(shí)。你只能在一個(gè)線程的內(nèi)部獲取其 RunLoop(主線程除外)
一個(gè)HTTP流程:
url - DNS查ip ,dns自己有cache,未命中再去找dns服務(wù)器 -UDP - ip -Mac地址
埋點(diǎn)系統(tǒng)設(shè)計(jì)
GCD.串行并行隊(duì)列
二叉搜索樹(shù)的判斷
string strong copy的區(qū)別
當(dāng)原字符串是NSString時(shí),由于是不可變字符串,所以,不管使用strong還是copy修飾,都是指向原來(lái)的對(duì)象,copy操作只是做了一次淺拷貝。
而當(dāng)源字符串是NSMutableString時(shí),strong只是將源字符串的引用計(jì)數(shù)加1,而copy則是對(duì)原字符串做了次深拷貝,從而生成了一個(gè)新的對(duì)象,并且copy的對(duì)象指向這個(gè)新對(duì)象。另外需要注意的是,這個(gè)copy屬性對(duì)象的類型始終是NSString,而不是NSMutableString,如果想讓拷貝過(guò)來(lái)的對(duì)象是可變的,就要使用mutableCopy。 所以,如果源字符串是NSMutableString的時(shí)候,使用strong只會(huì)增加引用計(jì)數(shù)。 但是copy會(huì)執(zhí)行一次深拷貝,會(huì)造成不必要的內(nèi)存浪費(fèi)。而如果原字符串是NSString時(shí),strong和copy效果一樣,就不會(huì)有這個(gè)問(wèn)題。
一般怎么檢查野指針,zombie對(duì)象怎么知道是野指針
http://www.itdecent.cn/p/7bb92761f2f5
消息轉(zhuǎn)發(fā)
從全局來(lái)看,消息轉(zhuǎn)發(fā)機(jī)制共分為3大步驟:
1.Method resolution 方法解析處理階段
2.Fast forwarding 快速轉(zhuǎn)發(fā)階段
3.Normal forwarding 常規(guī)轉(zhuǎn)發(fā)階段
動(dòng)態(tài)卡片vm,類似字節(jié)lua
概念上類似于阿里開(kāi)源的LuaView
分類為什么不能添加屬性
分類添加方法的原理和順序
- 最后添加分類的方法 new_method ,從整個(gè)方法的內(nèi)存從首端開(kāi)始覆蓋
- 編譯順序越靠后的分類方法的優(yōu)先級(jí)越高
所以在調(diào)用實(shí)例對(duì)象的方法時(shí),會(huì)優(yōu)先調(diào)用分類中的實(shí)例對(duì)象方法,具體的分類順序需要在 XCode 中設(shè)置分類文件的編譯順序,在 Project-BuildPhases-Compile Sources 中進(jìn)行設(shè)置
https://juejin.cn/post/6953474692363583525
https://fatofyoung.github.io/2018/06/13/OC%E5%88%86%E7%B1%BB%E5%8E%9F%E7%90%86/
uicontrol手勢(shì)沖突
https://juejin.cn/post/6908553699732226061
怎么解決單雙擊沖突
requireGestureRecognizerToFail 設(shè)置手勢(shì)的優(yōu)先級(jí),同樣,分頁(yè)控制器在左滑和系統(tǒng)左滑沖突時(shí)也可以這么解決
iOS 事件(UITouch、UIControl、UIGestureRecognizer)傳遞機(jī)制 - 簡(jiǎn)書(shū) (jianshu.com) 聊聊NSInvocation和NSMethodSignature_Deft_MKJing的博客-CSDN博客
UITableView繼承鏈?UITableView -> UIScrollView -> UIView -> UIResponder -> NSObject
UIresponder和UIcontrol的區(qū)別是啥?UIControl繼承自UIView,UIReponder是iOS用于處理觸摸事件
的基類,UIControl對(duì)其進(jìn)行了深度包裝,以target-action的模式進(jìn)行調(diào)用。觸摸事件傳遞流程是啥樣的?分為事件傳遞鏈和響應(yīng)鏈,傳遞鏈通過(guò)hittest函數(shù)和pointside遞歸的
判斷子view是否可以響應(yīng)事件,直到遞歸遍歷到最后一個(gè)view,響應(yīng)鏈則是消費(fèi)事件的過(guò)程,從子 view向其的vc,superView傳遞觸摸事件。優(yōu)先級(jí)的話手勢(shì)識(shí)別高于view的觸摸事件,系統(tǒng)的 uicontrol高于手勢(shì),自定義的低于手勢(shì)。如何擴(kuò)大UIbutton點(diǎn)擊范圍?兩種方法,重寫pointinside和hittest
如何擴(kuò)大手勢(shì)點(diǎn)擊范圍?或者擴(kuò)大一個(gè)小圖片的點(diǎn)擊范圍?圖片話調(diào)節(jié)內(nèi)邊距即可
獲取當(dāng)前viwe的vc方法?方法一:通過(guò)響應(yīng)鏈機(jī)制,尋找view的下一級(jí)響應(yīng)者,因?yàn)関iew的下一級(jí)
響應(yīng)鏈?zhǔn)瞧鋠c 方法二:通過(guò)KeyWindows獲取對(duì)應(yīng)的rootVC一直朝下遍歷,獲取presetedVC知
道最后一個(gè)VC消息轉(zhuǎn)發(fā)階段流程是什么樣的?具體有哪些方法?resolveMethod -> forwardingTarget -> methodSinature->forwardInvocation 第三步會(huì)獲取對(duì)應(yīng)的方法簽名,如果能獲取到可以在第四步 直接將這個(gè)方法以NSInvocation形式轉(zhuǎn)發(fā)給其他對(duì)象處理
NSInvocation和NSMethodSignature的區(qū)別是啥?NSMethodSignature是方法編碼過(guò)后的簽名,例如 NSString的類方法isEqualToString: 的方法簽名為B24@0:8@16,如下所示 @encode(BOOL) (B) 返回值 @encode(id) (@) 默認(rèn)第一個(gè)參數(shù) self
@encode(SEL) (:)默認(rèn)第二個(gè)參數(shù) _cmd
@encode(NSString ) (@) 實(shí)際上的第一個(gè)參數(shù)NSString* iOS中的method即由SEL、IMP和簽名組成,SEL是method檢索的方式,可以通過(guò)SEL在method list中找到對(duì)應(yīng)的方法,IMP則是函數(shù)指針指向方法的本身,簽名包括了函數(shù)頭中的各種信息。 NSInvocation則是消息在OC中對(duì)象的形式存在,是一種更高級(jí)的轉(zhuǎn)發(fā)機(jī)制可以通過(guò)添加target、 簽名、參數(shù)這些強(qiáng)行執(zhí)行方法消息轉(zhuǎn)發(fā)可以做什么?怎么做的?熱更新、多重代理和多繼承
Runtim相關(guān)函數(shù)有哪些?賊多,建議查 Objective-C Runtime | Apple Developer Documentation
線程鎖有哪些?iOS多線程安全-13種線程鎖%"#$ (juejin.cn)
semaphore和nslock有啥區(qū)別?優(yōu)缺點(diǎn)是啥?
怎么通過(guò)gcd實(shí)現(xiàn)讀寫鎖?Dispatch_barrity_async
循環(huán)引用是啥?有哪些會(huì)造成?iOS解除Block循環(huán)引用,你只知道_weak就out啦知更鳥(niǎo)
CoolLee的博客-CSDN博客
block中的強(qiáng)引用是對(duì)self指針的強(qiáng)引用所以簡(jiǎn)單使用weak/strong就可以解決循環(huán)引用問(wèn)題,但
是NSTimer中的循環(huán)引用是對(duì)整個(gè)對(duì)象的強(qiáng)引用NStimer循環(huán)引用是怎么造成?怎么解決?NSTimer會(huì)強(qiáng)引用整個(gè)對(duì)象,對(duì)象持有Timer就會(huì)引起強(qiáng)
引用。方法1:及時(shí)結(jié)束Timer運(yùn)行,使用invalidata結(jié)束運(yùn)行并置整個(gè)Timer為nil 方法2:target不指向自身,指向一個(gè)其他對(duì)象 方法3:使用NSProxy替代self,消息轉(zhuǎn)發(fā)階段轉(zhuǎn)發(fā)消息回原類NSProxy是啥?有啥用?NSProxy是一個(gè)等同于NSObject的基類,實(shí)現(xiàn)了<NSObject>的協(xié)議,自身沒(méi) 有任何實(shí)現(xiàn),主要用于轉(zhuǎn)發(fā)消息的基類,可以繼承自這個(gè)基類,實(shí)現(xiàn)消息轉(zhuǎn)發(fā)中的方法可以將消 息轉(zhuǎn)發(fā)給其他對(duì)象??梢杂糜趯?shí)現(xiàn)oc中本不支持的多繼承,解決NSTimer中的循環(huán)引用。
NSProxy和NSObject的區(qū)別?
-
雖然都需要實(shí)現(xiàn)了<NSObject>協(xié)議,主要差別在消息轉(zhuǎn)發(fā)流程中, NSObject會(huì)走完完整的消息轉(zhuǎn)發(fā)機(jī)制,NSProxy直接回調(diào)-methodSignatureForSelector:/- forwardInvocation:,消息轉(zhuǎn)發(fā)過(guò)程比class NSObject要簡(jiǎn)單得多,NSProxy會(huì)將自省相關(guān)的selector
直接forward到-forwardInvocation:回調(diào)中,例如 - (BOOL)isKindOfClass:(Class)aClass;- (BOOL)isMemberOfClass:(Class)aClass;
- (BOOL)conformsToProtocol:(Protocol *)aProtocol; - (BOOL)respondsToSelector:(SEL)aSelector;
_cmd是啥?表示這個(gè)方法本身
block如何獲取外部變量?
+load方法和initialize方法加載順序?
IOSkeychain
Socket 場(chǎng)鏈接 內(nèi)購(gòu) gcd
如何捕獲**crash **
http://www.itdecent.cn/p/5fcf7bb7955f
動(dòng)態(tài)庫(kù)和靜態(tài)庫(kù)
block 為什么用copy修飾 Block實(shí)現(xiàn)原理
https://juejin.cn/post/6844904040954871815
setObject:forKey:和setValue:forKey:的
kvc 和kvo
kvc set:簡(jiǎn)單來(lái)說(shuō)就是如果沒(méi)有找到Set<Key>方法的話,會(huì)按照_key,_iskey,key,iskey的順序搜索成員并進(jìn)行賦值操作。
當(dāng)你觀察一個(gè)對(duì)象時(shí),一個(gè)新的類會(huì)動(dòng)態(tài)被創(chuàng)建。這個(gè)類繼承自該對(duì)象的原本的類,并重寫了被觀察屬性的 setter 方法。自然,重寫的 setter 方***負(fù)責(zé)在調(diào)用原 setter方法之前和之后,通知所有觀察對(duì)象值的更改。最后把這個(gè)對(duì)象的 isa 指針 ( isa 指針告訴 Runtime 系統(tǒng)這個(gè)對(duì)象的類是什么 ) 指向這個(gè)新創(chuàng)建的子類,對(duì)象就神奇的變成了新創(chuàng)建的子類的實(shí)例。
原來(lái),這個(gè)中間類,繼承自原本的那個(gè)類。不僅如此,Apple 還重寫了 -class 方法,企圖欺騙我們這個(gè)類沒(méi)有變,就是原本那個(gè)類。更具體的信息,去跑一下 Mike Ash 的那篇文章里的代碼就能明白,這里就不再重復(fù)。
https://juejin.cn/post/6844903602545229831
介紹下oc
RunTime:
首先 OC 是 C 語(yǔ)言的超集,因?yàn)?runtime 這個(gè)庫(kù)使得C語(yǔ)言有了面向?qū)ο蟮哪芰Γ?br> OC 對(duì)象可以用C語(yǔ)言中的結(jié)構(gòu)體表示,而方法可以用C函數(shù)來(lái)實(shí)現(xiàn),這些結(jié)構(gòu)體和函數(shù)被 runtime 函數(shù)封裝后,我們就可以在程序運(yùn)行時(shí)創(chuàng)建,檢查,修改類、對(duì)象和它們的方法了。
OC 是一門動(dòng)態(tài)語(yǔ)言,它將很多靜態(tài)語(yǔ)言在編譯和鏈接時(shí)期做的事放到了運(yùn)行時(shí)來(lái)處理。
這種特性意味著Objective-C不僅需要一個(gè)編譯器,還需要一個(gè)運(yùn)行時(shí)系統(tǒng)來(lái)執(zhí)行編譯的代碼。這個(gè)運(yùn)行時(shí)系統(tǒng)即Objc Runtime。Objc Runtime基本上是用C和匯編寫的。
http://www.itdecent.cn/p/d7818dcb21de
靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù):
https://juejin.cn/post/7040003550977458207
編譯和鏈接:
http://www.360doc.com/content/17/0111/22/32626470_621879084.shtml
集合類型 copy 操作和 mutableCopy 操作
一個(gè)類遵循 NSCopying, NSMutableCopying 協(xié)議并且實(shí)現(xiàn)相對(duì)應(yīng)的初始化方法后,這個(gè)類就具有對(duì)象拷貝的能力。如果你自定義類沒(méi)有遵守協(xié)議直接調(diào)用 copy / mutableCopy 程序會(huì)奔潰。拷貝協(xié)議的具體使用我這里不做擴(kuò)展感興趣的可以自行 Google 一下。有一種觀點(diǎn):copy 操作就是淺復(fù)制,mutableCopy 就是深復(fù)制,這是一個(gè)非常錯(cuò)誤的理解。以下是我的一些總結(jié):
- 可變的集合對(duì)象 + copy 得到一個(gè)新的對(duì)象(新對(duì)象不可變) 深復(fù)制
- 可變的集合對(duì)象 + mutablecopy 得到一個(gè)新的對(duì)象(新對(duì)象可變) 深復(fù)制
- 不可變集合對(duì)象 + copy 沒(méi)有得到新的對(duì)象(地址的引用) 淺復(fù)制
- 不可變集合對(duì)象 + mutablecopy 得到一個(gè)新的對(duì)象(新對(duì)象可變) 深復(fù)制
怎么去動(dòng)態(tài)關(guān)聯(lián)一個(gè)weak屬性
持有一個(gè)strong的容器,讓其持有該weak屬性,獲取關(guān)聯(lián)對(duì)象時(shí)獲取其屬性即可
首先,給category屬性是需要使用runtime中的關(guān)聯(lián)來(lái)實(shí)現(xiàn)set和get方法,但runtime沒(méi)有提供weak ,雖然runtime沒(méi)有開(kāi)放weak解決方案,但objc對(duì)象是可以實(shí)現(xiàn)weak的,所以讓需要被修飾的對(duì)象去持有一個(gè)strong對(duì)象,然后當(dāng)被修飾的對(duì)象釋放的時(shí)候,持有的對(duì)象也會(huì)被釋放,那么我們就可以捕捉到釋放的事件,進(jìn)而使用OBJC_ASSOCIATION_ASSIGN來(lái)實(shí)現(xiàn)弱引用
對(duì)象的內(nèi)存布局
struct objc_class {
Class isa;
Class super_class;
const charchar *name;
long version;
long info;
long instance_size;
struct objc_ivar_list *ivars;
struct objc_method_list **methodLists;
struct objc_cache *cache;
struct objc_protocol_list *protocols;
} OBJC2_UNAVAILABLE;
二叉樹(shù)的層序遍歷
消息轉(zhuǎn)發(fā)的優(yōu)化
在 2020 年中,Apple 針對(duì) Objective-C 做了三項(xiàng)優(yōu)化
- 類數(shù)據(jù)結(jié)構(gòu)變化:節(jié)約了系統(tǒng)更多的內(nèi)存。
- 相對(duì)方法地址:節(jié)約了內(nèi)存,并且提高了性能。
- Tagged Pointer 格式的變化:提高了 msgSend 性能
Self 和 this 的底層實(shí)現(xiàn),是編譯期還是運(yùn)行期做的。答案是編譯期間
this指針本質(zhì): 當(dāng)一個(gè)對(duì)象調(diào)用某成員函數(shù)時(shí)編譯器會(huì)隱式傳入一個(gè)參數(shù), 這個(gè)參數(shù)就是this指針
this指針中存放的就是這個(gè)對(duì)象的首地址。
其實(shí)編譯器在生成程序時(shí)加入了獲取對(duì)象首地址的相關(guān)代碼,并把獲取的首地址存放在了寄存器ECX中(VC++編譯器是放在ECX中,其它編譯器有可能不同)。
成員函數(shù)的其它參數(shù)正常都是存放在棧中,而this指針參數(shù)則是存放在寄存器中。
我們都知道:self 是類的隱藏參數(shù),指向當(dāng)前調(diào)用方法的這個(gè)類的實(shí)例。那 super 呢?
很多人會(huì)想當(dāng)然的認(rèn)為“ super 和 self 類似,應(yīng)該是指向父類的指針吧!”。這是很普遍的一個(gè)誤區(qū)。其實(shí) super 是一個(gè) Magic Keyword, 它本質(zhì)是一個(gè)編譯器標(biāo)示符,和 self 是指向的同一個(gè)消息接受者!他們兩個(gè)的不同點(diǎn)在于:super 會(huì)告訴編譯器,調(diào)用 class 這個(gè)方法時(shí),要去父類的方法,而不是本類里的。
上面的例子不管調(diào)用[self class]還是[super class],接受消息的對(duì)象都是當(dāng)前 Son *xxx 這個(gè)對(duì)象。
當(dāng)使用 self 調(diào)用方法時(shí),會(huì)從當(dāng)前類的方法列表中開(kāi)始找,如果沒(méi)有,就從父類中再找;而當(dāng)使用 super 時(shí),則從父類的方法列表中開(kāi)始找。然后調(diào)用父類的這個(gè)方法。
**OC Property **
https://juejin.cn/post/6844903735651647502
20. 一個(gè)objc對(duì)象的isa的指針指向什么?有什么作用?
isa 顧名思義 is a 表示對(duì)象所屬的類。
isa 指向他的類對(duì)象,從而可以找到對(duì)象上的方法。
同一個(gè)類的不同對(duì)象,他們的 isa 指針是一樣的。
算法36進(jìn)制加法
https://blog.csdn.net/lyl194458/article/details/100192501
Unicode 和 UTF-8 有什么區(qū)別?
簡(jiǎn)單來(lái)說(shuō): Unicode 是「字符集」 UTF-8 是「編碼規(guī)則」 其中: 字符集:為每一個(gè)「
為什么說(shuō)OC是動(dòng)態(tài)語(yǔ)言
為什么說(shuō)OC是動(dòng)態(tài)語(yǔ)言呢?我們可以從下面幾個(gè)方面來(lái)說(shuō)明:
1.動(dòng)態(tài)類型:即運(yùn)行時(shí)再?zèng)Q定對(duì)象的類型,簡(jiǎn)單說(shuō)就是id類型,任何對(duì)象都可以被指定為Id類型,只有在運(yùn)行時(shí)才能決定是什么類型。像內(nèi)置的明確的基本數(shù)據(jù)類型都屬于靜態(tài)類型(int,NSString等)。靜態(tài)類型在編譯的時(shí)候就能被識(shí)別出來(lái),所以當(dāng)程序發(fā)生了類型不對(duì)應(yīng),編譯器就會(huì)發(fā)出警告。而動(dòng)態(tài)類型在編譯器編譯的時(shí)候是不能被識(shí)別的,要等到運(yùn)行時(shí),即程序運(yùn)行的時(shí)候才會(huì)根據(jù)語(yǔ)境來(lái)識(shí)別。所以這里就有兩個(gè)概念要區(qū)分:編譯時(shí)跟運(yùn)行時(shí)
2.動(dòng)態(tài)綁定:基于動(dòng)態(tài)類型,在某個(gè)實(shí)例對(duì)象被確定之后其數(shù)據(jù)類型便被確定了,該對(duì)象的屬性和響應(yīng)的消息也被完全確定,這就是動(dòng)態(tài)綁定。比如我們向一個(gè)NSObject對(duì)象發(fā)送-respondsToSelector:或者-instancesRespondToSelector:等來(lái)確定對(duì)象是否可以對(duì)某個(gè)SEL做出響應(yīng),而在OC消息轉(zhuǎn)發(fā)機(jī)制被觸發(fā)之前,對(duì)應(yīng)類的+resolveClassMethod:和+resolveInstanceMethod:將會(huì)被調(diào)用,在此時(shí)有機(jī)會(huì)動(dòng)態(tài)的向類或者實(shí)例添加新的方法,也即類的實(shí)現(xiàn)是可以動(dòng)態(tài)綁定的;isKindOfClass也是一樣的道理。
3.動(dòng)態(tài)加載:所謂動(dòng)態(tài)加載就是我們做開(kāi)發(fā)的時(shí)候icon圖片在retina設(shè)備上要多添加一個(gè)@2x的圖片,當(dāng)設(shè)備更換的時(shí)候圖片也會(huì)自動(dòng)的替換
4.多態(tài):運(yùn)行時(shí)機(jī)制是多態(tài)的基礎(chǔ)。多態(tài)主要是將數(shù)據(jù)類型的確定由編譯時(shí)推遲到了運(yùn)行時(shí)。不同對(duì)象以自己的方式響應(yīng)相同消息的能力叫做多態(tài)。例如所有的動(dòng)物都有同一個(gè)方法eat,但每個(gè)動(dòng)物的eat方式不同,也就是不同的對(duì)象以自己的方式響應(yīng)了相同的信息(響應(yīng)了eat這個(gè)選擇器)。
Category的本質(zhì)是一個(gè)_category_t結(jié)構(gòu)體,其結(jié)構(gòu)如下:
1、分類中只能添加“方法”,不能增加成員變量。如果分類中聲明了一個(gè)屬性,那么分類只會(huì)生成這個(gè)屬性的set、get方法聲明,也就是不會(huì)有實(shí)現(xiàn)。 2、分類中可以/只能訪問(wèn)原有類中.h中的屬性。如果想要訪問(wèn)本類中的私有變量,分類和子類一樣,只能通過(guò)方法來(lái)訪問(wèn)。 3、在本類和分類有相同的方法時(shí),優(yōu)先調(diào)用分類的方法再調(diào)用本類的方法。 4、如果多個(gè)分類中都有和原有類中同名的方法,那么調(diào)用該方法的時(shí)候執(zhí)行誰(shuí)由編譯器決定;編譯器會(huì)執(zhí)行最后一個(gè)參與編譯的分類中的方法。
Categroy的加載過(guò)程
在編譯時(shí)只是一個(gè)包含類名,類指針,方法列表,屬性列表,協(xié)議列表的_category_t結(jié)構(gòu)體;
在運(yùn)行時(shí)通過(guò)runtime加載分類數(shù)據(jù),把分類的方法、屬性、協(xié)議數(shù)據(jù)合并到一個(gè)大數(shù)組中,后參與編譯的分類會(huì)在數(shù)組的前面(i–倒數(shù)遍歷數(shù)組添加的)(這也說(shuō)明了分類中相同的方法后參與編譯的分類會(huì)被調(diào)用);
合并后的分類數(shù)據(jù)會(huì)插入到原來(lái)類數(shù)據(jù)的前面(相同的方法,分類會(huì)優(yōu)先于原來(lái)調(diào)用)。
編譯順序是可以手動(dòng)設(shè)置的:TARGETS->BuildPhases->Complle Sources。(自己可以驗(yàn)證一下,這里不再贅述)
Category 和Class Extension 的區(qū)別
Class Extension 是在編譯后合并到類中。
Category 是runtime 運(yùn)行時(shí) 合并到類中。
weak 實(shí)現(xiàn)原理的概括
Runtime維護(hù)了一個(gè)weak表,用于存儲(chǔ)指向某個(gè)對(duì)象的所有weak指針。weak表其實(shí)是一個(gè)hash(哈希)表,Key是所指對(duì)象的地址,Value是weak指針的地址(這個(gè)地址的值是所指對(duì)象指針的地址)數(shù)組。
weak 的實(shí)現(xiàn)原理可以概括一下三步:
1、初始化時(shí):runtime會(huì)調(diào)用objc_initWeak函數(shù),初始化一個(gè)新的weak指針指向?qū)ο蟮牡刂贰?br>
2、添加引用時(shí):objc_initWeak函數(shù)會(huì)調(diào)用 objc_storeWeak() 函數(shù), objc_storeWeak() 的作用是更新指針指向,創(chuàng)建對(duì)應(yīng)的弱引用表。
3、釋放時(shí),調(diào)用clearDeallocating函數(shù)。clearDeallocating函數(shù)首先根據(jù)對(duì)象地址獲取所有weak指針地址的數(shù)組,然后遍歷這個(gè)數(shù)組把其中的數(shù)據(jù)設(shè)為nil,最后把這個(gè)entry從weak表中刪除,最后清理對(duì)象的記錄。
騰訊1
Category 在什么時(shí)候加載、為什么不能動(dòng)態(tài)添加屬性 關(guān)聯(lián)對(duì)象關(guān)聯(lián)的應(yīng)該是成員變量
https://tech.meituan.com/2015/03/03/diveintocategory.html
Oc的js通信的幾種方式
為什小游戲不用阿里的GCanvas
premin的流程
propoety的本質(zhì)
Weak的內(nèi)部實(shí)現(xiàn)。
http://www.itdecent.cn/p/13c4fb1cedea
算法leetcode 62 不同路徑
Bilibili1
Category的實(shí)現(xiàn)原理、關(guān)聯(lián)對(duì)象的原理、加載的順序和流程;
UIimageView加載一張圖片的過(guò)程、大圖片怎么優(yōu)化
埋點(diǎn)框架
UIview和Calayer的關(guān)系
流媒體常用的協(xié)議
死鎖的產(chǎn)生和常見(jiàn)場(chǎng)景
GCD和NS Operation
Bili2
基本問(wèn)的都是項(xiàng)目、、沒(méi)啥好提的
字節(jié)2
iOS xcodebuild后經(jīng)歷了哪些過(guò)程,一個(gè)oc類怎么加載的
Category的方法列表怎么加到當(dāng)前class的,為什么最后一個(gè)方法的優(yōu)先級(jí)最高
dispath barrier是什么,用來(lái)干嘛的
設(shè)計(jì)一個(gè)線程安全的讀寫 讀讀并發(fā),讀寫互斥 寫寫互斥
UItableview cell復(fù)用的原理,怎么去設(shè)計(jì)一套cell復(fù)用
https://www.cnblogs.com/zhangyang17/p/3601512.html
UIView的渲染過(guò)程、渲染管線怎么工作
oc 編譯過(guò)程 -objc - all_load的參數(shù)作用
字節(jié)3
描述下目前app的架構(gòu),有什么優(yōu)化方向,組件化的后續(xù)發(fā)展、facebook和google怎么設(shè)計(jì)的架構(gòu)和組件化
線程通信原理:
https://juejin.cn/post/6844904152082939917
runloop通信:
https://segmentfault.com/a/1190000021994646
iOS進(jìn)程和進(jìn)程程的通信原理,wkwebview和主進(jìn)程通信原理,runloop通信的原理
消息轉(zhuǎn)發(fā)、IOS系統(tǒng)內(nèi)部對(duì)消息轉(zhuǎn)發(fā)做了什么優(yōu)化
Metal 和 opengl的區(qū)別,做了哪些優(yōu)化
Swift 5的新特性,對(duì)應(yīng)async wait原理
怎么做啟動(dòng)優(yōu)化,怎么設(shè)計(jì)啟動(dòng)框架,啟動(dòng)線程調(diào)度和依賴怎么管理,主線程可以依賴異步線程的任務(wù)么
AOP面向切片編程在oc設(shè)計(jì)里那個(gè)場(chǎng)景用到了
算法題
鏈表交錯(cuò)重排
招銀1
UIview和calayer
Xcode編譯一個(gè)app經(jīng)過(guò)的過(guò)程
攜程1面
NSOperation 線程依賴的原理 如果沒(méi)有這個(gè),自己怎么實(shí)現(xiàn)一套線程依賴?(我回答的是信號(hào)量)
Weak實(shí)現(xiàn)的原理kv是什么
啟動(dòng)優(yōu)化做了哪些事情
離屏渲染為什么會(huì)導(dǎo)致性能消耗
https://juejin.cn/post/6847902222567604231
怎么異步渲染一個(gè)imageView、imageView的性能優(yōu)化
http://www.itdecent.cn/p/7d8a82115060
http://www.itdecent.cn/p/43ac91be0cf4
異步渲染主要做什么
為什么UIview層級(jí)過(guò)多會(huì)影響性能
描述下iOS里面的鎖,講一下用到鎖的場(chǎng)景
OOM:
監(jiān)控可以用didReceiveMemoryWarning
也可以類似flex ,通過(guò)malloc_get_all_zones可以獲取所有堆區(qū)的對(duì)象,通過(guò)objc_getClass獲取對(duì)應(yīng)的對(duì)象名,通過(guò)class_getInstanceSize獲取單個(gè)對(duì)象的大小。進(jìn)行引用分析,獲取當(dāng)前內(nèi)存占用
Facebook的方案是排除法,判斷終止進(jìn)程原因,排除已知原因
騰訊的做法是OOMDetector
可以通過(guò)malloc_logger實(shí)現(xiàn)對(duì)于malloc/free的監(jiān)控,記錄內(nèi)存
AutoreleasePool與ARC的關(guān)系?
AutoreleasePool可以理解為一個(gè)對(duì)象,在ARC環(huán)境下,這個(gè)對(duì)象本身也是自動(dòng)計(jì)數(shù)的,當(dāng)這個(gè)pool的引用計(jì)數(shù)為0時(shí),就被清掉了,這是手動(dòng)聲明時(shí)候的情況,當(dāng)系統(tǒng)自動(dòng)為我們建立AutoreleasePool以及在runloop結(jié)束時(shí)釋放就是系統(tǒng)的事情了。但同時(shí)AutoreleasePool不同于一般的對(duì)象指針,它可以持有多個(gè)對(duì)象,當(dāng)pool被release的時(shí)候,其會(huì)向其持有的所有對(duì)象發(fā)送release消息,在非ARC環(huán)境下用來(lái)延長(zhǎng)對(duì)象的作用域是很有效的。我們知道ARC只是編譯器在幫我們自動(dòng)添加retain和release,而并非垃圾回收器,這樣以來(lái),就會(huì)不可避免的產(chǎn)生一些內(nèi)存問(wèn)題,
http://blog.sunnyxx.com/2014/10/15/behind-autorelease/
.a 和 .framework 的區(qū)別是什么?
.a 是單純的二進(jìn)制文件,.framework是二進(jìn)制問(wèn)價(jià)+資源文件。
其中.a 不能直接使用,需要 .h文件配合,而.framework則可以直接使用。
.framework = .a + .h + sorrceFile(資源文件)
RunLoop
所以,RunLoop 實(shí)際上就是一個(gè)對(duì)象,這個(gè)對(duì)象管理了其需要處理的事件和消息,并提供了一個(gè)入口函數(shù)來(lái)執(zhí)行上面 Event Loop 的邏輯。線程執(zhí)行了這個(gè)函數(shù)后,就會(huì)一直處于這個(gè)函數(shù)內(nèi)部 “接受消息->等待->處理” 的循環(huán)中,直到這個(gè)循環(huán)結(jié)束(比如傳入 quit 的消息),函數(shù)返回。
線程和 RunLoop 之間是一一對(duì)應(yīng)的,其關(guān)系是保存在一個(gè)全局的 Dictionary 里。線程剛創(chuàng)建時(shí)并沒(méi)有 RunLoop,如果你不主動(dòng)獲取,那它一直都不會(huì)有。RunLoop 的創(chuàng)建是發(fā)生在第一次獲取時(shí),RunLoop 的銷毀是發(fā)生在線程結(jié)束時(shí)。你只能在一個(gè)線程的內(nèi)部獲取其 RunLoop(主線程除外)
一個(gè)HTTP流程:
url - DNS查ip ,dns自己有cache,未命中再去找dns服務(wù)器 -UDP - ip -Mac地址
埋點(diǎn)系統(tǒng)設(shè)計(jì)
GCD.串行并行隊(duì)列
二叉搜索樹(shù)的判斷
string strong copy的區(qū)別
當(dāng)原字符串是NSString時(shí),由于是不可變字符串,所以,不管使用strong還是copy修飾,都是指向原來(lái)的對(duì)象,copy操作只是做了一次淺拷貝。
而當(dāng)源字符串是NSMutableString時(shí),strong只是將源字符串的引用計(jì)數(shù)加1,而copy則是對(duì)原字符串做了次深拷貝,從而生成了一個(gè)新的對(duì)象,并且copy的對(duì)象指向這個(gè)新對(duì)象。另外需要注意的是,這個(gè)copy屬性對(duì)象的類型始終是NSString,而不是NSMutableString,如果想讓拷貝過(guò)來(lái)的對(duì)象是可變的,就要使用mutableCopy。 所以,如果源字符串是NSMutableString的時(shí)候,使用strong只會(huì)增加引用計(jì)數(shù)。 但是copy會(huì)執(zhí)行一次深拷貝,會(huì)造成不必要的內(nèi)存浪費(fèi)。而如果原字符串是NSString時(shí),strong和copy效果一樣,就不會(huì)有這個(gè)問(wèn)題。
一般怎么檢查野指針,zombie對(duì)象怎么知道是野指針
http://www.itdecent.cn/p/7bb92761f2f5
消息轉(zhuǎn)發(fā)
從全局來(lái)看,消息轉(zhuǎn)發(fā)機(jī)制共分為3大步驟:
1.Method resolution 方法解析處理階段
2.Fast forwarding 快速轉(zhuǎn)發(fā)階段
3.Normal forwarding 常規(guī)轉(zhuǎn)發(fā)階段
動(dòng)態(tài)卡片vm,類似字節(jié)lua
概念上類似于阿里開(kāi)源的LuaView
分類為什么不能添加屬性
分類添加方法的原理和順序
- 最后添加分類的方法 new_method ,從整個(gè)方法的內(nèi)存從首端開(kāi)始覆蓋
- 編譯順序越靠后的分類方法的優(yōu)先級(jí)越高
所以在調(diào)用實(shí)例對(duì)象的方法時(shí),會(huì)優(yōu)先調(diào)用分類中的實(shí)例對(duì)象方法,具體的分類順序需要在 XCode 中設(shè)置分類文件的編譯順序,在 Project-BuildPhases-Compile Sources 中進(jìn)行設(shè)置
https://juejin.cn/post/6953474692363583525
https://fatofyoung.github.io/2018/06/13/OC%E5%88%86%E7%B1%BB%E5%8E%9F%E7%90%86/
uicontrol手勢(shì)沖突
https://juejin.cn/post/6908553699732226061
怎么解決單雙擊沖突
requireGestureRecognizerToFail 設(shè)置手勢(shì)的優(yōu)先級(jí),同樣,分頁(yè)控制器在左滑和系統(tǒng)左滑沖突時(shí)也可以這么解決
iOS 事件(UITouch、UIControl、UIGestureRecognizer)傳遞機(jī)制 - 簡(jiǎn)書(shū) (jianshu.com) 聊聊NSInvocation和NSMethodSignature_Deft_MKJing的博客-CSDN博客
UITableView繼承鏈?UITableView -> UIScrollView -> UIView -> UIResponder -> NSObject
UIresponder和UIcontrol的區(qū)別是啥?UIControl繼承自UIView,UIReponder是iOS用于處理觸摸事件
的基類,UIControl對(duì)其進(jìn)行了深度包裝,以target-action的模式進(jìn)行調(diào)用。觸摸事件傳遞流程是啥樣的?分為事件傳遞鏈和響應(yīng)鏈,傳遞鏈通過(guò)hittest函數(shù)和pointside遞歸的
判斷子view是否可以響應(yīng)事件,直到遞歸遍歷到最后一個(gè)view,響應(yīng)鏈則是消費(fèi)事件的過(guò)程,從子 view向其的vc,superView傳遞觸摸事件。優(yōu)先級(jí)的話手勢(shì)識(shí)別高于view的觸摸事件,系統(tǒng)的 uicontrol高于手勢(shì),自定義的低于手勢(shì)。如何擴(kuò)大UIbutton點(diǎn)擊范圍?兩種方法,重寫pointinside和hittest
如何擴(kuò)大手勢(shì)點(diǎn)擊范圍?或者擴(kuò)大一個(gè)小圖片的點(diǎn)擊范圍?圖片話調(diào)節(jié)內(nèi)邊距即可
獲取當(dāng)前viwe的vc方法?方法一:通過(guò)響應(yīng)鏈機(jī)制,尋找view的下一級(jí)響應(yīng)者,因?yàn)関iew的下一級(jí)
響應(yīng)鏈?zhǔn)瞧鋠c 方法二:通過(guò)KeyWindows獲取對(duì)應(yīng)的rootVC一直朝下遍歷,獲取presetedVC知
道最后一個(gè)VC消息轉(zhuǎn)發(fā)階段流程是什么樣的?具體有哪些方法?resolveMethod -> forwardingTarget -> methodSinature->forwardInvocation 第三步會(huì)獲取對(duì)應(yīng)的方法簽名,如果能獲取到可以在第四步 直接將這個(gè)方法以NSInvocation形式轉(zhuǎn)發(fā)給其他對(duì)象處理
NSInvocation和NSMethodSignature的區(qū)別是啥?NSMethodSignature是方法編碼過(guò)后的簽名,例如 NSString的類方法isEqualToString: 的方法簽名為B24@0:8@16,如下所示 @encode(BOOL) (B) 返回值 @encode(id) (@) 默認(rèn)第一個(gè)參數(shù) self
@encode(SEL) (:)默認(rèn)第二個(gè)參數(shù) _cmd
@encode(NSString ) (@) 實(shí)際上的第一個(gè)參數(shù)NSString* iOS中的method即由SEL、IMP和簽名組成,SEL是method檢索的方式,可以通過(guò)SEL在method list中找到對(duì)應(yīng)的方法,IMP則是函數(shù)指針指向方法的本身,簽名包括了函數(shù)頭中的各種信息。 NSInvocation則是消息在OC中對(duì)象的形式存在,是一種更高級(jí)的轉(zhuǎn)發(fā)機(jī)制可以通過(guò)添加target、 簽名、參數(shù)這些強(qiáng)行執(zhí)行方法消息轉(zhuǎn)發(fā)可以做什么?怎么做的?熱更新、多重代理和多繼承
Runtim相關(guān)函數(shù)有哪些?賊多,建議查 Objective-C Runtime | Apple Developer Documentation
線程鎖有哪些?iOS多線程安全-13種線程鎖%"#$ (juejin.cn)
semaphore和nslock有啥區(qū)別?優(yōu)缺點(diǎn)是啥?
怎么通過(guò)gcd實(shí)現(xiàn)讀寫鎖?Dispatch_barrity_async
循環(huán)引用是啥?有哪些會(huì)造成?iOS解除Block循環(huán)引用,你只知道_weak就out啦知更鳥(niǎo)
CoolLee的博客-CSDN博客
block中的強(qiáng)引用是對(duì)self指針的強(qiáng)引用所以簡(jiǎn)單使用weak/strong就可以解決循環(huán)引用問(wèn)題,但
是NSTimer中的循環(huán)引用是對(duì)整個(gè)對(duì)象的強(qiáng)引用NStimer循環(huán)引用是怎么造成?怎么解決?NSTimer會(huì)強(qiáng)引用整個(gè)對(duì)象,對(duì)象持有Timer就會(huì)引起強(qiáng)
引用。方法1:及時(shí)結(jié)束Timer運(yùn)行,使用invalidata結(jié)束運(yùn)行并置整個(gè)Timer為nil 方法2:target不指向自身,指向一個(gè)其他對(duì)象 方法3:使用NSProxy替代self,消息轉(zhuǎn)發(fā)階段轉(zhuǎn)發(fā)消息回原類NSProxy是啥?有啥用?NSProxy是一個(gè)等同于NSObject的基類,實(shí)現(xiàn)了<NSObject>的協(xié)議,自身沒(méi) 有任何實(shí)現(xiàn),主要用于轉(zhuǎn)發(fā)消息的基類,可以繼承自這個(gè)基類,實(shí)現(xiàn)消息轉(zhuǎn)發(fā)中的方法可以將消 息轉(zhuǎn)發(fā)給其他對(duì)象??梢杂糜趯?shí)現(xiàn)oc中本不支持的多繼承,解決NSTimer中的循環(huán)引用。
NSProxy和NSObject的區(qū)別?
-
雖然都需要實(shí)現(xiàn)了<NSObject>協(xié)議,主要差別在消息轉(zhuǎn)發(fā)流程中, NSObject會(huì)走完完整的消息轉(zhuǎn)發(fā)機(jī)制,NSProxy直接回調(diào)-methodSignatureForSelector:/- forwardInvocation:,消息轉(zhuǎn)發(fā)過(guò)程比class NSObject要簡(jiǎn)單得多,NSProxy會(huì)將自省相關(guān)的selector
直接forward到-forwardInvocation:回調(diào)中,例如 - (BOOL)isKindOfClass:(Class)aClass;- (BOOL)isMemberOfClass:(Class)aClass;
- (BOOL)conformsToProtocol:(Protocol *)aProtocol; - (BOOL)respondsToSelector:(SEL)aSelector;
_cmd是啥?表示這個(gè)方法本身
block如何獲取外部變量?
+load方法和initialize方法加載順序?
IOSkeychain
Socket 場(chǎng)鏈接 內(nèi)購(gòu) gcd
如何捕獲**crash **
http://www.itdecent.cn/p/5fcf7bb7955f
動(dòng)態(tài)庫(kù)和靜態(tài)庫(kù)
block 為什么用copy修飾 Block實(shí)現(xiàn)原理
https://juejin.cn/post/6844904040954871815
setObject:forKey:和setValue:forKey:的
kvc 和kvo
kvc set:簡(jiǎn)單來(lái)說(shuō)就是如果沒(méi)有找到Set<Key>方法的話,會(huì)按照_key,_iskey,key,iskey的順序搜索成員并進(jìn)行賦值操作。
當(dāng)你觀察一個(gè)對(duì)象時(shí),一個(gè)新的類會(huì)動(dòng)態(tài)被創(chuàng)建。這個(gè)類繼承自該對(duì)象的原本的類,并重寫了被觀察屬性的 setter 方法。自然,重寫的 setter 方***負(fù)責(zé)在調(diào)用原 setter方法之前和之后,通知所有觀察對(duì)象值的更改。最后把這個(gè)對(duì)象的 isa 指針 ( isa 指針告訴 Runtime 系統(tǒng)這個(gè)對(duì)象的類是什么 ) 指向這個(gè)新創(chuàng)建的子類,對(duì)象就神奇的變成了新創(chuàng)建的子類的實(shí)例。
原來(lái),這個(gè)中間類,繼承自原本的那個(gè)類。不僅如此,Apple 還重寫了 -class 方法,企圖欺騙我們這個(gè)類沒(méi)有變,就是原本那個(gè)類。更具體的信息,去跑一下 Mike Ash 的那篇文章里的代碼就能明白,這里就不再重復(fù)。
https://juejin.cn/post/6844903602545229831
介紹下oc
RunTime:
首先 OC 是 C 語(yǔ)言的超集,因?yàn)?runtime 這個(gè)庫(kù)使得C語(yǔ)言有了面向?qū)ο蟮哪芰Γ?br> OC 對(duì)象可以用C語(yǔ)言中的結(jié)構(gòu)體表示,而方法可以用C函數(shù)來(lái)實(shí)現(xiàn),這些結(jié)構(gòu)體和函數(shù)被 runtime 函數(shù)封裝后,我們就可以在程序運(yùn)行時(shí)創(chuàng)建,檢查,修改類、對(duì)象和它們的方法了。
OC 是一門動(dòng)態(tài)語(yǔ)言,它將很多靜態(tài)語(yǔ)言在編譯和鏈接時(shí)期做的事放到了運(yùn)行時(shí)來(lái)處理。
這種特性意味著Objective-C不僅需要一個(gè)編譯器,還需要一個(gè)運(yùn)行時(shí)系統(tǒng)來(lái)執(zhí)行編譯的代碼。這個(gè)運(yùn)行時(shí)系統(tǒng)即Objc Runtime。Objc Runtime基本上是用C和匯編寫的。
http://www.itdecent.cn/p/d7818dcb21de
靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù):
https://juejin.cn/post/7040003550977458207
編譯和鏈接:
http://www.360doc.com/content/17/0111/22/32626470_621879084.shtml
集合類型 copy 操作和 mutableCopy 操作
一個(gè)類遵循 NSCopying, NSMutableCopying 協(xié)議并且實(shí)現(xiàn)相對(duì)應(yīng)的初始化方法后,這個(gè)類就具有對(duì)象拷貝的能力。如果你自定義類沒(méi)有遵守協(xié)議直接調(diào)用 copy / mutableCopy 程序會(huì)奔潰。拷貝協(xié)議的具體使用我這里不做擴(kuò)展感興趣的可以自行 Google 一下。有一種觀點(diǎn):copy 操作就是淺復(fù)制,mutableCopy 就是深復(fù)制,這是一個(gè)非常錯(cuò)誤的理解。以下是我的一些總結(jié):
- 可變的集合對(duì)象 + copy 得到一個(gè)新的對(duì)象(新對(duì)象不可變) 深復(fù)制
- 可變的集合對(duì)象 + mutablecopy 得到一個(gè)新的對(duì)象(新對(duì)象可變) 深復(fù)制
- 不可變集合對(duì)象 + copy 沒(méi)有得到新的對(duì)象(地址的引用) 淺復(fù)制
- 不可變集合對(duì)象 + mutablecopy 得到一個(gè)新的對(duì)象(新對(duì)象可變) 深復(fù)制
怎么去動(dòng)態(tài)關(guān)聯(lián)一個(gè)weak屬性
持有一個(gè)strong的容器,讓其持有該weak屬性,獲取關(guān)聯(lián)對(duì)象時(shí)獲取其屬性即可
首先,給category屬性是需要使用runtime中的關(guān)聯(lián)來(lái)實(shí)現(xiàn)set和get方法,但runtime沒(méi)有提供weak ,雖然runtime沒(méi)有開(kāi)放weak解決方案,但objc對(duì)象是可以實(shí)現(xiàn)weak的,所以讓需要被修飾的對(duì)象去持有一個(gè)strong對(duì)象,然后當(dāng)被修飾的對(duì)象釋放的時(shí)候,持有的對(duì)象也會(huì)被釋放,那么我們就可以捕捉到釋放的事件,進(jìn)而使用OBJC_ASSOCIATION_ASSIGN來(lái)實(shí)現(xiàn)弱引用
對(duì)象的內(nèi)存布局
struct objc_class {
Class isa;
Class super_class;
const charchar *name;
long version;
long info;
long instance_size;
struct objc_ivar_list *ivars;
struct objc_method_list **methodLists;
struct objc_cache *cache;
struct objc_protocol_list *protocols;
} OBJC2_UNAVAILABLE;
二叉樹(shù)的層序遍歷
消息轉(zhuǎn)發(fā)的優(yōu)化
在 2020 年中,Apple 針對(duì) Objective-C 做了三項(xiàng)優(yōu)化
- 類數(shù)據(jù)結(jié)構(gòu)變化:節(jié)約了系統(tǒng)更多的內(nèi)存。
- 相對(duì)方法地址:節(jié)約了內(nèi)存,并且提高了性能。
- Tagged Pointer 格式的變化:提高了 msgSend 性能
Self 和 this 的底層實(shí)現(xiàn),是編譯期還是運(yùn)行期做的。答案是編譯期間
this指針本質(zhì): 當(dāng)一個(gè)對(duì)象調(diào)用某成員函數(shù)時(shí)編譯器會(huì)隱式傳入一個(gè)參數(shù), 這個(gè)參數(shù)就是this指針
this指針中存放的就是這個(gè)對(duì)象的首地址。
其實(shí)編譯器在生成程序時(shí)加入了獲取對(duì)象首地址的相關(guān)代碼,并把獲取的首地址存放在了寄存器ECX中(VC++編譯器是放在ECX中,其它編譯器有可能不同)。
成員函數(shù)的其它參數(shù)正常都是存放在棧中,而this指針參數(shù)則是存放在寄存器中。
我們都知道:self 是類的隱藏參數(shù),指向當(dāng)前調(diào)用方法的這個(gè)類的實(shí)例。那 super 呢?
很多人會(huì)想當(dāng)然的認(rèn)為“ super 和 self 類似,應(yīng)該是指向父類的指針吧!”。這是很普遍的一個(gè)誤區(qū)。其實(shí) super 是一個(gè) Magic Keyword, 它本質(zhì)是一個(gè)編譯器標(biāo)示符,和 self 是指向的同一個(gè)消息接受者!他們兩個(gè)的不同點(diǎn)在于:super 會(huì)告訴編譯器,調(diào)用 class 這個(gè)方法時(shí),要去父類的方法,而不是本類里的。
上面的例子不管調(diào)用[self class]還是[super class],接受消息的對(duì)象都是當(dāng)前 Son *xxx 這個(gè)對(duì)象。
當(dāng)使用 self 調(diào)用方法時(shí),會(huì)從當(dāng)前類的方法列表中開(kāi)始找,如果沒(méi)有,就從父類中再找;而當(dāng)使用 super 時(shí),則從父類的方法列表中開(kāi)始找。然后調(diào)用父類的這個(gè)方法。
**OC Property **
https://juejin.cn/post/6844903735651647502
20. 一個(gè)objc對(duì)象的isa的指針指向什么?有什么作用?
isa 顧名思義 is a 表示對(duì)象所屬的類。
isa 指向他的類對(duì)象,從而可以找到對(duì)象上的方法。
同一個(gè)類的不同對(duì)象,他們的 isa 指針是一樣的。
算法36進(jìn)制加法
https://blog.csdn.net/lyl194458/article/details/100192501
Unicode 和 UTF-8 有什么區(qū)別?
簡(jiǎn)單來(lái)說(shuō): Unicode 是「字符集」 UTF-8 是「編碼規(guī)則」 其中: 字符集:為每一個(gè)「
為什么說(shuō)OC是動(dòng)態(tài)語(yǔ)言
為什么說(shuō)OC是動(dòng)態(tài)語(yǔ)言呢?我們可以從下面幾個(gè)方面來(lái)說(shuō)明:
1.動(dòng)態(tài)類型:即運(yùn)行時(shí)再?zèng)Q定對(duì)象的類型,簡(jiǎn)單說(shuō)就是id類型,任何對(duì)象都可以被指定為Id類型,只有在運(yùn)行時(shí)才能決定是什么類型。像內(nèi)置的明確的基本數(shù)據(jù)類型都屬于靜態(tài)類型(int,NSString等)。靜態(tài)類型在編譯的時(shí)候就能被識(shí)別出來(lái),所以當(dāng)程序發(fā)生了類型不對(duì)應(yīng),編譯器就會(huì)發(fā)出警告。而動(dòng)態(tài)類型在編譯器編譯的時(shí)候是不能被識(shí)別的,要等到運(yùn)行時(shí),即程序運(yùn)行的時(shí)候才會(huì)根據(jù)語(yǔ)境來(lái)識(shí)別。所以這里就有兩個(gè)概念要區(qū)分:編譯時(shí)跟運(yùn)行時(shí)
2.動(dòng)態(tài)綁定:基于動(dòng)態(tài)類型,在某個(gè)實(shí)例對(duì)象被確定之后其數(shù)據(jù)類型便被確定了,該對(duì)象的屬性和響應(yīng)的消息也被完全確定,這就是動(dòng)態(tài)綁定。比如我們向一個(gè)NSObject對(duì)象發(fā)送-respondsToSelector:或者-instancesRespondToSelector:等來(lái)確定對(duì)象是否可以對(duì)某個(gè)SEL做出響應(yīng),而在OC消息轉(zhuǎn)發(fā)機(jī)制被觸發(fā)之前,對(duì)應(yīng)類的+resolveClassMethod:和+resolveInstanceMethod:將會(huì)被調(diào)用,在此時(shí)有機(jī)會(huì)動(dòng)態(tài)的向類或者實(shí)例添加新的方法,也即類的實(shí)現(xiàn)是可以動(dòng)態(tài)綁定的;isKindOfClass也是一樣的道理。
3.動(dòng)態(tài)加載:所謂動(dòng)態(tài)加載就是我們做開(kāi)發(fā)的時(shí)候icon圖片在retina設(shè)備上要多添加一個(gè)@2x的圖片,當(dāng)設(shè)備更換的時(shí)候圖片也會(huì)自動(dòng)的替換
4.多態(tài):運(yùn)行時(shí)機(jī)制是多態(tài)的基礎(chǔ)。多態(tài)主要是將數(shù)據(jù)類型的確定由編譯時(shí)推遲到了運(yùn)行時(shí)。不同對(duì)象以自己的方式響應(yīng)相同消息的能力叫做多態(tài)。例如所有的動(dòng)物都有同一個(gè)方法eat,但每個(gè)動(dòng)物的eat方式不同,也就是不同的對(duì)象以自己的方式響應(yīng)了相同的信息(響應(yīng)了eat這個(gè)選擇器)。
Category的本質(zhì)是一個(gè)_category_t結(jié)構(gòu)體,其結(jié)構(gòu)如下:
1、分類中只能添加“方法”,不能增加成員變量。如果分類中聲明了一個(gè)屬性,那么分類只會(huì)生成這個(gè)屬性的set、get方法聲明,也就是不會(huì)有實(shí)現(xiàn)。 2、分類中可以/只能訪問(wèn)原有類中.h中的屬性。如果想要訪問(wèn)本類中的私有變量,分類和子類一樣,只能通過(guò)方法來(lái)訪問(wèn)。 3、在本類和分類有相同的方法時(shí),優(yōu)先調(diào)用分類的方法再調(diào)用本類的方法。 4、如果多個(gè)分類中都有和原有類中同名的方法,那么調(diào)用該方法的時(shí)候執(zhí)行誰(shuí)由編譯器決定;編譯器會(huì)執(zhí)行最后一個(gè)參與編譯的分類中的方法。
Categroy的加載過(guò)程
在編譯時(shí)只是一個(gè)包含類名,類指針,方法列表,屬性列表,協(xié)議列表的_category_t結(jié)構(gòu)體;
在運(yùn)行時(shí)通過(guò)runtime加載分類數(shù)據(jù),把分類的方法、屬性、協(xié)議數(shù)據(jù)合并到一個(gè)大數(shù)組中,后參與編譯的分類會(huì)在數(shù)組的前面(i–倒數(shù)遍歷數(shù)組添加的)(這也說(shuō)明了分類中相同的方法后參與編譯的分類會(huì)被調(diào)用);
合并后的分類數(shù)據(jù)會(huì)插入到原來(lái)類數(shù)據(jù)的前面(相同的方法,分類會(huì)優(yōu)先于原來(lái)調(diào)用)。
編譯順序是可以手動(dòng)設(shè)置的:TARGETS->BuildPhases->Complle Sources。(自己可以驗(yàn)證一下,這里不再贅述)
Category 和Class Extension 的區(qū)別
Class Extension 是在編譯后合并到類中。
Category 是runtime 運(yùn)行時(shí) 合并到類中。
weak 實(shí)現(xiàn)原理的概括
Runtime維護(hù)了一個(gè)weak表,用于存儲(chǔ)指向某個(gè)對(duì)象的所有weak指針。weak表其實(shí)是一個(gè)hash(哈希)表,Key是所指對(duì)象的地址,Value是weak指針的地址(這個(gè)地址的值是所指對(duì)象指針的地址)數(shù)組。
weak 的實(shí)現(xiàn)原理可以概括一下三步:
1、初始化時(shí):runtime會(huì)調(diào)用objc_initWeak函數(shù),初始化一個(gè)新的weak指針指向?qū)ο蟮牡刂贰?br>
2、添加引用時(shí):objc_initWeak函數(shù)會(huì)調(diào)用 objc_storeWeak() 函數(shù), objc_storeWeak() 的作用是更新指針指向,創(chuàng)建對(duì)應(yīng)的弱引用表。
3、釋放時(shí),調(diào)用clearDeallocating函數(shù)。clearDeallocating函數(shù)首先根據(jù)對(duì)象地址獲取所有weak指針地址的數(shù)組,然后遍歷這個(gè)數(shù)組把其中的數(shù)據(jù)設(shè)為nil,最后把這個(gè)entry從weak表中刪除,最后清理對(duì)象的記錄。