面向對象的三大特性:封裝、繼承勇边、多態(tài)
OC內存管理
_strong
?? 引用計數(shù)器來控制對象的生命周期峭判。
_weak
?? 不會持有對象,防止循環(huán)引用棍好。
_autorelasing
?? 自動釋放池仗岸。
ARC
ARC會自動插入retain和release語句。ARC編譯器有兩部分借笙,分別是前端編譯器和優(yōu)化器扒怖。
1. 前端編譯器
前端編譯器會為“擁有的”每一個對象插入相應的release語句。如果對象的所有權修飾符是__strong提澎,那么它就是被擁有的姚垃。如果在某個方法內創(chuàng)建了一個對象,前端編譯器會在方法末尾自動插入release語句以銷毀它盼忌。而類擁有的對象(實例變量/屬性)會在dealloc方法內被釋放积糯。事實上,你并不需要寫dealloc方法或調用父類的dealloc方法谦纱,ARC會自動幫你完成一切看成。此外,由編譯器生成的代碼甚至會比你自己寫的release語句的性能還要好跨嘉,因為編輯器可以作出一些假設川慌。在ARC中,沒有類可以覆蓋release方法祠乃,也沒有調用它的必要梦重。ARC會通過直接使用objc_release來優(yōu)化調用過程。而對于retain也是同樣的方法亮瓷。ARC會調用objc_retain來取代保留消息琴拧。
2. ARC優(yōu)化器
雖然前端編譯器聽起來很厲害的樣子,但代碼中有時仍會出現(xiàn)幾個對retain和release的重復調用嘱支。ARC優(yōu)化器負責移除多余的retain和release語句蚓胸,確保生成的代碼運行速度高于手動引用計數(shù)的代碼。
runtime 中除师,SEL和IMP的區(qū)別
答:SEL:類成員的方法指針沛膳,不同于C中的函數(shù)指針,SEL只是一個編號汛聚。?
? ? ? ? IMP:函數(shù)指針锹安,指向我們定義的函數(shù)。
? ? ? ? 每一個繼承于NSObject的類都能自動獲得runtime的支持。在這樣的一個類中八毯,有一個isa指針搓侄,指向該類定義的數(shù)據(jù)結構體,這個結構體是由編譯器編譯時為類(需繼承于NSObject)創(chuàng)建的.在這個結構體中有包括了指向其父類類定義的指針以及 Dispatch table. Dispatch table是一張SEL和IMP的對應表。(http://blog.csdn.net/fengsh998/article/details/8614486)
? ? 也就是說方法編號SEL最后還是要通過Dispatch table表尋找到對應的IMP话速,IMP就是一個函數(shù)指針讶踪,然后執(zhí)行這個方法
事件的傳遞與響應:
1、當一個事件發(fā)生后泊交,事件會從父控件傳給子控件乳讥,也就是說由UIApplication -> UIWindow -> UIView -> initial view,以上就是事件的傳遞,也就是尋找最合適的view的過程廓俭。
2云石、接下來是事件的響應。首先看initial view能否處理這個事件研乒,如果不能則會將事件傳遞給其上級視圖(inital view的superView)汹忠;如果上級視圖仍然無法處理則會繼續(xù)往上傳遞;一直傳遞到視圖控制器view controller雹熬,首先判斷視圖控制器的根視圖view是否能處理此事件宽菜;如果不能則接著判斷該視圖控制器能否處理此事件,如果還是不能則繼續(xù)向上傳 遞竿报;(對于第二個圖視圖控制器本身還在另一個視圖控制器中铅乡,則繼續(xù)交給父視圖控制器的根視圖,如果根視圖不能處理則交給父視圖控制器處理)烈菌;一直到 window阵幸,如果window還是不能處理此事件則繼續(xù)交給application處理,如果最后application還是不能處理此事件則將其丟棄
3芽世、在事件的響應中挚赊,如果某個控件實現(xiàn)了touches…方法,則這個事件將由該控件來接受济瓢,如果調用了[supertouches….];就會將事件順著響應者鏈條往上傳遞咬腕,傳遞給上一個響應者;接著就會調用上一個響應者的touches….方法葬荷。
事件的傳遞和響應的區(qū)別:
? ? 事件的傳遞是從上到下(父控件到子控件),事件的響應是從下到上(順著響應者鏈條向上傳遞:子控件到父控件纽帖。
?1宠漩、事件傳遞查找到用戶點擊的視圖(C)后,當前視圖(C)是否能夠響應觸摸事件(處理觸摸事件)懊直。
?2扒吁、如果不能響應觸摸事件,則交給當前視圖(C)的父視圖來響應室囊。
?3雕崩、如果父視圖不能響應觸摸事件魁索,則由父視圖的父視圖來響應。
?4盼铁、若最后誰都不對此觸摸事件做處理粗蔚,則丟棄此事件。
hitTest:用來找出最適合響應事件的視圖饶火。
1鹏控、首先在當前視圖的hitTest方法中調用pointInside方法判斷觸摸點是否在當前視圖內
2、若pointInside方法返回NO肤寝,說明觸摸點不在當前視圖內当辐,則當前視圖的hitTest返回nil,該視圖不處理該事件
3鲤看、若pointInside方法返回YES缘揪,說明觸摸點在當前視圖內,則從最上層的子視圖開始(即從subviews數(shù)組的末尾向前遍歷)义桂,遍歷當前視圖的所有子視圖找筝,調用子視圖的hitTest方法重復步驟1-3
4、直到有子視圖的hitTest方法返回非空對象或者全部子視圖遍歷完畢
5澡刹、若第一次有子視圖的hitTest方法返回非空對象呻征,則當前視圖的hitTest方法就返回此對象,處理結束
6罢浇、若所有子視圖的hitTest方法都返回nil陆赋,則當前視圖的hitTest方法返回當前視圖本身,最終由該對象處理觸摸事件
http://www.reibang.com/p/4fea8fa60d75
屬性的實質是什么嚷闭?包括哪幾個部分攒岛?屬性默認的關鍵字都有哪些?@dynamic關鍵字和@synthesize關鍵字是用來做什么的胞锰?
屬性的實質:@property = ivar + getter + setter -> 實例變量+get方法+set方法,也就是說使用@property 系統(tǒng)會自動生成 成員變量以及setter和getter方法;
?? ? 在普通的OC對象中,@property就是編譯其自動幫我們生成一個私有的成員變量和setter與getter方法的聲明和實現(xiàn)灾锯。
包括:實例變量+get方法+set方法
@synthesize和@dynamic分別有什么作用?
答:
@property有兩個對應的詞嗅榕,一個是@synthesize顺饮,一個是@dynamic。如果@synthesize和@dynamic都沒寫凌那,那么默認的就是@syntheszie var = _var;
@synthesize的語義是如果你沒有手動實現(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)綁定。
tableview
tableview的delegate和datasource執(zhí)行順序
1.//有多少列?
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
2.//cell 頁眉高度?
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
3.//cell頁腳高度?
-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
4.//每組有多少行?
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
5.//cell高度?
-(CGFloat)tableView:(UITableView )tableView heightForRowAtIndexPath:(NSIndexPath )indexPath
6.//布局UItableviewcell?
-(UITableViewCell )tableView:(UITableView )tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
UITableViewCell的可重用機制
1.使用可重用機制創(chuàng)建cell(系統(tǒng))
1)定義可重用標識
2)從可重用隊列中取出cell
3)若隊列中無可用cell骆捧,利用alloc澎羞,init新建cell
原理
在UITableView的頭文件中有visibleCells,存放當前顯示的的cells
@property (nonatomic,readonly)NSArray<__kindofUITableViewCell *> *visibleCells;
當需要更新顯示數(shù)據(jù)時敛苇,dequeueReusableCellWithIdentifier會先在可重用cell隊列?reusable-cell queue中返回一個cell對象妆绞,若不存在宿稀,則返回nil邓夕;
存在的問題
重取出來的cell是有可能已經(jīng)捆綁過數(shù)據(jù)或者加過子視圖的,造成視圖疊加混亂的現(xiàn)象
解決:
1)刪除已有數(shù)據(jù)或子視圖
2)放棄了重用機制恕洲,每次根據(jù)indexPath獲取對應的cell返回来涨。
將方法:??UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIndentifier];
替換為: ?UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];?
tableView滑動為什么會卡頓图焰?
cell賦值內容時,會根據(jù)內容設置布局蹦掐,也就可以知道cell的高度技羔,若有1000行,就會調用1000次 cellForRow方法卧抗,而我們對cell的處理操作藤滥,都是在這個方法中賦值,布局等等社裆,開銷很大拙绊。
優(yōu)化總結
1.提前計算并緩存好高度,因為heightForRow最頻繁的調用泳秀。
2.異步繪制标沪,遇到復雜界面,性能瓶頸時嗜傅,可能是突破口谨娜。
3.滑動時按需加載,這個在大量圖片展示磺陡,網(wǎng)絡加載時,很管用。(SDWebImage已經(jīng)實現(xiàn)異步加載)币他。
4.重用cells坞靶。
5.如果cell內顯示得內容來自web,使用異步加載蝴悉,緩存結果請求彰阴。
6.少用或不用透明圖層,使用不透明視圖拍冠。
7.盡量使所有的view opaque尿这,包括cell本身。
8.減少subViews
9.少用addView給cell動態(tài)添加view庆杜,可以初始化的時候就添加射众,然后通過hide控制是否顯示。
Objective-C 中 Block 有三種類型:
1晃财、NSGlobalBlock
? ? block內部沒有引用外部變量的 Block 類型都是 NSGlobalBlock 類型叨橱,存儲于全局數(shù)據(jù)區(qū),由系統(tǒng)管理其內存断盛,retain罗洗、copy、release操作都無效钢猛。
2伙菜、NSStackBlock
? ? block內部引用外部變量,retain命迈、release 操作無效贩绕,存儲于棧區(qū),變量作用域結束時躺翻,其被系統(tǒng)自動釋放銷毀丧叽。MRC 環(huán)境下,[[mutableAarry addObject: blockA]公你,(在arc中不用擔心此問題踊淳,因為arc中會默認將實例化的block拷貝到堆上)在其所在作用域結束也就是函數(shù)出棧后,從mutableAarry中取到的blockA已經(jīng)被回收陕靠,變成了野指針迂尝。正確的做法是先將blockA copy到堆上,然后加入數(shù)組剪芥。支持copy垄开,copy之后生成新的NSMallocBlock類型對象。
3税肪、NSMallocBlock
? ? 如上例中的_block溉躲,[blockA copy]操作后變量類型變?yōu)?NSMallocBlock榜田,支持retain、release锻梳,雖然 retainCount 始終是 1箭券,但內存管理器中仍然會增加、減少計數(shù)疑枯,當引用計數(shù)為零的時候釋放(可多次retain辩块、release 操作驗證)。copy之后不會生成新的對象荆永,只是增加了一次引用废亭,類似retain,盡量不要對Block使用retain操作具钥。
http://www.cocoachina.com/ios/20150601/11970.html
runloop
? ? 一個 RunLoop 包含若干個 Mode豆村,每個 Mode 又包含若干個 Source/Timer/Observer。每次調用 RunLoop 的主函數(shù)時氓拼,只能指定其中一個 Mode你画,這個Mode被稱作 CurrentMode。如果需要切換 Mode桃漾,只能退出 Loop坏匪,再重新指定一個 Mode 進入。這樣做主要是為了分隔開不同組的 Source/Timer/Observer撬统,讓其互不影響适滓。
作用:
1、等待用戶操作
2恋追、決定處理事件
3凭迹、調用解耦
4、節(jié)省cpu時間(沒事的時候等待)
? ? 一般來講苦囱,一個線程一次只能執(zhí)行一個任務嗅绸,執(zhí)行完成后線程就會退出。如果我們需要一個機制撕彤,讓線程能隨時處理事件但并不退出鱼鸠,所以,RunLoop 實際上就是一個對象羹铅,這個對象管理了其需要處理的事件和消息蚀狰,并提供了一個入口函數(shù)來執(zhí)行上面 Event Loop 的邏輯。線程執(zhí)行了這個函數(shù)后职员,就會一直處于這個函數(shù)內部 "接受消息->等待->處理" 的循環(huán)中麻蹋,直到這個循環(huán)結束(比如傳入 quit 的消息),函數(shù)返回焊切。
NSTimer與Runloop的關系
?? ? 我們前面做演示的代碼創(chuàng)建的NSTimer會默認為我們添加到Runloop的NSDefaultRunLoopMode中扮授,而且由于是在主線程中芳室,所以Runloop是開啟的,不需要我們手動打開刹勃。
? ? 在我們進行多線程編程時渤愁,所有的Source都需要添加到Runloop中才能生效,對于我們的NSTimer當然也需要添加到Runloop中才能生效深夯,NSTimer也在source里。如果一個Runloop中沒有任何Source的話诺苹,會立即退出的咕晋。而主線程的Runloop在程序運行時,系統(tǒng)就已經(jīng)為我們添加了很多Source到Runloop中收奔,所以主線程的Runloop是一直存在的掌呜,我們可以通過打印MainThread中的Runloop來查看所包含的Source。
NSTimer添加到Runloop中坪哄,但是不運行
? ? 在iOS多線程中质蕉,每一個線程都有一個Runloop,但是只有主線程的Runloop默認是打開的翩肌,其他子線程也就是我們創(chuàng)建的線程的Runloop默認是關閉的模暗,需要我們手動運行。
? ? 我們可以通過[NSRunLoop currentRunLoop]來獲得當前線程的Runloop念祭,并且調用[runloop addTimer:timer forMode:NSDefaultRunLoopMode]方法將定時器添加到Runloop中兑宇,最后一定不要忘記調用Runloop的run方法將當前Runloop開啟,否則NSTimer永遠也不會運行粱坤。
http://www.reibang.com/p/32265cbb2a26
Autorelease
UIKit通過RunLoopObserver在Runloop倆次sleep間對AutoreleasePool進行pop和push隶糕,將這次loop中產(chǎn)生的Autorelease對象釋放。
AutoreleasePoolPage由雙向鏈表鏈接站玄,每個AutoreleasePoolPage所能存儲的對象有限枚驻,當一個AutoreleasePoolPage滿時會創(chuàng)建另一個AutoreleasePoolPage的對象來存放對象。
objc_autoreleasePoolPush 方法:
void *objc_autoreleasePoolPush(void) {
? ? return AutoreleasePoolPage::push();
}
它調用 AutoreleasePoolPage 的類方法 push株旷,也非常簡單:
static inline void *push() {
?? return autoreleaseFast(POOL_SENTINEL);
}
在這里會進入一個比較關鍵的方法 autoreleaseFast再登,并傳入哨兵對象 POOL_SENTINEL:
static inline id *autoreleaseFast(id obj)
{
?? AutoreleasePoolPage *page = hotPage();
?? if (page && !page->full()) {
?? ? ? return page->add(obj);
?? } else if (page) {
?? ? ? return autoreleaseFullPage(obj, page);
?? } else {
?? ? ? return autoreleaseNoPage(obj);
?? }
}
上述方法分三種情況選擇不同的代碼執(zhí)行:
有 hotPage 并且當前 page 不滿
調用 page->add(obj) 方法將對象添加至 AutoreleasePoolPage 的棧中
有 hotPage 并且當前 page 已滿
調用 autoreleaseFullPage 初始化一個新的頁
調用 page->add(obj) 方法將對象添加至 AutoreleasePoolPage 的棧中
無 hotPage
調用 autoreleaseNoPage 創(chuàng)建一個 hotPage
調用 page->add(obj) 方法將對象添加至 AutoreleasePoolPage 的棧中
最后的都會調用 page->add(obj) 將對象添加到自動釋放池中。
hotPage 可以理解為當前正在使用的 AutoreleasePoolPage灾常。
page->add 添加對象
autoreleaseFullPage(當前 hotPage 已滿)
autoreleaseFullPage 會在當前的 hotPage 已滿的時候調用:
static id *autoreleaseFullPage(id obj, AutoreleasePoolPage *page) {
? ? do {
? ? ? ? if (page->child) page = page->child;
? ? ? ? else page = new AutoreleasePoolPage(page);
? ? } while (page->full());
? ? setHotPage(page);
? ? return page->add(obj);
}
它會從傳入的 page 開始遍歷整個雙向鏈表霎冯,直到:
1、查找到一個未滿的 AutoreleasePoolPage
或者
2钞瀑、使用構造器傳入 parent 創(chuàng)建一個新的 AutoreleasePoolPage
在查找到一個可以使用的 AutoreleasePoolPage 之后沈撞,會將該頁面標記成 hotPage,然后調動上面分析過的 page->add 方法添加對象雕什。
autoreleaseNoPage(沒有 hotPage)
如果當前內存中不存在 hotPage缠俺,就會調用 autoreleaseNoPage 方法初始化一個 AutoreleasePoolPage:
static id *autoreleaseNoPage(id obj) {
? ? AutoreleasePoolPage *page = new AutoreleasePoolPage(nil);
? ? setHotPage(page);
? ? if (obj != POOL_SENTINEL) {
? ? ? ? page->add(POOL_SENTINEL);
? ? }
? ? return page->add(obj);
}
既然當前內存中不存在 AutoreleasePoolPage显晶,就要從頭開始構建這個自動釋放池的雙向鏈表,也就是說壹士,新的 AutoreleasePoolPage 是沒有 parent 指針的磷雇。
初始化之后,將當前頁標記為 hotPage躏救,然后會先向這個 page 中添加一個 POOL_SENTINEL 對象唯笙,來確保在 pop 調用的時候,不會出現(xiàn)異常盒使。
最后崩掘,將 obj 添加到自動釋放池中。
多線程
NSThread?
? ? 這套方案是經(jīng)過蘋果封裝后的少办,并且完全面向對象的苞慢。所以你可以直接操控線程對象,非常直觀和方便英妓。但是挽放,它的生命周期還是需要我們手動管理。
–優(yōu)點:NSThread 比其他兩個輕量級蔓纠,使用簡單
–缺點:需要自己管理線程的生命周期辑畦、線程同步、加鎖贺纲、睡眠以及喚醒等航闺。線程同步對數(shù)據(jù)的加鎖會有一定的系統(tǒng)開銷
https://www.cnblogs.com/wendingding/p/3806821.html
GCD
?GCD有兩種隊列:串行隊列和并行隊列。
? 它是蘋果為多核的并行運算提出的解決方案猴誊,所以會自動合理地利用更多的CPU內核(比如雙核潦刃、四核),最重要的是它會自動管理線程的生命周期(創(chuàng)建線程懈叹、調度任務乖杠、銷毀線程),完全不需要我們管理澄成,我們只需要告訴干什么就行胧洒。同時它使用的也是 c語言,不過由于使用了 Block(Swift里叫做閉包)墨状,使得使用起來更加方便卫漫,而且靈活。
說明:同步函數(shù)不具備開啟線程的能力肾砂,無論是什么隊列都不會開啟線程列赎;異步函數(shù)具備開啟線程的能力,開啟幾條線程由隊列決定(串行隊列只會開啟一條新的線程镐确,并發(fā)隊列會開啟多條線程)
同步函數(shù)
(1)并發(fā)隊列:不會開線程
(2)串行隊列:不會開線程
異步函數(shù)
(1)并發(fā)隊列:能開啟N條線程
(2)串行隊列:開啟1條線程
https://www.cnblogs.com/zh-li/p/5140610.html
http://ios.jobbole.com/82622/
GCD死鎖的幾種情況
經(jīng)典:
NSLog(@"1"); // 任務1
dispatch_sync(dispatch_get_main_queue(), ^{
????NSLog(@"2"); // 任務2
});
NSLog(@"3"); // 任務3
分析:
1 dispatch_sync表示是一個同步線程包吝;
2 dispatch_get_main_queue表示運行在主線程中的主隊列饼煞;
3 任務2是同步線程的任務。
?? ? 首先執(zhí)行任務1诗越,這是肯定沒問題的砖瞧,只是接下來,程序遇到了同步線程嚷狞,那么它會進入等待块促,等待任務2執(zhí)行完,然后執(zhí)行任務3床未。但這是隊列褂乍,有任務來,當然會將任務加到隊尾即硼,然后遵循FIFO原則執(zhí)行任務。那么屡拨,現(xiàn)在任務2就會被加到最后只酥,任務3排在了任務2前面,
問題來了:
?? ? 任務3要等任務2執(zhí)行完才能執(zhí)行呀狼,任務2由排在任務3后面裂允,意味著任務2要在任務3執(zhí)行完才能執(zhí)行,所以他們進入了互相等待的局面哥艇【啵【既然這樣,那干脆就卡在這里吧】這就是死鎖貌踏。
NSOperation和NSOperationQueue
? ? NSOperation 是蘋果公司對 GCD 的封裝十饥,完全面向對象,不需要關心線程管理祖乳,數(shù)據(jù)同步的事情逗堵,可以把精力放在自己需要執(zhí)行的操作上,所以使用起來更好理解眷昆。 大家可以看到 NSOperation 和 NSOperationQueue 分別對應 GCD 的 任務 和 隊列 蜒秤。
?? ? NSOperation 只是一個抽象類,所以不能封裝任務亚斋。但它有 2 個子類用于封裝任務作媚。分別是:NSInvocationOperation 和 NSBlockOperation 。
NSOperationQueue與cancel
? ? 對于NSOperationQueue,只有add到NSOperationQueue的NSOperation才能夠執(zhí)行帅刊,關于cancel纸泡,NSOperation的cancel 并不是立即取消掉,而是過一會厚掷,?
? ? 最重要的是無論是NSOperation的cancel還是NSOperationQueue的cancelAllOperations弟灼,都不會停止正在執(zhí)行的operation级解,只能取消在隊列中等待的operation
NSOperationQueue串行隊列
? ? NSOperationQueue可以設置設置線程池中的線程數(shù),也就是并發(fā)操作數(shù)田绑。默認情況下是-1勤哗,也就是沒有限制,同時運行隊列中的全部操作掩驱。設置為1即為串行芒划,即當前只能執(zhí)行單個task,以及FIFO原則執(zhí)行完了之后再執(zhí)行下一個欧穴。
OC 中load方法和initialize方法的異同
+load:
?? 對于加入運行期系統(tǒng)中的每個類(class)及分類(category)來說民逼,都會調用此方法,且只會調用一次涮帘。如果分類和其所屬的類都調用了load方法拼苍,則先調用類里面的,再調用分類里的调缨。
load方法并不像普通方法那樣疮鲫,它并不遵從繼承規(guī)則。即如果某個類本身沒有l(wèi)oad方法弦叶,那么不管其超類是否實現(xiàn)load方法俊犯,系統(tǒng)都不會調用。
子類 +load 方法等父類先執(zhí)行完 +load 方法才執(zhí)行伤哺。?
分類 +load 方法會在它的主類 +load 方法之后執(zhí)行燕侠。
+initialize:
?? ? 對每個類來說,該方法會在程序首次使用該類前調用立莉,且只調用一次绢彤。它是由運行期系統(tǒng)來調用的,絕不應該通過代碼直接調用蜓耻。
initialize方法與其他消息一樣杖虾,如果某個類未實現(xiàn)它,而其超類實現(xiàn)了媒熊,就會運行超類的實現(xiàn)代碼奇适。
load和initialize之間的區(qū)別如下:
initialize是”惰性調用的”,即只有當用到了相關的類時芦鳍,才會調用嚷往。如果某個類一直都沒有使用,則其initialize方法就一直不會運行柠衅。這也就是說皮仁,應用程序無須把每個類的initialize都執(zhí)行一遍。?
這就與load不同,對于load來說贷祈,應用程序必須阻塞并等待所有類的load都執(zhí)行完趋急,才能繼續(xù)。
initialize在運行期系統(tǒng)執(zhí)行該方法時势誊,是處于正常狀態(tài)呜达,因此從運行期系統(tǒng)完整度上來講,此時可以安全使用并調用任意類中的任意方法粟耻。而且查近,運行期系統(tǒng)也能保證initialize方法一定會在“線程安全的環(huán)境(thread-safe environment)”中執(zhí)行,這就是說挤忙,只有執(zhí)行initialize的那個線程可以操作類或者類實例霜威。其他線程都要先阻塞,等著initialize執(zhí)行完册烈。?
load方法的問題在于戈泼,執(zhí)行該方法時,運行期系統(tǒng)處于“脆弱狀態(tài)(fragile state)”赏僧。在執(zhí)行子類的load方法之前矮冬,必定會執(zhí)行所有超類的load方法。
http://www.reibang.com/p/14efa33b3562
Block
// OC代碼如下
void(^myBlock)() = ^{
? ? NSLog(@"global = %d", global);
};
// 轉為C++代碼如下
void(*myBlock)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, global));
將變量類型精簡之后C++代碼如下,我們發(fā)現(xiàn)Block變量實際上就是一個指向結構體__main_block_impl_0的指針
_block修飾符
__block在MRC下有兩個作用
1. 允許在Block中訪問和修改局部變量?
2. 禁止Block對所引用的對象進行隱式retain操作
__block在ARC下只有一個作用
允許在Block中訪問和修改局部變量
_block修飾符同樣可以解決block的循環(huán)引用次哈,但是有個必須執(zhí)行的過程,詳見第131頁
SDWebImage
01 設置imageView的圖片
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:app.icon]?
? ? placeholderImage:[UIImage imageNamed:@"placehoder"]];
// 02 設置圖片并計算下載進度
?? //下載并設置圖片
/*
?第一個參數(shù):要下載圖片的url地址
?第二個參數(shù):設置該imageView的占位圖片
?第三個參數(shù):傳一個枚舉值,告訴程序你下載圖片的策略是什么
?第一個block塊:獲取當前圖片數(shù)據(jù)的下載進度
?? ? receivedSize:已經(jīng)下載完成的數(shù)據(jù)大小
?? ? expectedSize:該文件的數(shù)據(jù)總大小
?第二個block塊:當圖片下載完成之后執(zhí)行該block中的代碼
?? ? image:下載得到的圖片數(shù)據(jù)
?? ? error:下載出現(xiàn)的錯誤信息
?? ? SDImageCacheType:圖片的緩存策略(不緩存吆录,內存緩存窑滞,沙盒緩存)
?? ? imageURL:下載的圖片的url地址
?*/
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:app.icon]?
? ? placeholderImage:[UIImage imageNamed:@"placehoder"]?
? ? options:SDWebImageRetryFailed progress:^(NSInteger receivedSize, NSInteger expectedSize) {
? ? //計算當前圖片的下載進度
? ? NSLog(@"%.2f",1.0 *receivedSize / expectedSize);
} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
}];
// 03 系統(tǒng)級內存警告如何處理(面試)
// 利用通知中心觀察(監(jiān)聽系統(tǒng)警告)
? ? - UIApplicationDidReceiveMemoryWarningNotification接收到內存警告的通知
執(zhí)行 clearMemory 方法,清理內存緩存恢筝!
? ? - UIApplicationWillTerminateNotification接收到應用程序將要終止通知
執(zhí)行 cleanDisk 方法哀卫,清理磁盤緩存!(按照文件創(chuàng)建順序:從遠到近)先刪除過去的緩存,計算當前緩存的大小
maxCacheSize設置緩存的大小,默認為0
比較是否大于設定的緩存大小,如果超過,則繼續(xù)刪除,直到小于為止
? ? - UIApplicationDidEnterBackgroundNotification接收到應用程序進入后臺通知
執(zhí)行 backgroundCleanDisk 方法,后臺清理磁盤!
通過以上退出的通知,能夠保證緩存文件的大小始終在控制范圍之內冒版!
clearDisk 清空磁盤緩存嬉荆,將所有緩存目錄中的文件,全部刪除蒋失!
實際工作,將緩存目錄直接刪除,再次創(chuàng)建一個同名空目錄移剪!
04 SDWebImage默認的緩存時間是: 1周
05 SDWebImage的內存緩存是用什么實現(xiàn)的: NSCache
06 SDWebImag的最大并發(fā)數(shù)是: maxConcurrentDownloads = 6是程序固定死了,可以通過屬性進行調整
07 如何播放gif圖片
/*
5-1 把用戶傳入的gif圖片->NSData
5-2 根據(jù)該Data創(chuàng)建一個圖片數(shù)據(jù)源(NSData->CFImageSourceRef)
5-3 計算該數(shù)據(jù)源中一共有多少幀薪者,把每一幀數(shù)據(jù)取出來放到圖片數(shù)組中
5-4 根據(jù)得到的數(shù)組+計算的動畫時間-》可動畫的image
[UIImage animatedImageWithImages:images duration:duration];
*/
08 如何判斷當前圖片類型
+ (NSString *)sd_contentTypeForImageData:(NSData *)data;
09 SDWebImage是如何區(qū)分不同格式的圖像的
? ? ? ? 根據(jù)圖像數(shù)據(jù)第一個字節(jié)來判斷的纵苛!
? ? ? ? PNG:壓縮比沒有JPG高,但是無損壓縮,解壓縮性能高攻人,蘋果推薦的圖像格式取试!
? ? ? ? JPG:壓縮比最高的一種圖片格式,有損壓縮,壓縮的性能不好怀吻!最多使用的場景,照相機解
? ? ? ? GIF:序列楨動圖瞬浓,特點:只支持256種顏色!最流行的時候在1998~1999烙博,有專利的
10 圖片下載順序(先進先出 | 先進先出) 默認是先進先出
下載了圖片后為什么要解碼瑟蜈?
答:由于UIImage的imageWithData函數(shù)是每次畫圖的時候才將Data解壓成ARGB的圖像,所以在每次畫圖的時候渣窜,會有一個解壓操作铺根,這樣效率很低,但是只有瞬時的內存需求乔宿。
?? ? ? 為了提高效率通過SDWebImageDecoder將包裝在Data下的資源解壓位迂,然后畫在另外一張圖片上,這樣這張新圖片就不再需要重復解壓了详瑞。這種做法是典型的空間換時間的做法掂林。
UIView的生命周期總結
1 -[ViewController initWithCoder:]或-[ViewController initWithNibName:Bundle]:首先從歸檔文件中加載UIViewController對象。即使是純代碼坝橡,也會把nil作為參數(shù)傳給后者泻帮。
2 -[UIView awakeFromNib]:作為第一個方法的助手,方便處理一些額外的設置计寇。
3 -[ViewController loadView]:創(chuàng)建或加載一個view并把它賦值給UIViewController的view屬性
4 -[ViewController viewDidLoad]:此時整個視圖層次(view hierarchy)已經(jīng)被放到內存中锣杂,可以移除一些視圖,修改約束番宁,加載數(shù)據(jù)等
5 -[ViewController viewWillAppear:]:視圖加載完成元莫,并即將顯示在屏幕上,還沒有設置動畫,可以改變當前屏幕方向或狀態(tài)欄的風格等蝶押。
6 -[ViewController viewWillLayoutSubviews]:即將開始子視圖位置布局
7 -[ViewController viewDidLayoutSubviews]:用于通知視圖的位置布局已經(jīng)完成
8 -[ViewController viewDidAppear:]:視圖已經(jīng)展示在屏幕上踱蠢,可以對視圖做一些關于展示效果方面的修改。
9 -[ViewController viewWillDisappear:]:視圖即將消失
10 -[ViewController viewDidDisappear:]:視圖已經(jīng)消失
如果考慮UIViewController可能在某個時刻釋放整個view棋电。那么再次加載視圖時顯然會從步驟3開始茎截。因為此時的UIViewController對象依然存在。
為什么IBOutlet修飾的UIView也適用weak關鍵字赶盔?
我們將控件拖到Storyboard上稼虎,相當于創(chuàng)建了一個對象,而這個對象是加到試圖控制器的view上招刨,存放在view的subviews數(shù)組中霎俩。即我們的控件對象是屬于的view的哀军,view對其子控件之前的關系是強引用。當我們使用Outlet屬性的時候打却,這個Outlet屬性是有view來進行強引用的杉适。我們是在viewController中僅僅對其進行使用,沒有必要擁有它柳击,所以使用weak進行修飾猿推。
nonatomic和atomic的區(qū)別?atomic是絕對的線程安全么捌肴?為什么蹬叭?如果不是,那應該如何實現(xiàn)状知?
nonatomic和atomic用來決定編譯器生成的getter和setter操作是否為原子操作秽五。atomic不是絕對的線程安全。atomic的本意是指屬性的存取方法是線程安全的饥悴,并不保證整個對象是線程安全的坦喘。如:
聲明一個NSMutableArray的原子屬性stuff,此時self.stuff 和 self.stuff = otherstuff都是線程安全的西设。但是使用[self.stuff objectAtIndex:index]就不是線程安全的瓣铣。需要用互斥鎖來保證線程安全性。
NSCache
1)NSCache是蘋果官方提供的緩存類贷揽,具體使用和NSMutableDictionary類似棠笑,在AFN和SDWebImage框架中被使用來管理緩存
2)蘋果官方解釋NSCache在系統(tǒng)內存很低時,會自動釋放對象(但模擬器演示不會釋放)
? ? 建議:接收到內存警告時主動調用removeAllObject方法釋放對象
3)NSCache是線程安全的禽绪,在多線程操作中蓖救,不需要對NSCache加鎖
4)NSCache的Key只是對對象進行Strong引用,不是拷貝丐一,在清理的時候計算的是實際大小而不是引用的大小
NSCache優(yōu)于NSDictionary的幾點?
? ? NSCache勝過NSDictionary之處在于淹冰,當系統(tǒng)資源將要耗盡時库车,它可以自動刪減緩存。如果采用普通的字典樱拴,那么就要自己編寫掛鉤柠衍,在系統(tǒng)發(fā)出“低內存”通知時手工刪減緩存。
? ? NSCache并不會“拷貝”鍵晶乔,而是會“保留”它珍坊。此行為用NSDictionary也可以實現(xiàn),然而需要編寫相當復雜的代碼正罢。NSCache對象不拷貝鍵的原因在于:很多時候阵漏,鍵都是不支持拷貝操作的對象來充當?shù)摹R虼耍琋SCache不會自動拷貝鍵履怯,所以說回还,在鍵不支持拷貝操作的情況下,該類用起來比字典更方便叹洲。另外柠硕,NSCache是線程安全的,而NSDictionary則絕對不具備此優(yōu)勢运提。
description方法
http://www.reibang.com/p/08b59e425d2c
什么時候會報unrecognized selector錯誤蝗柔?
1 對象未實現(xiàn)該方法。
2 對象已經(jīng)被釋放民泵。
能否向編譯后得到的類中增加實例變量癣丧?能否向運行時創(chuàng)建的類中添加實例變量?為什么洪灯?
? ? 不能坎缭,能。
? ? 因為編譯后的類已經(jīng)注冊在 runtime 中签钩,類結構體中的 objc_ivar_list 實例變量的鏈表 和 instance_size 實例變量的內存大小已經(jīng)確定掏呼,同時runtime 會調用 class_setIvarLayout 或 class_setWeakIvarLayout 來處理 strong weak 引用。所以不能向存在的類中添加實例變量铅檩;
? ? 運行時創(chuàng)建的類是可以添加實例變量憎夷,調用 class_addIvar 函數(shù)。但是得在調用 objc_allocateClassPair 之后昧旨,objc_registerClassPair 之前拾给,原因同上。
UITableview的優(yōu)化方法
緩存高度兔沃,異步繪制蒋得,減少層級,hide乒疏,減少空間额衙,估算高度,避免離屏渲染怕吴。
有沒有用過運行時窍侧,用它都能做什么?
交換方法转绷,創(chuàng)建類伟件,給新創(chuàng)建的類增加方法,改變isa指針
5议经、AFN為什么添加一條常駐線程斧账?
http://www.reibang.com/p/e59bb8f59302
KVO的使用谴返?實現(xiàn)原理?(為什么要創(chuàng)建子類來實現(xiàn))
?? ? 當觀察某對象 A 時其骄,KVO 機制動態(tài)創(chuàng)建一個對象A當前類的子類亏镰,并為這個新的子類重寫了被觀察屬性 keyPath 的 setter 方法。setter 方法隨后負責通知觀察對象屬性的改變狀況拯爽。
深入剖析:
?? ? Apple使用了 isa 混寫(isa-swizzling)來實現(xiàn) KVO 索抓。當觀察對象A時,KVO機制動態(tài)創(chuàng)建一個新的名為:NSKVONotifying_A 的新類毯炮,該類繼承自對象A的本類逼肯,且 KVO 為 NSKVONotifying_A 重寫觀察屬性的 setter 方法,setter 方法會負責在調用原 setter 方法之前和之后桃煎,通知所有觀察對象屬性值的更改情況篮幢。
(備注: isa 混寫(isa-swizzling)isa:is a kind of ; swizzling:混合为迈,攪合三椿;)
?? ? ①NSKVONotifying_A 類剖析:在這個過程,被觀察對象的 isa 指針從指向原來的 A 類葫辐,被 KVO 機制修改為指向系統(tǒng)新創(chuàng)建的子類 NSKVONotifying_A 類搜锰,來實現(xiàn)當前類屬性值改變的監(jiān)聽;
所以當我們從應用層面上看來耿战,完全沒有意識到有新的類出現(xiàn)蛋叼,這是系統(tǒng)“隱瞞”了對 KVO 的底層實現(xiàn)過程,讓我們誤以為還是原來的類剂陡。但是此時如果我們創(chuàng)建一個新的名為“NSKVONotifying_A”的類()狈涮,就會發(fā)現(xiàn)系統(tǒng)運行到注冊 KVO 的那段代碼時程序就崩潰,因為系統(tǒng)在注冊監(jiān)聽的時候動態(tài)創(chuàng)建了名為 NSKVONotifying_A 的中間類鸭栖,并指向這個中間類了歌馍。
(isa 指針的作用:每個對象都有 isa 指針,指向該對象的類晕鹊,它告訴 Runtime 系統(tǒng)這個對象的類是什么松却。所以對象注冊為觀察者時,isa 指針指向新子類捏题,那么這個被觀察的對象就神奇地變成新子類的對象(或實例)了玻褪。) 因而在該對象上對 setter 的調用就會調用已重寫的 setter肉渴,從而激活鍵值通知機制公荧。
—>我猜,這也是 KVO 回調機制同规,為什么都俗稱KVO技術為黑魔法的原因之一吧:內部神秘循狰、外觀簡潔窟社。
? ? ? ②子類setter方法剖析:KVO 的鍵值觀察通知依賴于 NSObject 的兩個方法:willChangeValueForKey:和 didChangevlueForKey:,在存取數(shù)值的前后分別調用 2 個方法:
被觀察屬性發(fā)生改變之前绪钥,willChangeValueForKey:被調用灿里,通知系統(tǒng)該 keyPath 的屬性值即將變更;當改變發(fā)生后程腹, didChangeValueForKey: 被調用匣吊,通知系統(tǒng)該 keyPath 的屬性值已經(jīng)變更;之后寸潦, observeValueForKey:ofObject:change:context: 也會被調用色鸳。且重寫觀察屬性的 setter 方法這種繼承方式的注入是在運行時而不是編譯時實現(xiàn)的。
? ? KVO為子類的觀察者屬性重寫調用存取方法的工作原理在代碼中相當于:
-(void)setName:(NSString *)newName{?
[self willChangeValueForKey:@"name"];? ? //KVO在調用存取方法之前總調用?
[super setValue:newName forKey:@"name"]; //調用父類的存取方法?
[self didChangeValueForKey:@"name"];? ? //KVO在調用存取方法之后總調用
}
KVC的使用见转?實現(xiàn)原理命雀?(KVC拿到key以后,是如何賦值的斩箫?知不知道集合操作符吏砂,能不能訪問私有屬性,能不能直接訪問_ivar)
kvc最常見的兩種用法就是:1乘客,對私有變量進行賦值? 2狐血,字典轉模型
http://blog.csdn.net/coyote1994/article/details/52454600
http://hl1987.com/2015/12/16/理解Objective-C中的消息發(fā)送/
objective—c消息轉發(fā)機制
objc_msgSend的具體流程如下:
?1、通過isa指針找到所屬類
?2寨典、查找類的cache列表, 如果沒有則下一步
?3氛雪、查找類的”方法列表”
?4、如果能找到與選擇子名稱相符的方法, 就跳至其實現(xiàn)代碼
?5耸成、找不到, 就沿著繼承體系繼續(xù)向上查找
?6报亩、如果能找到與選擇子名稱相符的方法, 就跳至其實現(xiàn)代碼
?7、找不到, 執(zhí)行”消息轉發(fā)”.
消息轉發(fā)
上面我們提到, 如果到最后都找不到, 就會來到消息轉發(fā)井氢,消息轉發(fā)的流程如下:
1弦追、動態(tài)方法解析 : 先問接收者所屬的類, 你看能不能動態(tài)添加個方法來處理這個”未知的消息”? 如果能, 則消息轉發(fā)結束.
2、備胎(后備接收者) : 請接收者看看有沒有其他對象能處理這條消息? 如果有, 則把消息轉給那個對象, 消息轉發(fā)結束.
3花竞、消息簽名 : 這里會要求你返回一個消息簽名, 如果返回nil, 則消息轉發(fā)結束.
4劲件、完整的消息轉發(fā) : 備胎都搞不定了, 那就只能把該消息相關的所有細節(jié)都封裝到一個NSInvocation對象, 再問接收者一次, 快想辦法把這個搞定了. 到了這個地步如果還無法處理, 消息轉發(fā)機制也無能為力了。
OC中給空對象發(fā)送消息程序會Crash嗎约急?
? ? 首先零远,OC中向nil發(fā)消息,程序是不會崩潰的厌蔽。
? ? 因為OC的函數(shù)調用都是通過objc_msgSend進行消息發(fā)送來實現(xiàn)的牵辣,相對于C和C++來說,對于空指針的操作會引起Crash的問題奴饮,而objc_msgSend會通過判斷self來決定是否發(fā)送消息纬向,如果self為nil择浊,那么selector也會為空,直接返回逾条,所以不會出現(xiàn)問題琢岩。視方法返回值,向nil發(fā)消息可能會返回nil(返回值為對象)师脂、0(返回值為一些基礎數(shù)據(jù)類型)或0X0(返回值為id)等担孔。但是對[NSNull null]對象發(fā)送消息時,是會crash的吃警,因為這個NSNull類只有一個null方法攒磨。
? ? 當然,如果一個對象已經(jīng)被釋放了(引用計數(shù)為0了)汤徽,那么這個時候再去調用方法肯定是會Crash的娩缰,因為這個時候這個對象就是一個野指針(指向僵尸對象(對象的引用計數(shù)為0,指針指向的內存已經(jīng)不可用)的指針)了谒府,安全的做法是釋放后將對象重新置為nil拼坎,使它成為一個空指針,大家可以在關閉ARC后手動release對象驗證一下完疫。
iOS數(shù)據(jù)加密方式
md5加密泰鸡、aes加密、base64加密
delegate壳鹤、notification盛龄、KVO各優(yōu)缺點
delegate?的?優(yōu)勢?:
????? 1.非常嚴格的語法。所有將聽到的事件必須是在delegate協(xié)議中有清晰的定義芳誓。
????? 2.如果delegate中的一個方法沒有實現(xiàn)那么就會出現(xiàn)編譯警告/錯誤
????? 3.協(xié)議必須在controller的作用域范圍內定義
? ? ? 4.在一個應用中的控制流程是可跟蹤的并且是可識別的余舶;
????? 5.在一個控制器中可以定義定義多個不同的協(xié)議,每個協(xié)議有不同的delegates
????? 6.沒有第三方對象要求保持/監(jiān)視通信過程锹淌。
????? 7.能夠接收調用的協(xié)議方法的返回值匿值。這意味著delegate能夠提供反饋信息給controller
??????缺點?:
????? 1.需要定義很多代碼:1.協(xié)議定義;2.controller的delegate屬性赂摆;3.在delegate本身中實現(xiàn)delegate方法定義
????? 2.在釋放代理對象時挟憔,需要小心的將delegate改為nil。一旦設定失敗烟号,那么調用釋放對象的方法將會出現(xiàn)內存crash
????? 3.在一個controller中有多個delegate對象绊谭,并且delegate是遵守同一個協(xié)議,但還是很難告訴多個對象同一個事件汪拥,不過有可能达传。
notification?的?優(yōu)勢?:
????? ? 1.不需要編寫多少代碼,實現(xiàn)比較簡單;
??????? 2.對于一個發(fā)出的通知趟大,多個對象能夠做出反應,即1對多的方式實現(xiàn)簡單
??????? 3.controller能夠傳遞context對象(dictionary)铣焊,context對象攜帶了關于發(fā)送通知的自定義的信息
????????缺點?:
??????? 1.在編譯期不會檢查通知是否能夠被觀察者正確的處理逊朽;?
??????? 2.在釋放注冊的對象時,需要在通知中心取消注冊曲伊;
??????? 3.在調試的時候應用的工作以及控制過程難跟蹤叽讳;
??????? 4.需要第三方對喜愛那個來管理controller與觀察者對象之間的聯(lián)系;
??????? 5.controller和觀察者需要提前知道通知名稱坟募、UserInfo dictionary keys岛蚤。如果這些沒有在工作區(qū)間定義,那么會出現(xiàn)不同步的情況懈糯;
??????? 6.通知發(fā)出后涤妒,controller不能從觀察者獲得任何的反饋信息。
KVO?的?優(yōu)勢?:
???????? 1.能夠提供一種簡單的方法實現(xiàn)兩個對象間的同步赚哗。例如:model和view之間同步她紫;
???????? 2.能夠對非我們創(chuàng)建的對象,即內部對象的狀態(tài)改變作出響應屿储,而且不需要改變內部對象(SKD對象)的實現(xiàn)贿讹;
???????? 3.能夠提供觀察的屬性的最新值以及先前值;
???????? 4.用key paths來觀察屬性够掠,因此也可以觀察嵌套對象民褂;
???????? 5.完成了對觀察對象的抽象,因為不需要額外的代碼來允許觀察值能夠被觀察
????????缺點?:
???????? 1.我們觀察的屬性必須使用strings來定義疯潭。因此在編譯器不會出現(xiàn)警告以及檢查赊堪;
???????? 2.對屬性重構將導致我們的觀察代碼不再可用;
???????? 3.復雜的“IF”語句要求對象正在觀察多個值竖哩。這是因為所有的觀察代碼通過一個方法來指向雹食;
???????? 4.當釋放觀察者時不需要移除觀察者。
1.??效率?肯定是delegate比NSNotification高期丰。
delegate方法比notification更加直接群叶,最典型的特征是,delegate方法往往需要關注返回值钝荡, 也就是delegate方法的結果街立。比如-windowShouldClose:,需要關心返回的是yes還是no埠通。所以delegate方法往往包含 should這個很傳神的詞赎离。也就是好比你做我的delegate,我會問你我想關閉窗口你愿意嗎端辱?你需要給我一個答案梁剔,我根據(jù)你的答案來決定如何做下一 步虽画。相反的,notification最大的特色就是不關心接受者的態(tài)度荣病, 我只管把通告放出來码撰,你接受不接受就是你的事情,同時我也不關心結果个盆。所以notification往往用did這個詞匯脖岛,比如 NSWindowDidResizeNotification,那么NSWindow對象放出這個notification后就什么都不管了也不會等待接受者的反應颊亮。
2柴梆、KVO和NSNotification的區(qū)別?:
和delegate一樣,KVO和NSNotification的作用也是類與類之間的通信终惑,與delegate不同的是1)這兩個都是負責發(fā)出通知绍在,剩下的事情就不管了,所以沒有返回值雹有;2)delegate只是一對一揣苏,而這兩個可以一對多。這兩者也有各自的特點件舵。
NSUrlSession與NSURLConnection區(qū)別
http://www.reibang.com/p/5c09d6976d8b
為什么棄用NSURLConnection?
1卸察、NSUrlSession不用每次都新建tcp鏈接。2铅祸、NSUrlSession速度更快坑质。3、NSUrlSession更加安全临梗。
http://www.reibang.com/p/079e5cf0f014
UIView 和 CALayer 的關系如何涡扼?他們分別負責什么功能?為什么這樣設計盟庞?
1.首先UIView可以響應事件吃沪,Layer不可以.
2.一個 Layer 的 frame 是由它的 anchorPoint,position,bounds,和 transform 共同決定的,而一個 View 的 frame 只是簡單的返回 Layer的 frame什猖,同樣 View 的 center和 bounds 也是返回 Layer 的一些屬性砰盐。
3.UIView主要是對顯示內容的管理而 CALayer 主要側重顯示內容的繪制辞嗡。
4.在做 iOS 動畫的時候队贱,修改非 RootLayer的屬性(譬如位置兔朦、背景色等)會默認產(chǎn)生隱式動畫,而修改UIView則不會摇零。
view負責了與人的動作交互以及對layer的管理推掸,layer則負責了所有能讓人看到的東西。
uiview super class:UIResponder
calayer? super class:NSObject
uiresponder? super class:NSObject
http://www.cnblogs.com/flyFreeZn/p/4264220.html
ARC內存管理技術要點
http://www.reibang.com/p/17e158a666b1
http://www.reibang.com/p/927c8384855a
runtime機制
?? ? 我們寫的代碼在程序運行過程中都會被轉化成runtime的C代碼執(zhí)行,例如[target doSomething];會被轉化成objc_msgSend(target, @selector(doSomething));谅畅。
?? ? OC中一切都被設計成了對象登渣,我們都知道一個類被初始化成一個實例,這個實例是一個對象毡泻。實際上一個類本質上也是一個對象胜茧,在runtime中用結構體表示。
//類在runtime中的表示
struct objc_class {
? ? Class isa;//指針牙捉,顧名思義,表示是一個什么敬飒,
? ? //實例的isa指向類對象邪铲,類對象的isa指向元類
#if !__OBJC2__
? ? Class super_class;? //指向父類
? ? const char *name;? //類名
? ? long version;
? ? long info;
? ? long instance_size
? ? struct objc_ivar_list *ivars //成員變量列表
? ? struct objc_method_list **methodLists; //方法列表
? ? struct objc_cache *cache;//緩存
? ? //一種優(yōu)化,調用過的方法存入緩存列表无拗,下次調用先找緩存
? ? struct objc_protocol_list *protocols //協(xié)議列表
? ? #endif
} OBJC2_UNAVAILABLE;
http://www.reibang.com/p/a6b675f4d073
方法交換
OC中每個方法的名字(SEL)跟函數(shù)的實現(xiàn)(IMP)是一一對應带到,Swizzle的原理只是在這個地方做下手腳,將原來方法名與實現(xiàn)的指向交叉處理英染,就能達到一個新的效果揽惹。
靜態(tài)庫和動態(tài)庫
framework為什么既是靜態(tài)庫又是動態(tài)庫?
答:系統(tǒng)的.framework是動態(tài)庫四康,我們自己建立的.framework是靜態(tài)庫搪搏。
a與.framework有什么區(qū)別?
答:.a是一個純二進制文件闪金,.framework中除了有二進制文件之外還有資源文件疯溺。
.a文件不能直接使用,至少要有.h文件配合哎垦,.framework文件可以直接使用囱嫩。
.a + .h + sourceFile = .framework。
建議用.framework.
FMDB
?? ? 在多個線程中同時使用一個FMDatabase實例是不明智的漏设。不要讓多個線程分享同一個FMDatabase實例墨闲,它無法在多個線程中同時使用。 如果在多個線程中同時使用一個FMDatabase實例郑口,會造成數(shù)據(jù)混亂等問題鸳碧。所以,請使用 FMDatabaseQueue犬性,它是線程安全的
UIView生命周期
loadView方法
?? loadView方法在UIViewController對象的view屬性被訪問到且為空的時候調用杆兵。這個方法不應該被直接調用,而是由系統(tǒng)自動調用仔夺。它會加載或創(chuàng)建一個view并把它賦值給UIViewController的view屬性琐脏。
viewDidLoad方法
@synthesize 和 @dynamic 分別有什么作用?
1 @property有兩個對應的詞,一個是 @synthesize日裙,一個是 @dynamic吹艇。如果 @synthesize 和 @dynamic 都沒寫,那么默認的就是 @syntheszie var = _var;
2 @synthesize的語義是如果你沒有手動實現(xiàn) setter 方法和 getter 方法昂拂,那么編譯器會自動為你加上這兩個方法受神。
3 @dynamic告訴編譯器:屬性的 setter 與 getter 方法由用戶自己實現(xiàn),不自動生成格侯。(當然對于 readonly 的屬性只需提供 getter 即可)鼻听。假如一個屬性被聲明為 @dynamic var,然后你沒有提供 @setter 方法和 @getter 方法联四,編譯的時候沒問題撑碴,但是當程序運行到 instance.var = someVar,由于缺 setter 方法會導致程序崩潰朝墩;或者當運行到 someVar = var 時醉拓,由于缺 getter 方法同樣會導致崩潰。編譯時沒問題收苏,運行時才執(zhí)行相應的方法亿卤,這就是所謂的動態(tài)綁定。
objc中的類方法和實例方法有什么本質區(qū)別和聯(lián)系
類方法:
1鹿霸,類方法是屬于類對象的 2排吴,類方法只能通過類對象調用 3,類方法中的self是類對象 4,類方法中不能訪問成員變量 5懦鼠,類方法可以調用其他的類方法 6傍念,類方法中不能直接調用對象方法
實例方法:
1,實例方法是屬于實例對象的 2葛闷,實例方法只能通過實例對象調用憋槐,3,實例方法中的self是實例對象 4淑趾,實例方法中可以訪問成員變量 5阳仔,實例方法中直接調用實例方法6,實例方法中可以直接調用類方法(通過類名)
runtime如何通過selector找到對應的IMP地址扣泊?
答:selector是通過方法名去查找近范,而在oc中,類因為runtime會被轉化成結構體延蟹,結構體里的成員變量? structobjc_method_list **methodLists? 里面存儲的是類方法列表和實例方法列表评矩,所以在runtime中,selector是通過找方法列表去找到對應的imp地址阱飘。
struct objc_method_list **methodLists 存儲的內容:http://blog.csdn.net/nynllwp/article/details/49926619
1.首先到該類的方法cache中去尋找斥杜,如果找到了虱颗,返回改函數(shù)
2.如果沒有找到就到該類的方法列表中查找,如果找到了蔗喂,將該IMP返回并且將它加入到cache中緩存起來忘渔,這樣可以節(jié)省再次調用的開銷。
3.如果還沒有找到缰儿,通過該類結構中的super_class指針去它的弗雷的方法列表中尋找畦粮,如果找到了了對應的IMP,返回IMP并加入cache
4.如果在自身及父類的方法列表中都沒有找到,則看是否可以動態(tài)決議(本文先不講)
5.如果動態(tài)方法決議沒有解決乖阵,進入消息轉發(fā)流程(本文先不講)
SEL是否只和方法名有關
答:相同名字的SEL指向同一塊內存地址宣赔,不通的類可以擁有相同的SEL, 根據(jù)同一個SEL找到的對應的IMP是不同的。
直接調用函數(shù)會節(jié)省方法調用時消息傳遞的開銷瞪浸,那么直接調用函數(shù)是否比oc本身的消息傳遞效率更高儒将?
答:在調用次數(shù)少于10000次時,直接調用函數(shù)指針的效率優(yōu)勢并不明顯默终,有時候還是oc的消息傳遞效率更好椅棺,只有循環(huán)次數(shù)非常大的時候犁罩,直接調用函數(shù)指針才有效率優(yōu)勢齐蔽。
http://www.reibang.com/p/700f58eb0b86
copy,MutableCopy的區(qū)別
淺復制:不拷貝對象本身,僅僅是拷貝指向對象的指針床估,一般來說像這種使用’=’號賦值的對象含滴,基本上都是淺復制。
深復制:是直接拷貝整個對象內存到另一塊內存中
? ? copy的字面意思就是“復制”丐巫,它是產(chǎn)生一個副本的過程谈况,再來看在iOS里,copy與mutableCopy都是NSObject里的方法递胧,一個NSObject的對象要想使用這兩個函數(shù)碑韵,那么類必須實現(xiàn)NSCopying協(xié)議或NSMutableCopying協(xié)議,并且是實現(xiàn)了一般來說我們用的很多系統(tǒng)里的容器類已經(jīng)實現(xiàn)了這些方法缎脾。
copy到底是深拷貝還是淺拷貝祝闻?
答:我相信有的同學認為只要是使用copy關鍵字,那么肯定都是深拷貝遗菠,這樣是很不嚴謹?shù)牧捅热缟蟼€例子,雖然使用了copy辙纬,但是指針地址是一樣豁遭,那么它就應該是淺拷貝。
所以是否是深淺拷貝贺拣,是否創(chuàng)建新的對象蓖谢,是由程序運行的環(huán)境所造成的捂蕴,并不是一概而論。
NSString為什么用的copy
?? ? 假如有一個NSMutableString,現(xiàn)在用他給一個retain修飾 NSString賦值,那么只是將NSString指向了NSMutableString所指向的位置,并對NSMUtbaleString計數(shù)器加一,此時,如果對NSMutableString進行修改,也會導致NSString的值修改,原則上這是不允許的. 如果是copy修飾的NSString對象,在用NSMutableString給他賦值時,會進行深拷貝,及把內容也給拷貝了一份,兩者指向不同的位置,即使改變了NSMutableString的值,NSString的值也不會改變.
? ? 所以用copy是為了安全,防止NSMutableString賦值給NSString時,前者修改引起后者值變化而用的.
高效圓角
第一種:設置CALayer的cornerRadius
?imageView.image = [UIImage imageNamed:@"img"];
?imageView.image.layer.cornerRadius = 5;
?imageView.image.layer.masksToBounds =YES;
這樣設置會觸發(fā)離屏渲染蜈抓,比較消耗性能启绰。比如當一個頁面上有十幾頭像這樣設置了圓角
會明顯感覺到卡頓。
這種就是最常用的沟使,也是最耗性能的委可。
注意:ios9.0之后對UIImageView的圓角設置做了優(yōu)化,UIImageView這樣設置圓角
不會觸發(fā)離屏渲染腊嗡,ios9.0之前還是會觸發(fā)離屏渲染着倾。而UIButton還是都會觸發(fā)離屏渲染。
第二種
imageView.clipsToBounds = YES;
imageView.layer setCornerRadius:50];
imageView.layer.shouldRasterize = YES;
shouldRasterize=YES設置光柵化燕少,可以使離屏渲染的結果緩存到內存中存為位圖卡者, 使用的時候直接使用緩存,節(jié)省了一直離屏渲染損耗的性能客们。
但是如果layer及sublayers常常改變的話崇决,它就會一直不停的渲染及刪除緩存重新 創(chuàng)建緩存,所以這種情況下建議不要使用光柵化底挫,這樣也是比較損耗性能的恒傻。
第三種 :通過Core Graphics重新繪制帶圓角的視圖
這種方式性能最好,但是UIButton上不知道怎么繪制建邓,可以用UIimageView添加個 點擊手勢當做UIButton使用
@implementation UIImage (CircleImage)
- (UIImage *)drawCircleImage {
?? UIGraphicsBeginImageContextWithOptions(self.bounds.size,NO, [UIScreen mainScreen].scale);?
?? [[UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:50] addClip];?
?? [self drawInRect:self.bounds];?
?? UIImage *output = UIGraphicsGetImageFromCurrentImageContext();
?? UIGraphicsEndImageContext();
?? return output;?
}
?@end
//在需要圓角時調用如下
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
? ? UIImage *img = [[UIImage imageNamed:@"image.png"] drawCircleImage];
? ? dispatch_async(dispatch_get_main_queue(), ^{
? ? ? ? imageView.image = img;
? ? });
});
四盈厘、通過混合圖層
此方法就是在要添加圓角的視圖上再疊加一個部分透明的視圖,只對圓角部分進行遮擋官边。圖層混合的透明度處理方式與mask正好相反沸手。此方法雖然是最優(yōu)解,沒有離屏渲染注簿,沒有額外的CPU計算契吉,但是應用范圍有限。
總結
1 在可以使用混合圖層遮擋的場景下诡渴,優(yōu)先使用第四種方法捐晶。
2 即使是非iOS9以上系統(tǒng),第一種方法在綜合性能上依然強于后兩者玩徊,iOS9以上由于沒有了離屏渲染更是首選租悄。
3 方法三由于需要大量計算和增加部分內存,需要實際情況各自取舍恩袱。
http://www.cocoachina.com/ios/20170502/19163.html
Category和Extension
Category:
? category只能給某個已有的類擴充方法泣棋,不能擴充成員變量。
? category中也可以添加屬性畔塔,只不過@property只會生成setter和getter的聲明潭辈,不會生成setter和getter的實現(xiàn)以及成員變量鸯屿。
? 如果category中的方法和類中原有方法同名,運行時會優(yōu)先調用category中的方法把敢。也就是寄摆,category中的方法會覆蓋掉類中原有的方法。所以開發(fā)中盡量保證不要讓分類中的方法和原有類中的方法名相同修赞。避免出現(xiàn)這種情況的解決方案是給分類的方法名統(tǒng)一添加前綴婶恼。比如category_。
? 如果多個category中存在同名的方法柏副,運行時到底調用哪個方法由編譯器決定勾邦,最后一個參與編譯的方法會被調用。
調用優(yōu)先級
分類(category) > 本類 > 父類割择。即眷篇,優(yōu)先調用cateory中的方法,然后調用本類方法荔泳,最后調用父類方法蕉饼。 注意:category是在運行時加載的,不是在編譯時玛歌。
Category與屬性和變量:
? ? 在類中昧港,聲明一個屬性,編譯器會自動幫我們生成帶下劃線的成員變量和_ivar以及setter/getter方法沾鳄,ivar會添加到類轉化的結構體的成員變量struct?objc_ivar_list?*ivars里面慨飘,而setter/getter方法則會放到struct?objc_method_list?**methodLists里面确憨。
? ? 由于category是在運行時加載的译荞,不是在編譯時,并且在Runtime中休弃,類會轉化成結構體來表示吞歼,所以轉化的objc_class結構體大小在runtime時期就已經(jīng)是固定的了,已經(jīng)編譯好了塔猾,那么就不可能往這個結構體中添加數(shù)據(jù)篙骡,只能修改。
?? 所謂的可以在Category里面可以添加成員變量僅僅是關聯(lián)了另外一個屬性丈甸,這些東西和之前的類并不在一個內存空間糯俗。
extension:
? ? extension在編譯期決議,它就是類的一部分睦擂。extension在編譯期和頭文件里的@interface以及實現(xiàn)文件里的@implement一起形成一個完整的類得湘,它、extension伴隨類的產(chǎn)生而產(chǎn)生顿仇,亦隨之一起消亡淘正。
? ? extension一般用來隱藏類的私有信息摆马,你必須有一個類的源碼才能為一個類添加extension,所以你無法為系統(tǒng)的類比如NSString添加extension鸿吆,除非創(chuàng)建子類再添加extension囤采。而category不需要有類的源碼,我們可以給系統(tǒng)提供的類添加category惩淳。
? ? extension可以添加實例變量蕉毯,而category不可以。
? ? extension和category都可以添加屬性思犁,但是category的屬性不能生成成員變量和getter恕刘、setter方法的實現(xiàn)。
NSNotification
NSNotification在發(fā)送通知的時候抒倚,是同步褐着。可以使用gcd改成異步托呕。在不使用的時候記住要移除通知含蓉。
iOS消息推送
1、應用程序注冊消息推送项郊。
2馅扣、iOS從APNS Server獲取device token,應用程序接收device token着降。
3差油、應用程序將device token發(fā)送給PUSH服務端程序。
4任洞、服務端程序向APNS服務發(fā)送消息蓄喇。
5、APNS服務將消息發(fā)送給iPhone應用程序交掏。
http://www.reibang.com/p/4db013fa8c02
hook(不是很懂)
不進行在結構體里查找方法的過程妆偏,直接進入到消息轉發(fā)的第一個過程。
在Objective-C中調用一個方法盅弛,其實是向一個對象發(fā)送消息钱骂,查找消息的唯一依據(jù)是selector的名字。利用Objective-C的動態(tài)特性挪鹏,可以實現(xiàn)在運行時偷換selector對應的方法實現(xiàn)见秽,達到給方法掛鉤的目的。
大體分兩步:
1讨盒、直接替換原方法的實現(xiàn)為_objc_msgForward解取。當原來的函數(shù)被調用時,就不會在類方法催植,父類方法列表里查找實現(xiàn)了肮蛹,直接表示找不到勺择,進入轉發(fā)流程。代碼如下:
class_replaceMethod(class, selector, _objc_msgForward, method_getTypeEncoding(targetMethod));
用_objc_msgForward來代替原來的函數(shù)伦忠。
2省核、替換forwardInvocation:的實現(xiàn),當進入轉發(fā)流程時昆码,階段一和階段二都不接手气忠,在階段三forwardInvocation:里會接手。
屏幕渲染
OpenGL中,GPU屏幕渲染有兩種方式.
On-Screen Rendering (當前屏幕渲染)
指的是GPU的渲染操作是在當前用于顯示的屏幕緩沖區(qū)進行.
Off-Screen Rendering (離屏渲染)
指的是在GPU在當前屏幕緩沖區(qū)以外開辟一個緩沖區(qū)進行渲染操作.
特殊的離屏渲染:
如果將不在GPU的當前屏幕緩沖區(qū)中進行的渲染都稱為離屏渲染赋咽,那么就還有另一種特殊的“離屏渲染”方式: CPU渲染旧噪。
如果我們重寫了drawRect方法,并且使用任何Core Graphics的技術進行了繪制操作脓匿,就涉及到了CPU渲染淘钟。整個渲染過程由CPU在App內 同步地完成,渲染得到的bitmap最后再交由GPU用于顯示陪毡。
備注:CoreGraphic通常是線程安全的米母,所以可以進行異步繪制,顯示的時候再放回主線程毡琉,一個簡單的異步繪制過程大致如下
Off-Screen Rendering (離屏渲染)
? ? 離屏渲染的代價很高,想要進行離屏渲染,首選要創(chuàng)建一個新的緩沖區(qū),屏幕渲染會有一個上下文環(huán)境的一個概念,離屏渲染的整個過程需要切換上下文環(huán)境,先從 當前屏幕切換到離屏,等結束后,又要將上下文環(huán)境切換回來.這也是為什么會消耗性能的原因了(有個屏幕和離屏切換的過程)铁瞒。由于垂直同步的機制,如果在一個 HSync(水平同步信號) 時間內桅滋,CPU 或者 GPU 沒有完成內容提交慧耍,則那一幀就會被丟棄,等待下一次機會再顯示丐谋,而這時顯示屏會保留之前的內容不變芍碧。這就是界面卡頓的原因。
?? 當使用圓角笋鄙,陰影师枣,遮罩的時候怪瓶,圖層屬性的混合體被指定為在未預合成之前(下一個HSync信號開始前)不能直接在屏幕中繪制萧落,所以就需要屏幕外渲染。 你可以這么理解. 老板叫我短時間間內做一個 app.我一個人能做,但是時間太短,所以我得讓我朋友一起來幫著我做.(性能消耗: 也就是耗 你跟你朋友之間溝通的這些成本,多浪費啊).但是沒辦法 誰讓你做不完呢.
上下文切換
? ? 上下文切換洗贰,不管是在GPU渲染過程中找岖,還是一直所熟悉的進程切換,上下文切換在哪里都是一個相當耗時的操作敛滋。首先我要保存當前屏幕渲染環(huán)境许布,然后切換到一個新的繪制環(huán)境,申請繪制資源绎晃,初始化環(huán)境蜜唾,然后開始一個繪制杂曲,繪制完畢后銷毀這個繪制環(huán)境,如需要切換到On-Screen
Rendering或者再開始一個新的離屏渲染重復之前的操作袁余。
會離屏渲染的操作
shouldRasterize(光柵化)擎勘、masks(遮罩)、shadows(陰影)颖榜、edge antialiasing(抗鋸齒)棚饵、group opacity(不透明)、復雜形狀設置圓角等掩完、漸變噪漾、Text(UILabel, CATextLayer, Core Text, etc)等
如何檢測我的項目里面離屏渲染?
?*之前看了一些文章說在intruments里面的 CoreAnimation里面有工具.檢測.(沒找著.求補充)
iOS版本上的優(yōu)化
?? iOS 9.0之前UIimageView跟UIButton設置圓角都會觸發(fā)離屏渲染
?? iOS 9.0之后UIButton設置圓角會觸發(fā)離屏渲染且蓬,而UIImageView里png圖片設置圓角不會觸發(fā)離屏渲染了欣硼,如果設置其他陰影效果之類的還是會觸發(fā)離屏渲染的。
?? UIButton設置圓角不觸發(fā)離屏渲染可以使用貝塞爾曲線UIBezierPath和Core Graphics框架畫出一個圓角恶阴。
? ? 這可能是蘋果也意識到離屏渲染會產(chǎn)生性能問題分别,所以能不產(chǎn)生離屏渲染的地方蘋果也就不用離屏渲染了。
http://blog.csdn.net/hopedark/article/details/49640939
@synchronized
@synchronized(obj) {
? ? // do work
}
轉化成這樣的東東
@try {
? ? objc_sync_enter(obj);
? ? // do work
} @finally {
? ? objc_sync_exit(obj);? ?
}
objc_sync_enter 的文檔告訴我們一些新東西: @synchronized 結構在工作時為傳入的對象分配了一個遞歸鎖存淫。
方法和選擇器有何不同耘斩?
答:selector(選擇器)是方法的名字,通過它可以找到方法
? ? ? 方法是相對于對象來說的桅咆,包含名字和實現(xiàn)等括授。
layoutSubview
在以下情況下會被調用:
1、init初始化不會觸發(fā)layoutSubviews
???但是是用initWithFrame?進行初始化時岩饼,當rect的值不為CGRectZero時,也會觸發(fā)
2荚虚、addSubview會觸發(fā)layoutSubviews
3、設置view的Frame會觸發(fā)layoutSubviews籍茧,當然前提是frame的值設置前后發(fā)生了變化
4版述、滾動一個UIScrollView會觸發(fā)layoutSubviews
5、旋轉Screen會觸發(fā)父UIView上的layoutSubviews事件
6寞冯、改變一個UIView大小的時候也會觸發(fā)父UIView上的layoutSubviews事件
什么時候重寫layoutSubviews渴析?
1 自動布局無法滿足要求(例如要自定義一個按鈕,圖片在文字的右側)
2 不要直接調用調用這個方法吮龄,可以調用setNeedsLayout俭茧、layoutIfNeeded。
1漓帚、layoutSubviews
?? ? 在iOS5.1和之前的版本母债,此方法的缺省實現(xiàn)不會做任何事情(實現(xiàn)為空),iOS5.1之后(iOS6開始)的版本,此方法的缺省實現(xiàn)是使用你設置在此view上面的constraints(Autolayout)去決定subviews的position和size毡们。 UIView的子類如果需要對其subviews進行更精確的布局迅皇,則可以重寫此方法。只有在autoresizing和constraint-based behaviors of subviews不能提供我們想要的布局結果的時候衙熔,我們才應該重寫此方法喧半。可以在此方法中直接設置subviews的frame青责。 我們不應該直接調用此方法挺据,而應當用下面兩個方法。
2脖隶、setNeedsLayout (設置成需要布局)
? ? 標記為需要重新布局扁耐,異步調用layoutIfNeeded刷新布局,不立即刷新产阱,在下一輪runloop結束前刷新婉称,對于這一輪runloop之內的所有布局和UI上的更新只會刷新一次,layoutSubviews一定會被調用构蹬。
3王暗、layoutIfNeeded
? ? 使用此方法強制立即進行l(wèi)ayout,從當前view開始,此方法會遍歷整個view層次(包括superviews)請求layout庄敛。因此俗壹,調用此方法會強制整個view層次布局。
關鍵點
layoutIfNeeded不一定會調用layoutSubviews方法藻烤。
setNeedsLayout一定會調用layoutSubviews方法(有延遲绷雏,在下一輪runloop結束前)。
如果想在當前runloop中立即刷新怖亭,調用順序應該是
[self setNeedsLayout];
[self layoutIfNeeded];
反之可能會出現(xiàn)布局錯誤的問題涎显。
http://www.reibang.com/p/915356e280fc
isEquel和hash的關系
NSArray與NSMutableArray
往數(shù)組里加入nil是否會發(fā)生崩潰?
答:NSMutableArray會發(fā)生崩潰現(xiàn)象兴猩。無法往輸入里加入nil對象期吓。NSArray不會喷市,可以在初始化的時候把里面加入nil元素李命。
NSTimer
和block一樣拌喉,會對self進行引用哮兰,如果沒有按照流程釋放的話對造成循環(huán)引用而導致內存泄漏。它由于要對self進行引用饲齐,所以self將不會主動釋放缓窜,從而不會主動調用delloc函數(shù),所以問題就來了拯刁!如果在delloc里面釋放timer是不可取的,因為在沒有外部干涉的條件下它永遠不會調用delloc函數(shù)逝段,所以也就永遠不會釋放timer垛玻,造成內存泄漏割捅!
如果有侵犯到其他作者,請聯(lián)系我刪除帚桩!造成的不便亿驾,十分抱歉!