__block 和 __weak 的區(qū)別:
- __block不管是ARC還是MRC模式下都可以使用弟塞,可以修飾對(duì)象堡僻,還可以修飾基本數(shù)據(jù)類型。
- __weak只能在ARC模式下使用,也只能修飾對(duì)象(NSString)觉至,不能修飾基本數(shù)據(jù)類型(int)蓖谢。
- __block對(duì)象可以在block中被重新賦值, __weak不可以.
- __block對(duì)象在ARC下可能會(huì)導(dǎo)致循環(huán)引用, 非ARC下會(huì)避免循環(huán)引用, __weak只在ARC下使用, 可以避免循環(huán)引用.
assign 和 weak 的區(qū)別
assign 平時(shí)只是用在基本類型的的修飾,比如NSInteger,float等
weak主要用在對(duì)象上,其中尤以代理用的多,幾乎都是用weak; 自身已經(jīng)對(duì)它進(jìn)行一次強(qiáng)引用茁计,沒有必要再?gòu)?qiáng)引用一次時(shí)也會(huì)使用weak星压。比如:自定義 IBOutlet控件屬性一般也使用weak娜膘,當(dāng)然也可以使用strong...
weak修飾的對(duì)象不增加引用計(jì)數(shù),被釋放后自動(dòng)置為nil,而assign修飾的對(duì)象屬于指針賦值,也不會(huì)增加引用計(jì)數(shù),但是在對(duì)象被釋放后,assign修飾的這個(gè)變量并不會(huì)自動(dòng)置為nil, 指針的地址還是存在的, 所以會(huì)導(dǎo)致野指針 (對(duì)象一般分配在堆上的某塊內(nèi)存,如果在后續(xù)的內(nèi)存分配中演怎,剛好分到了這塊地址颤枪,程序就會(huì)崩潰掉畏纲。)
那為什么可以用assign修飾基本數(shù)據(jù)類型盗胀?因?yàn)榛A(chǔ)數(shù)據(jù)類型一般分配在棧上票灰,棧的內(nèi)存會(huì)由系統(tǒng)自己自動(dòng)處理浸策,不會(huì)造成野指針庸汗。
copy 與 深. 淺拷貝
- copy拷貝出來的對(duì)象類型總是不可變類型(例如, NSString, NSDictionary, NSArray等等)
- mutableCopy拷貝出來的對(duì)象類型總是可變類型(例如, NSMutableString, NSMutableDictionary, NSMutableArray等等)
深拷貝 與 淺拷貝
- 深拷貝 : 拷貝出來的對(duì)象與源對(duì)象地址不一致! 這意味著我修改拷貝對(duì)象的值對(duì)源對(duì)象的值沒有任何影響.
-
淺拷貝 : 拷貝出來的對(duì)象與源對(duì)象地址一致! 這意味著我修改拷貝對(duì)象的值會(huì)直接影響到源對(duì)象.
image.png
為什么block要用 copy
block是一個(gè)對(duì)象, 所以block理論上是可以retain/release的. 但是block在創(chuàng)建的時(shí)候它的內(nèi)存是默認(rèn)是分配在棧(stack)上, 而不是堆(heap)上的. 所以它的作用域僅限創(chuàng)建時(shí)候的當(dāng)前上下文(函數(shù), 方法...), 當(dāng)你在該作用域外調(diào)用該block時(shí), 程序就會(huì)崩潰.
RunLoop
當(dāng)定時(shí)器 Timer 加到 mode 為 kCFRunLoopDefaultMode 時(shí),拖拽 UITextview 時(shí)候 Timer 就不起作用了枉昏;當(dāng) mode 為 kCFRunLoopCommonModes 時(shí)兄裂,拖拽 UITextview 不影響 Timer 的使用...
一個(gè)線程對(duì)應(yīng)一個(gè)RunLoop晰奖,RunLoop里面有若干個(gè)mode畅涂,每個(gè)mode都有自己的內(nèi)容,Source/Timer/Observer等等冒萄。而RunLoop有了mode才會(huì)有效果帅戒。注意:mode里面必須要有內(nèi)容B咦 O狗谩扒秸!
要讓RunLoop跑起來,既要有有內(nèi)容的mode写烤,也需要 [[NSRunLoop currentRunLoop] run]; 洲炊。兩個(gè)都不可少选浑。
RunLoop跑起來后相當(dāng)于是一個(gè)while的死循環(huán),后面的代碼不會(huì)執(zhí)行拓提。
GCD
- GCD的好處
- GCD 可用于多核的并行運(yùn)算
- GCD 會(huì)自動(dòng)利用更多的 CPU 內(nèi)核(比如雙核代态、四核)
- GCD 會(huì)自動(dòng)管理線程的生命周期(創(chuàng)建線程蹦疑、調(diào)度任務(wù)艇肴、銷毀線程)
- 程序員只需要告訴 GCD 想要執(zhí)行什么任務(wù)叁温,不需要編寫任何線程管理代碼
- GCD的幾種情況:
- 同步任務(wù) + 并發(fā)隊(duì)列 : 沒有開啟新線程冲九,串行執(zhí)行任務(wù)
- 異步任務(wù) + 并發(fā)隊(duì)列 : 有開啟新線程莺奸,并發(fā)執(zhí)行任務(wù)
- 同步任務(wù) + 串行隊(duì)列 : 沒有開啟新線程灭贷,串行執(zhí)行任務(wù)
- 異步任務(wù) + 串行隊(duì)列 : 有開啟新線程(1條)氧腰,串行執(zhí)行任務(wù)
- 同步任務(wù) + 主隊(duì)列 : 主線程調(diào)用:死鎖卡住不執(zhí)行; 其他線程調(diào)用:沒有開啟新線程古拴,串行執(zhí)行任務(wù)
- 異步任務(wù) + 主隊(duì)列 : 沒有開啟新線程黄痪,串行執(zhí)行任務(wù)
- GCD 柵欄方法:dispatch_barrier _async
在執(zhí)行完柵欄前面的操作之后桅打,才執(zhí)行柵欄操作挺尾,最后再執(zhí)行柵欄后邊的操作遭铺。
特別注意: 不能用全局隊(duì)列: dispatch _get _global _queue , 只能用: dispatch _queue _create 來創(chuàng)建
GCD 延時(shí)執(zhí)行方法:dispatch_after
GCD 一次性代碼(只執(zhí)行一次):dispatch_once
GCD 快速迭代方法:dispatch_apply : 按照指定的次數(shù)將指定的任務(wù)追加到指定的隊(duì)列中甫题,并等待全部隊(duì)列執(zhí)行結(jié)束坠非。
GCD 隊(duì)列組:dispatch_group
- dispatch _group _notify : 當(dāng)所有任務(wù)都執(zhí)行完成之后炎码,才執(zhí)行dispatch _group _notify block 中的任務(wù)辅肾。
- dispatch _group _wait : 暫停當(dāng)前線程(阻塞當(dāng)前線程)矫钓,等待指定的 group 中的任務(wù)執(zhí)行完成后新娜,才會(huì)往下繼續(xù)執(zhí)行概龄。
- dispatch _group _enter私杜、dispatch _group _leave :
- GCD 信號(hào)量:dispatch_semaphore
作用:
- 保持線程同步衰粹,將異步執(zhí)行任務(wù)轉(zhuǎn)換為同步執(zhí)行任務(wù)
- 保證線程安全铝耻,為線程加鎖
進(jìn)程與線程
程序是一個(gè)可以運(yùn)行的文件, 一個(gè)程序至少有一個(gè)進(jìn)程, 一個(gè)進(jìn)程至少有一個(gè)線程, 即主線程.
進(jìn)程
- 正在進(jìn)行的程序被稱為進(jìn)程, 負(fù)責(zé)程序運(yùn)行的內(nèi)存分配, 每個(gè)進(jìn)程都有自己的獨(dú)立虛擬內(nèi)存空間, 一個(gè)程序的一次運(yùn)行, 在執(zhí)行過程中擁有獨(dú)立的內(nèi)存單元, 而多個(gè)線程共享一個(gè)內(nèi)存.
線程
- 線程是進(jìn)程中的基本單元(可執(zhí)行的代碼段), 線程可以并發(fā)運(yùn)行, 提高執(zhí)行效率
- 創(chuàng)建線程的目的: 就是為了開啟一條新的可執(zhí)行的代碼段, 與主線程中的代碼實(shí)現(xiàn)同時(shí)運(yùn)行, 防止界面假死, 是實(shí)現(xiàn)異步的技術(shù)的主要手段, 比如網(wǎng)絡(luò)異步下載...
多線程開發(fā)的優(yōu)缺點(diǎn):
- 好處:
- 使用多線程可以把程序中占據(jù)時(shí)間長(zhǎng)的任務(wù)或耗時(shí)操作放到后臺(tái)去處理, 如圖片 視頻的下載;
- 發(fā)揮多核處理器的優(yōu)勢(shì), 并發(fā)執(zhí)行讓系統(tǒng)運(yùn)行的更快, 更流暢, 用戶體驗(yàn)更好;
- 缺點(diǎn):
- 資源競(jìng)爭(zhēng), 線程安全的問題: 多個(gè)線程會(huì)對(duì)同一資源出現(xiàn)爭(zhēng)奪;
- 內(nèi)存消耗: 更多的線程需要更多的內(nèi)存空間;
- 大量的線程降低代碼的可讀性;
- 死鎖;
空指針和野指針
空指針: 沒有存儲(chǔ)任何內(nèi)存地址的指針;
野指針: 存儲(chǔ)不可用的內(nèi)存地址(或不存在的內(nèi)存地址, 如已被收回釋放) 的指針, 指向的內(nèi)存地址不可用會(huì)報(bào)錯(cuò);
僵尸指針: 野指針的一種情況, 即該指針指向的對(duì)象已經(jīng)被釋放, 但是卻沒有對(duì)當(dāng)前指針賦值為 nil ;
僵尸對(duì)象: 使用已經(jīng)被釋放了的對(duì)象, 若使用了一般會(huì)報(bào)錯(cuò): unrecognized selector sent to instance ;
宏與const的區(qū)別:
宏(define) : 宏只是進(jìn)行簡(jiǎn)單的文本替換, 沒有類型, 也不會(huì)作類型檢查, 不會(huì)報(bào)編譯錯(cuò)誤, 宏是預(yù)編譯(編譯之前處理), 若大量使用宏, 容易造成編譯時(shí)間久; 宏還能定義一些函數(shù), 方法, const不能;
const: 定義常量, 會(huì)有類型檢查; 它是在編譯運(yùn)行階段使用, 會(huì)報(bào)編譯錯(cuò)誤;
static 的作用:
static 聲明局部變量: 則改變變量的存儲(chǔ)方式(生命周期), 使變量成為表態(tài)的局部變量, 即編譯時(shí)就為變量分配內(nèi)存, 直到程序退出才釋放存儲(chǔ)單元. 這樣 使得該局部變量有記憶功能, 可以記憶上次的數(shù)據(jù), 不過由于仍是局部變量, 因而只能在代碼內(nèi)部使用(作用域不變).
static 聲明外部變量: 為了限制某些外部變量的作用域 (外部變量指在所有代碼塊 {} 之外定義的變量, 它本身是靜態(tài)變量, 編譯時(shí)分配內(nèi)存, 程序結(jié)束時(shí)釋放內(nèi)存單元. 同時(shí), 其作用域很廣, 整個(gè)文件都有效, 甚至別的文件也能引用它 ) , 使其只在本文件中有效, 而不能被其他文件引用, 可以用 static 關(guān)鍵字對(duì)其作出聲明.
swfit 和 oc 的區(qū)別
- Swift對(duì)數(shù)據(jù)要求嚴(yán)格泡态,不存在隱式轉(zhuǎn)換兽赁,強(qiáng)制轉(zhuǎn)換格式:int(a);
- swift 使用 private 修飾后, 是用運(yùn)行時(shí)也不能獲取其屬性或函數(shù), 而 oc 則可能...
- nil 指針的使用: swift 中 nil 也是一種類型(可選類型值會(huì) nil), 莫名調(diào)用會(huì)報(bào)錯(cuò), OC則不會(huì)...
- swift 還有命名空間, 泛型, 可選類型 的概念;
@synthesize和@dynamic 的區(qū)別
- @property有兩個(gè)對(duì)應(yīng)的詞刀崖,一個(gè)是@synthesize拍摇,一個(gè)是@dynamic蜂莉。如果@synthesize和@dynamic都沒寫映穗,那么默認(rèn)的就是@syntheszie var = _var;
- @synthesize的語義是如果你沒有手動(dòng)實(shí)現(xiàn)setter方法和getter方法蚁滋,那么編譯器會(huì)自動(dòng)為你加上這兩個(gè)方法辕录。
- @dynamic告訴編譯器,屬性的setter與getter方法由用戶自己實(shí)現(xiàn),不自動(dòng)生成蚣旱。(當(dāng)然對(duì)于readonly的屬性只需提供getter即可)。假如一個(gè)屬性被聲明為@dynamic var枕赵,然后你沒有提供@setter方法和@getter方法拷窜,編譯的時(shí)候沒問題,但是當(dāng)程序運(yùn)行到instance.var =someVar懊昨,由于缺setter方法會(huì)導(dǎo)致程序崩潰酵颁;或者當(dāng)運(yùn)行到 someVar = var時(shí)躏惋,由于缺getter方法同樣會(huì)導(dǎo)致崩潰。編譯時(shí)沒問題扁位,運(yùn)行時(shí)才執(zhí)行相應(yīng)的方法域仇,這就是所謂的動(dòng)態(tài)綁定
- @dynamic其主要的作用就是用在NSManageObject對(duì)象的屬性聲明上,由于此類對(duì)象的屬性一般是從Core Data的屬性中生成的般卑,Core Data框架會(huì)在程序運(yùn)行的時(shí)候?yàn)榇祟悓傩陨蒰etter和Setter方法
動(dòng)態(tài)庫 和 靜態(tài)庫
- 動(dòng)態(tài)庫: .dylib 和 .framework
- 靜態(tài)庫: .a 和 .framework
系統(tǒng)的.framework是動(dòng)態(tài)庫,我們自己建立的.framework是靜態(tài)庫叹谁。
instancetype 和 id 的區(qū)別
- 相同點(diǎn):
都可以作為方法的返回類型
- 不同點(diǎn):
- instancetype可以返回和方法所在類相同類型的對(duì)象焰檩,id只能返回未知類型的對(duì)象兜叨;
- instancetype : 編譯時(shí)判斷數(shù)據(jù)類型; - id : 編譯器不檢查類型, 運(yùn)行時(shí)檢查類型
- id可以作為方法的參數(shù),但instancetype不可以, instancetype只適用于初始化方法和便利構(gòu)造器的返回值類型
Smalltalk : 被稱為 "面向?qū)ο缶幊讨?
imageNamed 和 imageWithContentOfFile的區(qū)別
- 使用imageNamed:加載圖片
- 加載到內(nèi)存后, 會(huì)一直停留在內(nèi)存中, 不會(huì)隨著對(duì)象銷毀而銷毀;
- 加載進(jìn)圖片后, 戰(zhàn)勝的內(nèi)存歸系統(tǒng)管理, 我們無法管理;
- 相同的圖片, 圖片不會(huì)重新加載;
- 加載到內(nèi)存后, 占據(jù)內(nèi)存空間較大;
- 使用 imageWithContentOfFile 加載圖片
- 加載到內(nèi)存中后, 占據(jù)內(nèi)存空間比較小;
- 相同的圖片會(huì)被重新加載到內(nèi)存中;
- 對(duì)象銷毀的時(shí)候, 加載到內(nèi)存中的圖片會(huì)被一起銷毀
結(jié)論:
-
如果圖片較小,并且頻繁使用的圖片,使用imageName:來加載圖片(按鈕圖片/主頁圖片/占位圖)
-
如果圖片較大,并且使用次數(shù)較少,使用 imageWithContentOfFile:來加載(相冊(cè)/版本新特性)
NSCache
- NSCache 的特點(diǎn):
- NSCache是線程安全的
- 在內(nèi)存不足時(shí)NSCache會(huì)自動(dòng)釋放存儲(chǔ)的對(duì)象
- NSCache的鍵key不會(huì)被復(fù)制,所以key不需要實(shí)現(xiàn)NSCopying協(xié)議
- NSCache緩存對(duì)象自身被釋放
- 手動(dòng)調(diào)用removeObjectForKey:方法
- 手動(dòng)調(diào)用removeAllObjects
- 緩存中對(duì)象的個(gè)數(shù)大于countLimit,或屡久,緩存中對(duì)象的總cost值大于totalCostLimit
- 程序進(jìn)入后臺(tái)后
- 收到系統(tǒng)的內(nèi)存警告
幾種常用的鎖 ( iOS 中幾種常用的鎖總結(jié) )
@synchronized
NSLock 對(duì)象鎖
NSRecursiveLock 遞歸鎖
NSConditionLock 條件鎖
pthread_mutex 互斥鎖(C語言)
dispatch_semaphore 信號(hào)量實(shí)現(xiàn)加鎖(GCD)
UIView 的 setNeedsDisplay 與 setNeedsLayout 方法
兩個(gè)方法都是異步執(zhí)行的;
setNeedsDisplay:
setNeedsDisplay 會(huì)自動(dòng)調(diào)用drawRect方法,這樣可以拿到 UIGraphicsGetCurrentContext
setNeedsLayout:
setNeedsLayout會(huì)默認(rèn)調(diào)用layoutSubViews爱榔,可以調(diào)整子視圖的尺寸和位置;
一些UIView方法的調(diào)用情況
NSNumber 與NSValue
- 由于集合里只能存放對(duì)象被环,不可以存放基本數(shù)據(jù)類型,所以我們有時(shí)候需要講一些對(duì)象比如基本數(shù)據(jù)類型,結(jié)構(gòu)體等存到NSDictionary NSArray中搓蚪,我們就需要將這些數(shù)據(jù)類型或結(jié)構(gòu)體包裝成OC對(duì)象蛤售,以便集合能訪問到。常用的用來包裝這些類型的有NSNumber NSValue
- NSNumber只能包裝基本數(shù)據(jù)類型妒潭,比如int, float,char,BOOL等
- NSValue可以包裝任意一個(gè)對(duì)象,包括系統(tǒng)自定義的數(shù)據(jù)結(jié)構(gòu)揣钦,結(jié)構(gòu)體等等
- NSNumber是NSValue的一個(gè)子類
nil / Nil / NULL / NSNull的區(qū)別 ( 參考 )
- nil : 用于表示指向Objective-C中對(duì)象的指針為空
NSString *string = nil;
- Nil : 用于表示Objective-C類(Class)類型的變量值為空
Class anyClass = Nil;
- NULL: NULL表示C指針為空
char * c = NULL;
- NSNull: 一個(gè)Objective-C類
NSArray *arr = [NSArray arrayWithObjects:@"wang",@"zz",[NSNull null],@"foogry"];
內(nèi)存分區(qū)情況
- 代碼區(qū): 用來存放函數(shù)雳灾、二進(jìn)制代碼及最靜態(tài)的東西;
- 數(shù)據(jù)區(qū): 系統(tǒng)運(yùn)行時(shí)申請(qǐng)內(nèi)存并初始化, 系統(tǒng)退出時(shí)由系統(tǒng)釋放; 存放全局變量, 靜態(tài)變量, 常量;
- 堆區(qū): 通過malloc 等函數(shù) 或 new 等操作符動(dòng)態(tài)申請(qǐng)得到, 需要程序員手動(dòng)申請(qǐng)和釋放;
- 棧區(qū): 函數(shù)模塊內(nèi)申請(qǐng), 函數(shù)結(jié)束時(shí)由系統(tǒng)自動(dòng)釋放; 存放局部變量, 函數(shù)參數(shù), 結(jié)構(gòu)體中創(chuàng)建的變量也在棧中匈庭。
- 內(nèi)存泄漏:
用動(dòng)態(tài)存儲(chǔ)分配函數(shù)動(dòng)態(tài)開辟的空間魔熏,在使用完畢后未釋放,結(jié)果導(dǎo)致一直占據(jù)該內(nèi)存單元骡和,不能被任何程序再次使用东囚,直到程序結(jié)束。即所謂內(nèi)存泄漏废境。簡(jiǎn)單的說就是申請(qǐng)了一塊內(nèi)存空間,使用完畢后沒有釋放掉。
它的一般表現(xiàn)方式是程序運(yùn)行時(shí)間越長(zhǎng)片仿,占用內(nèi)存越多,最終用盡全部?jī)?nèi)存,整個(gè)系統(tǒng)崩潰。由程序申請(qǐng)的一塊內(nèi)存,且沒有任何一個(gè)指針指向它,那么這塊內(nèi)存就泄露了舀锨。注意:內(nèi)存泄漏是指堆內(nèi)存的泄漏告私。
- 內(nèi)存溢出:
內(nèi)存溢出就是在程序運(yùn)行的過程中如果一次需要讀取的數(shù)據(jù)超過這個(gè)棧內(nèi)存大小的話就會(huì)出現(xiàn)溢出.所以一般內(nèi)存管理中,需要生成一個(gè)對(duì)象釋放一個(gè)對(duì)象,你想對(duì)這個(gè)對(duì)象執(zhí)行的操作寫在生成和釋放之間.
- 野指針:
對(duì)象內(nèi)存空間已經(jīng)被系統(tǒng)回收番挺,仍然使?指針操作這塊內(nèi)存瀑晒。野指針異常是程序crash的主要原因把介。
iOS系統(tǒng)架構(gòu) 參考鏈接
iOS的系統(tǒng)架構(gòu)分為四層巢墅,由上到下一次為:可觸摸層(Cocoa Touch layer)雀监、媒體層(Media layer)蔚万、核心服務(wù)層(Core Services layer)已卷、核心操作系統(tǒng)層(Core OS layer)
影響app性能的幾個(gè)方面 參考鏈接
- 網(wǎng)絡(luò)性能:
- 內(nèi)存問題:
- 主線程阻塞:
- Offscreen rendering(離屏渲染):
- 圖片的處理:
self 和 super 的區(qū)別: 參考文章
self : 關(guān)鍵字, 代表當(dāng)前方法的調(diào)用者
- 如果是類方法, 代表當(dāng)前類
- 如果是實(shí)例方法, 代表當(dāng)前類的對(duì)象
super :編譯器指令
- 經(jīng)典題目:
@implementation Son : Father
- (id)init
{
self = [super init];
if (self)
{
NSLog(@"%@", NSStringFromClass([self class])); // 返回 Son
NSLog(@"%@", NSStringFromClass([super class])); // 返回 Son
}
return self;
}
@end
TabelView的性能優(yōu)化: 參考鏈接
- 行高一定要緩存! ( 因?yàn)?heightForRowAtIndexPath: 是調(diào)用最頻繁的方法 )
- 不要?jiǎng)討B(tài)創(chuàng)建子視圖,所有的子視圖都預(yù)先創(chuàng)建,如果不需要顯示可以設(shè)置Hidden;
- 所有的子視圖都應(yīng)該添加到 contentView上;
- 所有的子視圖都必須指定背景顏色, 且所有的顏色都不要 alpha;
- 異步加載圖片;
- 離屏渲染的問題
UIView動(dòng)畫與核心動(dòng)畫的區(qū)別埋虹?
- 核心動(dòng)畫只作用在 layer 上;
- 核心動(dòng)畫修改的值都是假像, 它的真實(shí)位置沒有發(fā)生變化
- 什么時(shí)候用 UIView動(dòng)畫 ?
當(dāng)需要與用戶交互時(shí)用 UIView, 不需要與用戶交互時(shí)兩個(gè)都可以...
- 什么情況用核心動(dòng)畫 ?
- 轉(zhuǎn)場(chǎng)動(dòng)畫.
- 幀動(dòng)畫.
- 動(dòng)畫組.