1幕庐、nil 、 NSNull
nil:針對對象骤素,而空對象不是說不占用空間匙睹,相當于一個“洗白”,回到初始狀態(tài)济竹。
我們給對象賦值時一般會使用object = nil痕檬,表示我想把這個對象釋放掉;或者對象由于某種原因送浊,經(jīng)過多次release梦谜,于是對象引用計數(shù)器為0了,系統(tǒng)將這塊內(nèi)存釋放掉袭景,這個時候這個對象為nil唁桩,我稱它為“空對象”。(注意:我這里強調(diào)的是“空對象”浴讯,下面我會拿它和“值為空的對象”作對比6湎摹!S芘Α)
所以對于這種空對象仰猖,所有關(guān)于retain的操作都會引起程序崩潰,例如字典添加鍵值或數(shù)組添加新原素等
NSNull:針對指針奈籽,對對象指針和非對象指針都有效饥侵,Null不會占用空間。
NSNull和nil的區(qū)別在于衣屏,nil是一個空對象躏升,已經(jīng)完全從內(nèi)存中消失了,而如果我們想表達“我們需要有這樣一個容器狼忱,但這個容器里什么也沒有”的觀念時膨疏,我們就用到NSNull一睁,我稱它為“值為空的對象”。如果你查閱開發(fā)文檔你會發(fā)現(xiàn)NSNull這個類是繼承NSObject佃却,并且只有一個“+ (NSNull *) null者吁;”類方法。這就說明NSNull對象擁有一個有效的內(nèi)存地址饲帅,所以在程序中對它的任何引用都是不會導致程序崩潰的复凳。
2、沙盒包有含三個目錄:Documents灶泵、Library育八、temp
????1)Documents :這個目錄用于存儲用戶數(shù)據(jù)。該路徑可通過配置實現(xiàn)iTunes共享文件赦邻。iTunes或iCloud會對其進行備份髓棋。
????2)Library :這個目錄下有兩個子目錄:
? ? ? ? ? ????????Preferences :包含應(yīng)用程序的偏好設(shè)置文件。iTunes或iCloud會對其進行備份深纲。
? ? ? ? ??????????Caches :存放緩存數(shù)據(jù)仲锄,可以重新下載或生成的數(shù)據(jù)劲妙,同時沒有這些數(shù)據(jù)不會影響用戶離線使用湃鹊。緩存數(shù)據(jù)在設(shè)備低存儲空間時可能被刪除。iTunes或iCloud不會對其進行備份镣奋。
?????3)tmp :這個目錄用于存放臨時文件币呵,保存應(yīng)用程序再次啟動過程中不需要的信息。系統(tǒng)會不定期刪除其中的文件侨颈。該路徑下的文件不會被iTunes備份余赢。
3、事件傳遞鏈
? ? ?先判斷點是否在View內(nèi)部哈垢,然后遍歷subViews
????- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;?
? ? ?判斷點是否在這個View內(nèi)部
????- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event;?
? ? ? ?// default returns YES if point is in bounds
????A: 流程
????????1:先判斷該層級是否能夠響應(yīng)(1.alpha>0.01 2.userInteractionEnabled == YES 3.hidden = NO)
????????2:判斷改點是否在view內(nèi)部,
????????3:如果在那么遍歷子view繼續(xù)返回可響應(yīng)的view妻柒,直到?jīng)]有。
????B:常見問題
????????父view設(shè)置為不可點擊耘分,子view可以點擊嗎
????????不可以举塔,hit test 到父view就截止了
????????子view設(shè)置view不可點擊不影響父類點擊
????????同父view覆蓋不影響點擊
????????手勢對responder方法的影響
????C:實際用法
????????點一一個圓形控件,如何實現(xiàn)只點擊圓形區(qū)域有效
????????重載pointInside求泰。此時可將外部的點也判斷為內(nèi)部的點央渣,反之也可以
4、進程和線程
????????1)線程在進程下行進(單純的車廂無法運行)
????????2)一個進程可以包含多個線程(一輛火車可以有多個車廂)
????????3)不同進程間數(shù)據(jù)很難共享(一輛火車上的乘客很難換到另外一輛火車渴频,比如站點換乘)
????????4)同一進程下不同線程間數(shù)據(jù)很易共享(A車廂換到B車廂很容易)
????????5)進程要比線程消耗更多的計算機資源(采用多列火車相比多個車廂更耗資源)
????????6)進程間不會相互影響芽丹,一個線程掛掉將導致整個進程掛掉(一列火車不會影響到另外一列火車,但是如果一列火車上中間的一節(jié)車廂著火了卜朗,將影響到所有車廂)
????????7)進程可以拓展到多機拔第,進程最多適合多核(不同火車可以開在多個軌道上咕村,同一火車的車廂不能在行進的不同的軌道上)
????????8)進程使用的內(nèi)存地址可以上鎖,即一個線程使用某些共享內(nèi)存時蚊俺,其他線程必須等它結(jié)束培廓,才能使用這一塊內(nèi)存。(比如火車上的洗手間)-"互斥鎖"
????????9)進程使用的內(nèi)存地址可以限定使用量(比如火車上的餐廳春叫,最多只允許多少人進入肩钠,如果滿了需要在門口等,等有人出來了才能進去)-“信號量”
????GCD的隊列分為2大類型:
? ? ? ? ? 1暂殖、并發(fā)隊列
????????????????可以讓多個任務(wù)并發(fā)執(zhí)行(自動開啟多個線程同時執(zhí)行任務(wù))
????????????????并發(fā)功能只有在異步函數(shù)下才有效
? ? ? ? ? 2价匠、串行隊列
????????????????任務(wù)一個接一個的執(zhí)行(一個任務(wù)執(zhí)行完畢后執(zhí)行下一個任務(wù))
? ??同步、異步呛每、并發(fā)踩窖、串行
????????????????同步和異步主要影響:能不能開啟新的線程
????????????????????????同步:在當前線程中執(zhí)行任務(wù),不具備開啟線程的能力
????????????????????????異步:在新的線程中執(zhí)行任務(wù)晨横,具備開啟新線程的能力
????????????????并發(fā)和串行主要影響:任務(wù)的執(zhí)行方式
????????????????????????并發(fā):多個任務(wù)同時執(zhí)行
????????????????????????串行:一個任務(wù)執(zhí)行完畢后洋腮,在執(zhí)行下一個任務(wù)
5、objc_getClass與object_getClass
????1)Class objc_getClass(const char *aClassName)
????????????1> 傳入字符串類名
????????????2> 返回對應(yīng)的類對象
????2)Class object_getClass(id obj)
????????????1> 傳入的obj可能是instance對象手形、class對象啥供、meta-class對象
????????????2> 返回值
????????????????????a) 如果是instance對象,返回class對象
????????????????????b) 如果是class對象库糠,返回meta-class對象
????????????????????c) 如果是meta-class對象伙狐,返回NSObject(基類)的meta-class對象
????3)- (Class)class、+ (Class)class
????????????1> 返回的就是類對象
????????????????- (Class) {
? ? ???????????? ????return self->isa;
?????????????????}
???????????????+ (Class) {
????????????? ??????? return self;
?????????????????}
6瞬欧、反射
????????反射可以理解為類名贷屎、方法名、屬性名等和字符串在運行時相互轉(zhuǎn)化的一種機制
????????實質(zhì) - 發(fā)送了一個消息給Runtime艘虎,然后Runtime再根據(jù)這個Class的字符串名和這個方法的字符串名唉侄,去匹配真正相應(yīng)的方法地址,然后再執(zhí)行野建。同樣反射就是利用字符串去動態(tài)的檢測属划,從而實現(xiàn)運行時的轉(zhuǎn)化。
????????優(yōu)點:
????????????????解耦合贬墩,消除類與類之間的依賴
????????缺點:
????????????????代碼可讀性降低榴嗅,將原有邏輯復(fù)雜化了,不利于維護
? ? ? ? 性能較差陶舞。使用反射匹配字符串間接命中內(nèi)存比直接命中內(nèi)存的方式要慢嗽测。當然,這個程度取決于使用場景,如果只是作為程序中很少涉及的部分唠粥,這個性能上的影響可以忽略不計疏魏。但是,如果在性能很關(guān)鍵的應(yīng)用核心邏輯中使用反射晤愧,性能問題就尤其重要了)
7大莫、CADisplayLink 與 NSTimer
????CADisplayLink
????????????正常情況下會在每次刷新結(jié)束都被調(diào)用,精確度相當高
????????????使用場合相對專一官份,適合做UI的不停重繪
????NSTimer
????????????精確度就顯得低了點只厘,比如NSTimer的觸發(fā)時間到的時候,runloop如果在阻塞狀態(tài)舅巷,觸發(fā)時間就會推遲到下一個runloop周期
????????????使用范圍要廣泛的多羔味,各種需要單次或者循環(huán)定時處理的任務(wù)都可以使用
8、iOS---------消息轉(zhuǎn)發(fā)機制
? ? ? ? 消息轉(zhuǎn)發(fā)機制的原理 其實就是在內(nèi)部做了三次的補救機會
????????1)動態(tài)解析? 利用runtime動態(tài)添加實現(xiàn)代碼? ?
????????????????resolveInstanceMethod:
????????????????resolveClassMethod:
????????2)快速轉(zhuǎn)發(fā)? 也就是重定向接受者? ? 它會去找其他的類 將消息轉(zhuǎn)發(fā)給可以響應(yīng)該消息的對象進行處理
????????????????- (id)forwardingTargetForSelector:(SEL)aSelector {
????????????????????????????return nil;
????????????????????}
???????3)完整轉(zhuǎn)發(fā)? ? 指定選擇器? IMP指向?qū)崿F(xiàn)代碼
????????????????forwardInvocation
????????_objc_msgForward 函數(shù)是做什么的钠右?直接調(diào)用會發(fā)生什么問題赋元?
? ??????當對象沒有實現(xiàn)某個方法 ,會調(diào)用這個函數(shù)進行方法轉(zhuǎn)發(fā)飒房。 (某方法對應(yīng)的IMP沒找到搁凸,會返回這個函數(shù)的IMP去執(zhí)行)
? ??????1.調(diào)用resolveInstanceMethod:方法,允許用戶在此時為該Class動態(tài)添加實現(xiàn)狠毯。如果有實現(xiàn)了护糖,則調(diào)用并返回。如果仍沒實現(xiàn)垃你,繼續(xù)下面的動作椅文。
? ??????2.調(diào)用forwardingTargetForSelector:方法,嘗試找到一個能響應(yīng)該消息的對象惜颇。如果獲取到,則直接轉(zhuǎn)發(fā)給它少辣。如果返回了nil凌摄,繼續(xù)下面的動作。
? ??????3.調(diào)用methodSignatureForSelector:方法漓帅,嘗試獲得一個方法簽名锨亏。如果獲取不到,則直接調(diào)用doesNotRecognizeSelector拋出異常忙干。
? ??????4.調(diào)用forwardInvocation:方法器予,將地3步獲取到的方法簽名包裝成Invocation傳入,如何處理就在這里面了捐迫。
? ??????如果直接調(diào)用這個方法乾翔,就算實現(xiàn)了想調(diào)用的方法,也不會被調(diào)用,會直接走消息轉(zhuǎn)發(fā)步驟反浓。
9萌丈、UI刷新在主線程
????????UIKit并不是一個線程安全的類,UI操作涉及到渲染訪問各種View對象的屬性雷则,如果異步操作下會存在讀寫問題辆雾,而為其加鎖則會耗費大量資源并拖慢運行速度。
????????整個程序的起點UIApplication是在主線程進行初始化月劈,所有的用戶事件都是在主線程上進行傳遞(如點擊度迂、拖動),所以view只能在主線程上才能對事件進行響應(yīng)猜揪。
????????渲染方面由于圖像的渲染需要以60幀的刷新率在屏幕上同時更新英岭,在非主線程異步化的情況下無法確定這個處理過程能夠?qū)崿F(xiàn)同步更新。在子線程中如果要對UI 進行更新湿右,必須等到該子線程運行結(jié)束才能把UI的更新提交給渲染服務(wù)诅妹。
10、NSObject和id
????????id是一個指針毅人。
????????NSObject *是NSObject類型的指針吭狡。
????????Objective-C中并非所有的類都繼承自NSObject,還有NSProxy類丈莺,故NSObject *的范圍小于id划煮。
11、鎖
????????自旋鎖缔俄、互斥鎖比較 -?
????????????????代碼執(zhí)行頻率高弛秋,CPU充足,可以使用互斥鎖俐载,
????????????????頻率低蟹略,代碼復(fù)雜則需要互斥鎖。
????????自旋鎖 - 等待鎖的進程會處于忙等(busy-wait)狀態(tài)遏佣,一直占用著CPU資源挖炬,目前已經(jīng)不安全,可能會出現(xiàn)優(yōu)先級翻轉(zhuǎn)問題
????????????????自旋鎖在等待時間比較短的時候比較合適
????????????????臨界區(qū)代碼經(jīng)常被調(diào)用状婶,但競爭很少發(fā)生
????????????????CPU不緊張
????????????????多核處理器
????????互斥鎖?- 等待鎖的線程會處于休眠狀態(tài)
????????????????預(yù)計線程等待時間比較長
????????????????單核處理器
????????????????臨界區(qū)IO操作
????????????????臨界區(qū)代碼比較多意敛、復(fù)雜,或者循環(huán)量大
????????????????臨界區(qū)競爭非常激烈
????????遞歸鎖 - 同一個線程可以加鎖N次而不會引發(fā)死鎖
????????mutex? ? :pthread_mutex_t 互斥鎖膛虫,等待鎖的線程會處于休眠狀態(tài)草姻。
????????NSLock ? :對mutex普通鎖的封裝。
????????NSRecursiveLock? ? :對mutex遞歸鎖的封裝稍刀,遞歸鎖可以對相同的線程進行反復(fù)加鎖撩独。
????????NSCondition ? :對mutex和cond的封裝,優(yōu)點是可以讓線程之間形成依賴,缺點是沒有明確的條件跌榔。
????????NSConditionLock? ? :NSCondition的進一步封裝
????????????????可以實現(xiàn)多個子線程進行線程間的依賴异雁,A依賴于B執(zhí)行完成,B依賴于C執(zhí)行完畢則可以使用NSConditionLock來解決問題
????????dispatch_queue ? :特殊的鎖僧须,直接使用GCD的串行隊列纲刀,也是可以實現(xiàn)線程同步的。串行隊列其實就是線程的任務(wù)在隊列中按照順序執(zhí)行担平,達到了鎖的目的示绊。
????????dispatch_semaphore :信號量控制并發(fā)數(shù)量,可以控制并發(fā)線程的數(shù)量暂论,當設(shè)置為1時面褐,可以作為同步鎖來用,設(shè)置多個的時候取胎,就是異步并發(fā)隊列展哭。
????????@synchronized ? :鎖的是對象obj,使用該鎖的時候闻蛀,底層是對象計算出來的值作為key匪傍,生成一把鎖,不同的資源的讀寫可以使用不同obj作為鎖對象觉痛。
????????atmoic ? :原子操作役衡,給屬性添加atmoic修飾,可以保證屬性的setter和getter都是原子性操作薪棒,也就保證了setter和getter的內(nèi)部是線程同步的手蝎。atomic讀取頻率高的時候會導致線程都在排隊,浪費CPU時間
????????讀寫鎖:pthread_rwlock(c語言封裝的讀寫鎖) / 異步柵欄調(diào)用 dispatch_barrier_async
????????性能從高到低排序
????????????????os_unfair_lock
????????????????OSSpinLock
????????????????dispatch_semaphore
????????????????pthread_mutex
????????????????dispatch_queue(DISPATCH_QUEUE_SERIAL)
????????????????NSLock
????????????????NSCondition
????????????????pthread_mutex(recursive)
????????????????NSRecursiveLock
????????????????NSConditionLock
????????????????@synchronized
????????平時簡單使用的話沒有很大的區(qū)別俐芯,還是推薦使用NSLock和信號量,最簡單的是@synchronized棵介,不用聲明和初始化,直接拿來就用泼各。
????????總結(jié)
????????????????普通線程鎖本質(zhì)就是同步執(zhí)行
????????????????atomic原子操作只限制setter和getter方法鞍时,不限制成員變量
????????????????讀寫鎖高性能可以使用pthread_rwlock_t和dispatch_barrier_async
????????死鎖的4個必要條件
????????1、互斥: 某種資源一次只允許一個進程訪問扣蜻,即該資源一旦分配給某個進程,其他進程就不能再訪問及塘,直到該進程訪問結(jié)束莽使。
????????2、占有且等待: 一個進程本身占有資源(一種或多種)笙僚,同時還有資源未得到滿足芳肌,正在等待其他進程釋放該資源。
????????3、不可搶占:別人已經(jīng)占有了某項資源亿笤,你不能因為自己也需要該資源翎迁,就去把別人的資源搶過來。
????????4净薛、循環(huán)等待: 存在一個進程鏈汪榔,使得每個進程都占有下一個進程所需的至少一種資源。
12肃拜、優(yōu)化
CPU
????????盡量用輕量級的對象痴腌,比如用不到事件處理的地方,可以考慮使用CALayer取代UIView
????????不要頻繁地調(diào)用UIView的相關(guān)屬性燃领,比如frame士聪、bounds、transform等屬性猛蔽,盡量減少不必要的修改
????????盡量提前計算好布局剥悟,在有需要時一次性調(diào)整對應(yīng)的屬性,不要多次修改屬性
????????Autolayout會比直接設(shè)置frame消耗更多的CPU資源
????????圖片的size最好剛好跟UIImageView的size保持一致
????????控制一下線程的最大并發(fā)數(shù)量
????????盡量把耗時的操作放到子線程
????????文本處理(尺寸計算曼库、繪制)
????????圖片處理(解碼区岗、繪制)
GPU
????????盡量避免短時間內(nèi)大量圖片的顯示,盡可能將多張圖片合成一張進行顯示
????????GPU能處理的最大紋理尺寸是4096x4096凉泄,一旦超過這個尺寸躏尉,就會占用CPU資源進行處理,所以紋理盡量不要超過這個尺寸
????????盡量減少視圖數(shù)量和層次
????????減少透明的視圖(alpha<1)后众,不透明的就設(shè)置opaque為YES
????????盡量避免出現(xiàn)離屏渲染
????????合理選擇 imageNamed 和 imageWithContentsOfFile
????????imageNamed 會對圖片進行緩存胀糜,適合多次使用某張圖片
????????imageWithContentsOfFile 從bundle中加載圖片文件,不會進行緩存蒂誉,適用于加載一張較大的并且只使用一次的圖片教藻,例如引導圖等
13、[self class] [super class]
????????1右锨、前兩個方法是給self發(fā)送消息, 消息名稱是class和superclass, 結(jié)果很明顯就是查看自己的類型和父類的類型
????????2括堤、后兩個方法也是給self發(fā)送消息, 只不過是從父類開始查詢class和superclass方法, 而這兩個方法都存在于NSObject中
????????3、消息接收者同樣是self, 調(diào)用的方法也是相同, 所以結(jié)果就是自己的類型和父類的類型
14绍移、RunLoop的基本作用
????????1悄窃、保持程序的持續(xù)運行
????????2、處理app中的各種事件(比如觸摸事件蹂窖、定時器事件轧抗、selector事件
????????3、節(jié)省CPU資源瞬测,提高程序性能横媚,有事情就做事情纠炮,沒事情就休息
????????Mode作用 - 指定事件在運行循環(huán)(Loop)中的優(yōu)先級。 線程的運行需要不同的模式灯蝴,去響應(yīng)各種不同的事件恢口,去處理不同情境模式。(比如可以優(yōu)化tableview的時候可以設(shè)置UITrackingRunLoopMode下不進行一些操作)
15穷躁、dealloc包括以下幾個步驟
????????1耕肩、c++析構(gòu)函數(shù)調(diào)用(C++析構(gòu)函數(shù)的作用是用來完成對象被刪除前的一些清理工作,也就是專門的掃尾工作)
????????2折砸、關(guān)聯(lián)對象(例如使用runtime在分類中關(guān)聯(lián)變量)移除看疗,是一個hash表來存儲
????????3、這里進行弱引用表sidetable的相關(guān)釋放操作睦授,包括表的釋放以及引用計數(shù)两芳,即weak指針置為nil的操作就在這里
????????注意 - dealloc方法是對象引用計數(shù)在哪個線程為0,則在哪個線程調(diào)用dealloc方法去枷,所以不一定在主線程執(zhí)行
16怖辆、SideTables 、 SideTable
????????在runtime內(nèi)存空間中删顶,SideTables是一個8個元素長度(長度為64)的hash數(shù)組惕蹄,里面存儲了SideTable洒嗤。SideTables的hash鍵值就是一個對象obj的address凳鬓。一個 obj影钉,對應(yīng)了一個SideTable。但是一個SideTable录粱,會對應(yīng)多個obj腻格。因為SideTable的數(shù)量只有64個,所以會有很多obj共用同一個SideTable
????????在一個SideTable中啥繁,成員:
????????spinlock_t slock ; ????????????? ?//自旋鎖菜职,用于上鎖/解鎖 SideTable。
????????RefcountMap refcnts;? ? ? ? // 對象引用計數(shù)相關(guān) map
????????? ? ? ? (hash map旗闽,其key是obj的地址酬核,而value,則是obj對象的引用計數(shù))
????????????????(僅在未開啟isa優(yōu)化 或 在isa優(yōu)化情況下isa_t的引用計數(shù)溢出時才會用到)
????????weak_table_t weak_table;? ? // 對象弱引用相關(guān) table
????????? ? ? ? (存儲了弱引用obj的指針的地址适室,其本質(zhì)是一個以obj地址為key嫡意,弱引用obj的指針的地址作為value的hash表)
????????Runtime 維護了一個 weak表,用于存儲指向某個對象的所有weak指針捣辆。weak表 其實是一個 hash(哈希)表鹅很,Key 是所指對象的地址,Value是 weak指針 的地址(這個地址的值是所指對象指針的地址)數(shù)組罪帖。
????????1促煮、初始化時:runtime 會調(diào)用 objc_initWeak函數(shù),初始化一個新的 weak指針 指向?qū)ο蟮牡刂贰?/i>
????????2整袁、添加引用時:objc_initWeak函數(shù) 會調(diào)用 objc_storeWeak() 函數(shù)菠齿, objc_storeWeak() 的作用是更新指針指向,創(chuàng)建對應(yīng)的弱引用表坐昙。
????????3绳匀、釋放時,調(diào)用 clearDeallocating函數(shù)炸客。clearDeallocating函數(shù)首先根據(jù)對象地址獲取所有 weak指針地址的數(shù)組疾棵,然后遍歷這個數(shù)組把其中的數(shù)據(jù)設(shè)為 nil,最后把這個 entry 從 weak表中刪除痹仙,最后清理對象的記錄是尔。
17、load 和 initialize
????????+load
????????????????1开仰、+load方法會在runtime加載類拟枚、分類時調(diào)用
????????????????2、每個類众弓、分類的+load恩溅,在程序運行過程中只調(diào)用一次
????????????????3、調(diào)用順序
????????????????????????1)先調(diào)用類的+load
????????????????????????????????按照編譯先后順序調(diào)用(先編譯谓娃,先調(diào)用)?????????
????????????????????????2)調(diào)用子類的+load之前會先調(diào)用父類的+load
????????????????????????3)再調(diào)用分類的+load
????????????????????????????????按照編譯先后順序調(diào)用(先編譯脚乡,先調(diào)用)
????????+initialize
????????? ? ? ?1、 +initialize方法會在類第一次接收到消息時調(diào)用
????????? ? ? ? 2滨达、調(diào)用順序
????????????????? ? ? ? 1奶稠、先調(diào)用父類的+initialize,再調(diào)用子類的+initialize
????????????????????????????????(先初始化父類弦悉,再初始化子類窒典,每個類只會初始化1次)
????????區(qū)別:
????????+initialize是通過objc_msgSend進行調(diào)用的,所以有以下特點:
????????? ? ? ? 1稽莉、如果子類沒有實現(xiàn)+initialize瀑志,會調(diào)用父類的+initialize(所以父類的+initialize可能會被調(diào)用多次)
????????? ? ? ? 2、如果分類實現(xiàn)了+initialize污秆,就覆蓋類本身的+initialize調(diào)用
18劈猪、Category
????????實現(xiàn)原理
? ? ? ? 1、Category編譯之后的底層結(jié)構(gòu)是struct category_t良拼,里面存儲著分類的對象方法战得、類方法、屬性庸推、協(xié)議信息
? ? ? ? 2常侦、在程序運行的時候浇冰,runtime會將Category的數(shù)據(jù),合并到類信息中(類對象聋亡、元類對象中)
????????Category和Class Extension的區(qū)別
? ? ? ? 1肘习、Class Extension在編譯的時候,它的數(shù)據(jù)就已經(jīng)包含在類信息中
? ? ? ? 2坡倔、Category是在運行時漂佩,才會將數(shù)據(jù)合并到類信息中
19、能否想向編譯后得到的類中增加實例變量罪塔?能否向運行時創(chuàng)建的類中添加實例變量投蝉?
????????1.不能向編譯后得到的類增加實例變量
????????2.能向運行時創(chuàng)建的類中添加實例變量
解釋:
????????1.編譯后的類已經(jīng)注冊在runtime中,類結(jié)構(gòu)體中的objc_ivar_list實例變量的鏈表和instance_size實例變量的內(nèi)存大小已經(jīng)確定, runtime會調(diào)用 class_setvarlayout 或 class_setWeaklvarLayout來處理 strong weak引用.所以不能向存在的類中添加實例變量
????????2.運行時創(chuàng)建的類是可以添加實例變量,調(diào)用class_addIvar函數(shù).但是的在調(diào)用objc_allocateClassPair之后, objc_registerClassPair之前,原因同上.
20、頁面加載速率
????????viewcontroller從viewdidload的第一行到viewdidappear的最后一行所用的時間
21征堪、AutoreleasePool AutoreleasePage
一個AutoreleasePoolPage屬于一個線程瘩缆,一個線程中可以有多個AutoreleasePoolPage
我們可以知道AutoreleasePoolPage底層結(jié)構(gòu)如下:
AutoreleasePoolPage是以棧為結(jié)點通過雙向鏈表的形式組合而成;遵循先進后出規(guī)則请契,整個自動釋放池由一系列的AutoreleasePoolPage組成的咳榜,而AutoreleasePoolPage是以雙向鏈表的形式連接起來。
自動釋放池與線程一一對應(yīng)爽锥;
每個AutoreleasePoolPage對象占用4096字節(jié)內(nèi)存涌韩,其中56個字節(jié)用來存放它內(nèi)部的成員變量,剩下的空間(4040個字節(jié))用來存放autorelease對象的地址氯夷。要注意的是第一頁只有504個對象臣樱,因為在創(chuàng)建page的時候會在next的位置插入1個POOL_SENTINEL。
POOL_BOUNDARY為哨兵對象腮考,入棧時插入雇毫,出棧時釋放對象到此傳入的哨兵對象
每一頁里都存儲了next指針,指向下次新添加的autoreleased對象的位置踩蔚。
每一頁里都包含父節(jié)點和子節(jié)點棚放,分別指向上一頁和下一頁。第一頁的父節(jié)點為nil馅闽,最后一頁的子節(jié)點為nil飘蚯。
每一頁都有一個深度標記,第一頁深度值為0福也,后面的頁面遞增1局骤。
每一頁里還包當前線程、最大入棧數(shù)量暴凑。
AutoreleasePool的內(nèi)存結(jié)構(gòu)如上圖所示峦甩,特點如下:
1)自動釋放池是一個棧的結(jié)構(gòu),是一個以AutoreleasePoolPage為結(jié)點的雙向鏈表现喳,根據(jù)需要來動態(tài)添加或刪除頁面凯傲。
2)每一頁AutoreleasePoolPage的大小為4096字節(jié)犬辰,地址從低到高依次存儲page自身成員、哨兵泣洞、對象指針忧风。其中,自身成員占用56字節(jié)球凰,且哨兵作為對象指針的邊界,在釋放池里只會有一個腿宰,因此:
第一頁呕诉,內(nèi)部存放:page成員 + 1個哨兵 + 504個對象指針。
其它頁吃度,內(nèi)部存放:page成員 + 505個對象指針甩挫。
3)已存滿的頁面被標記為full page,當前正在操作的頁被標記為hot page椿每。
4)AutoreleasePoolPage繼承自AutoreleasePoolPageData伊者,內(nèi)部成員情況如下:
magic:用來校驗AutoreleasePoolPage的結(jié)構(gòu)是否完整。
next :下次新添加的autoreleased對象的位置间护,初始化時指向begin()亦渗。
thread:當前線程,說明自動釋放池和線程有關(guān)聯(lián)汁尺。
parent :指向父節(jié)點法精,即上一個頁面,第一個頁面的parent值為nil痴突。
child:指向子節(jié)點搂蜓,即下一個頁面,最后一個頁面的child值為nil辽装。
depth :表示頁面深度帮碰,從0開始,往后遞增1拾积。
hiwat :即high water mark殉挽,表示最大入棧數(shù)量標記
POOL_BOUNDARY:
只是nil的別名。前世叫做POOL_SENTINEL殷勘,稱為哨兵對象或者邊界對象此再;
POOL_BOUNDARY用來區(qū)分不同的自動釋放池,以解決自動釋放池嵌套的問題
每當創(chuàng)建一個自動釋放池玲销,就會調(diào)用push()方法將一個POOL_BOUNDARY入棧输拇,并返回其存放的內(nèi)存地址;
當往自動釋放池中添加autorelease對象時贤斜,將autorelease對象的內(nèi)存地址入棧策吠,它們前面至少有一個POOL_BOUNDARY逛裤;
當銷毀一個自動釋放池時,會調(diào)用pop()方法并傳入一個POOL_BOUNDARY猴抹,會從自動釋放池中最后一個對象開始带族,依次給它們發(fā)送release消息,直到遇到這個POOL_BOUNDARY
22蟀给、ARC?
在即將超出作用域的時候蝙砌,編譯器會給所有__strong標識的變量調(diào)用一次release
weak也稱為弱引用,弱引用表示并不持有對象跋理,當所引用的對象銷毀了择克,這個變量就自動設(shè)為nil
即使是使用alloc/new/copy/mutableCopy創(chuàng)建的對象,也不持有前普,結(jié)果就是這個對象沒人要肚邢,所以一出來就銷毀了
注意 - 通過非這4個方法創(chuàng)建的對象,并不會因為__weak標識已創(chuàng)建就銷毀拭卿,而是要等到超出autoreleasepool的時候才會銷毀骡湖。
23、sizeThatFits峻厚、sizeToFit
????????sizeThatFits: 會計算出最優(yōu)的 size ,但是不會改變 自己的 size;
????????sizeToFit: 會計算出最優(yōu)的 size 而且會改變自己的 size.
????????Label 文本較長以至于不能單行顯示時响蕴,兩者也是有區(qū)別的
24、SEL IMP
????????SEL - 選擇器目木,代表方法名/函數(shù)名换途,底層結(jié)構(gòu)和char *類似
????????????????可以通過@selector()和sel_registerName()獲得
????????????????可以通過sel_getName()和NSStringFromSelector()轉(zhuǎn)成字符串
????????????????不同類中相同名字的方法名,所對應(yīng)的方法選擇器是相同的
????????IMP - 函數(shù)的具體實現(xiàn)
25刽射、安裝包瘦身
????ipa主要由可執(zhí)行文件军拟、資源組成
? ? ? ? 1、資源(圖片誓禁、音頻懈息、視頻等)
????????????????采取無損壓縮
????????????????去除沒有用到的資源: https://github.com/tinymind/LSUnusedResources
? ? ? ? 2、可執(zhí)行文件瘦身
????????????????編譯器優(yōu)化
Strip Linked Product摹恰、Make Strings Read-Only辫继、Symbols Hidden by Default設(shè)置為YES
????????????????去掉異常支持
Enable C++ Exceptions、Enable Objective-C Exceptions設(shè)置為NO俗慈, Other C Flags添加-fno-exceptions
????????????????利用AppCode(https://www.jetbrains.com/objc/)檢測未使用的代碼:菜單欄 -> Code -> Inspect Code
????????????????編寫LLVM插件檢測出重復(fù)代碼姑宽、未被調(diào)用的代碼
????????
????????????????
????????
????????????????
????????