本篇文章是承接上篇文章 iOS 進(jìn)階+面試(二)
二十一、可變數(shù)組與不可變數(shù)組用什么修飾:原因?
地址http://www.lxweimin.com/p/27305b08b0f2
二十二、nsstring 使用什么關(guān)鍵字修飾?
地址http://www.lxweimin.com/p/9b77d61d76fe
二十三、線上項(xiàng)目崩潰,日志處理?
友盟, 集成需要在
-(void)viewWillAppear:(BOOL)animated
-(void)viewWillDisappear:(BOOL)animated
詳解 : 用友盟詳細(xì)說明一下
- 報(bào)表中心中下載錯(cuò)誤
- 將 友盟Crash分析工具與下載的錯(cuò)誤報(bào)表放同一文件夾中, 打開 終端 , 先拖入友盟Crash分析工具** 再拖入 錯(cuò)誤報(bào)表 , 按回車
- 進(jìn)入友盟 個(gè)人中心 -> 錯(cuò)誤分析 -> 錯(cuò)誤列表 -> 點(diǎn)擊列表中錯(cuò)誤進(jìn)入界面
2. 點(diǎn)擊 右上角 進(jìn)入 [報(bào)表中心] 下載該錯(cuò)誤. 將 友盟Crash分析工具與下載的錯(cuò)誤報(bào)表放同一文件夾中, 打開 終端 , 先拖入友盟Crash分析工具 再拖入 錯(cuò)誤報(bào)表 , 按回車.
- 終端 運(yùn)行完成后 , 會(huì)顯示錯(cuò)誤的位置與行數(shù)
二十四、談?wù)劧嗑€程的理解?
- 使用線程可以把程序中占據(jù)時(shí)間長的任務(wù)放到后臺(tái)去處理,如圖片、視頻的下載
- 充分利用系統(tǒng)的多核 發(fā)揮多核處理器的優(yōu)勢(shì),并發(fā)執(zhí)行讓系統(tǒng)運(yùn)行的更快、更流暢,用戶體驗(yàn)更好
缺點(diǎn):
更多的線程需要更多的內(nèi)存空間
當(dāng)多個(gè)線程對(duì)同一個(gè)資源出現(xiàn)爭(zhēng)奪的時(shí)候要注意線程安全的問題。
二十五、iPhone x max這個(gè)你們是怎樣適配的?
iOS11之前導(dǎo)航欄默認(rèn)高度為64pt(這里高度指statusBar + NavigationBar),iOS11之后如果設(shè)置了prefersLargeTitles = YES則為96pt,默認(rèn)情況下還是64pt,但在iPhoneX上由于劉海的出現(xiàn)statusBar由以前的20pt變成了44pt,所以iPhoneX上高度變?yōu)?8pt,如果項(xiàng)目里隱藏了導(dǎo)航欄加了自定義按鈕之類的,這里需要注意適配一下。
之前是按照定義宏變量適配的,這個(gè)感覺每次新出手機(jī)都要重新適配新手機(jī),iOS11 新出安全區(qū)域的概念,這是我們可以根據(jù)安全區(qū)域來適配,
問題:
- 導(dǎo)航欄圖層及對(duì)titleView布局的影響
iOS11之前導(dǎo)航欄的title是添加在UINavigationItemView上面,而navigationBarButton則直接添加在UINavigationBar上面,如果設(shè)置了titleView,則titleView也是直接添加在UINavigationBar上面。iOS11之后,大概因?yàn)閘argeTitle的原因,視圖層級(jí)發(fā)生了變化,如果沒有給titleView賦值,則titleView會(huì)直接添加在_UINavigationBarContentView上面,如果賦值了titleView,則會(huì)把titleView添加在_UITAMICAdaptorView上,而navigationBarButton被加在了_UIButtonBarStackView上,然后他們都被加在了_UINavigationBarContentView上,如圖:
所以如果你的項(xiàng)目是自定義的navigationBar,那么在iOS11上運(yùn)行就可能出現(xiàn)布局錯(cuò)亂的bug,解決辦法是重寫UINavigationBar的layoutSubviews方法,調(diào)整布局,上代碼:
- (void)layoutSubviews {
[super layoutSubviews];
//注意導(dǎo)航欄及狀態(tài)欄高度適配
self.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), naviBarHeight);
for (UIView *view in self.subviews) {
if([NSStringFromClass([view class]) containsString:@"Background"]) {
view.frame = self.bounds;
}
else if ([NSStringFromClass([view class]) containsString:@"ContentView"]) {
CGRect frame = view.frame;
frame.origin.y = statusBarHeight;
frame.size.height = self.bounds.size.height - frame.origin.y;
view.frame = frame;
}
}
}
- UIScrollView、UITableView、UICollectionView
大家在iOS11設(shè)備上運(yùn)行出現(xiàn)最多問題應(yīng)該就是tableview莫名奇妙的偏移20pt或者64pt了。。原因是iOS11棄用了automaticallyAdjustsScrollViewInsets屬性,取而代之的是UIScrollView新增了contentInsetAdjustmentBehavior屬性,這一切的罪魁禍?zhǔn)锥际切乱氲膕afeArea,關(guān)于safeArea適配這篇文章iOS 11 安全區(qū)域適配總結(jié)講的很詳細(xì),感興趣的可以看下,我直接貼適配代碼,因?yàn)榈桶姹局苯佑胏ontentInsetAdjustmentBehavior會(huì)報(bào)警告,所有定義了如下的宏(感謝@炒雞范的指正,之前的宏犯了個(gè)低級(jí)錯(cuò)誤...現(xiàn)改為)
#define adjustsScrollViewInsets(scrollView)\
do {\
_Pragma("clang diagnostic push")\
_Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"")\
if ([scrollView respondsToSelector:NSSelectorFromString(@"setContentInsetAdjustmentBehavior:")]) {\
NSMethodSignature *signature = [UIScrollView instanceMethodSignatureForSelector:@selector(setContentInsetAdjustmentBehavior:)];\
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];\
NSInteger argument = 2;\
invocation.target = scrollView;\
invocation.selector = @selector(setContentInsetAdjustmentBehavior:);\
[invocation setArgument:&argument atIndex:2];\
[invocation retainArguments];\
[invocation invoke];\
}\
_Pragma("clang diagnostic pop")\
}
還有的發(fā)現(xiàn)某些界面tableView的sectionHeader、sectionFooter高度與設(shè)置不符的問題,在iOS11中如果不實(shí)現(xiàn) -tableView: viewForHeaderInSection:和-tableView: viewForFooterInSection: ,則-tableView: heightForHeaderInSection:和- tableView: heightForFooterInSection:不會(huì)被調(diào)用,導(dǎo)致它們都變成了默認(rèn)高度,這是因?yàn)閠ableView在iOS11默認(rèn)使用Self-Sizing,tableView的estimatedRowHeight、estimatedSectionHeaderHeight、 estimatedSectionFooterHeight三個(gè)高度估算屬性由默認(rèn)的0變成了UITableViewAutomaticDimension,解決辦法簡(jiǎn)單粗暴,就是實(shí)現(xiàn)對(duì)應(yīng)方法或把這三個(gè)屬性設(shè)為0。
如果你使用了Masonry,那么你需要適配safeArea
if (@available(iOS 11.0, *)) {
make.edges.equalTo()(self.view.safeAreaInsets)
} else {
make.edges.equalTo()(self.view)
}
- TabBarController
在viewWillAppear時(shí) tabbar高度是49(默認(rèn)高度?)
在viewDidAppear時(shí) tabbar高度是83(真實(shí)準(zhǔn)確高度)
可我在viewDidLoad時(shí)候就開始繪制界面了 如何適配?
具體的實(shí)現(xiàn)邏輯就是寫一個(gè)繼承UITabBarController的類然后修改類里面的方法
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
if (@available(iOS 11.0, *)){
for (UIView *view in self.view.subviews) {
if ([view isKindOfClass:[UITabBar class]]) {
//x的位置不變 y的位置你自己調(diào)調(diào)到UI滿意 寬不變 高也不能變 最終只是改變一下y的相對(duì)位置
view.frame = CGRectMake(view.frame.origin.x, self.view.bounds.size.height-64, view.frame.size.width, 83);
}
}
}
}
之前這么寫有一個(gè)問題,就是會(huì)出現(xiàn)tabbar在push和pop的時(shí)候有上移下移的問題,后來查了一些資料解決了這個(gè)問題,在需要展示tabbar的控制器中添加下面的代碼就可以了
- (void)viewWillDisappear:(BOOL)animated{
if (iPhoneX) {
if (@available(iOS 11.0, *)){
// 修改tabBra的frame
CGRect frame = self.tabBarController.tabBar.frame;
frame.origin.y = [UIScreen mainScreen].bounds.size.height -64;
self.navigationController.tabBarController.tabBar.frame = frame;
}
}
}
- (void)viewWillAppear:(BOOL)animated{
if (iPhoneX) {
if (@available(iOS 11.0, *)){
// 修改tabBra的frame
CGRect frame = self.tabBarController.tabBar.frame;
frame.origin.y = [UIScreen mainScreen].bounds.size.height -64;
self.navigationController.tabBarController.tabBar.frame = frame;
}
}
}
二十六、git的常見命令操作
git pull 拉下項(xiàng)目代碼
git status 查看狀態(tài)
git checkout --readme.txt 把readme.txt文件在工作去的修改全部撤銷
git rm 用于刪除一個(gè)文件
git branch dev 創(chuàng)建dev分支
git checkout dev 跳轉(zhuǎn)到dev分支 //注意當(dāng)前的要先提交然后再跳轉(zhuǎn)
git checkout -b dev 創(chuàng)建并切換到dev分支
git branch 查看當(dāng)前分支
二十七、http中的三次握手和四次揮手?
1:客戶端向服務(wù)器發(fā)出連接請(qǐng)求報(bào)文
2:TCP服務(wù)器收到請(qǐng)求報(bào)文后,如果同意連接,則發(fā)出確認(rèn)報(bào)文
3:TCP客戶進(jìn)程收到確認(rèn)后,還要向服務(wù)器給出確認(rèn)
思考:為什么要三次握手呢,有人說兩次握手就好了?
舉例:已失效的連接請(qǐng)求報(bào)文段。
client發(fā)送了第一個(gè)連接的請(qǐng)求報(bào)文,但是由于網(wǎng)絡(luò)不好,這個(gè)請(qǐng)求沒有立即到達(dá)服務(wù)端,而是在某個(gè)網(wǎng)絡(luò)節(jié)點(diǎn)中滯留了,直到某個(gè)時(shí)間才到達(dá)server,本來這已經(jīng)是一個(gè)失效
的報(bào)文,但是server端接收到這個(gè)請(qǐng)求報(bào)文后,還是會(huì)想client發(fā)出確認(rèn)的報(bào)文,表示同意連接。假如不采用三次握手,那么只要server發(fā)出確認(rèn),新的建立就連接了,但其實(shí)這個(gè)
請(qǐng)求是失效的請(qǐng)求,client是不會(huì)理睬server的確認(rèn)信息,也不會(huì)向服務(wù)端發(fā)送確認(rèn)的請(qǐng)求,但是server認(rèn)為新的連接已經(jīng)建立起來了,并一直等待client發(fā)來數(shù)據(jù),這樣,server的
很多資源就沒白白浪費(fèi)掉了,采用三次握手就是為了防止這種情況的發(fā)生,server會(huì)因?yàn)槭詹坏酱_認(rèn)的報(bào)文,就知道client并沒有建立連接。這就是三次握手的作用。
- TCP的四次揮手 ?
1、TCP發(fā)送一個(gè)FIN(結(jié)束),用來關(guān)閉客戶到服務(wù)端的連接。
2、服務(wù)端收到這個(gè)FIN,他發(fā)回一個(gè)ACK(確認(rèn)),確認(rèn)收到序號(hào)為收到序號(hào)+1,和SYN一樣,一個(gè)FIN將占用一個(gè)序號(hào)
3、 服務(wù)端發(fā)送一個(gè)FIN(結(jié)束)到客戶端,服務(wù)端關(guān)閉客戶端的連接。
4、客戶端發(fā)送ACK(確認(rèn))報(bào)文確認(rèn),并將確認(rèn)的序號(hào)+1,這樣關(guān)閉完成
思考:那么為什么是4次揮手呢?
為了確保數(shù)據(jù)能夠完成傳輸。
關(guān)閉連接時(shí),當(dāng)收到對(duì)方的FIN報(bào)文通知時(shí),它僅僅表示對(duì)方?jīng)]有數(shù)據(jù)發(fā)送給你了;但未必你所有的數(shù)據(jù)都全部發(fā)送給對(duì)方了,所以你可以未必會(huì)馬上會(huì)關(guān)閉SOCKET,也
即你可能還需要發(fā)送一些數(shù)據(jù)給對(duì)方之后,再發(fā)送FIN報(bào)文給對(duì)方來表示你同意現(xiàn)在可以關(guān)閉連接了,所以它這里的ACK報(bào)文和FIN報(bào)文多數(shù)情況下都是分開發(fā)送的。
可能有人會(huì)有疑問,tcp我握手的時(shí)候?yàn)楹蜛CK(確認(rèn))和SYN(建立連接)是一起發(fā)送。揮手的時(shí)候?yàn)槭裁词欠珠_的時(shí)候發(fā)送呢 ????
因?yàn)楫?dāng)Server端收到Client端的SYN連接請(qǐng)求報(bào)文后,可以直接發(fā)送SYN+ACK報(bào)文。其中ACK報(bào)文是用來應(yīng)答的,
思考:客戶端突然掛掉了怎么辦?
正常連接時(shí),客戶端突然掛掉了,如果沒有措施處理這種情況,那么就會(huì)出現(xiàn)客戶端和服務(wù)器端出現(xiàn)長時(shí)期的空閑。解決辦法是在服務(wù)器端設(shè)置保活計(jì)時(shí)器,每當(dāng)服務(wù)器收到
客戶端的消息,就將計(jì)時(shí)器復(fù)位。超時(shí)時(shí)間通常設(shè)置為2小時(shí)。若服務(wù)器超過2小時(shí)沒收到客戶的信息,他就發(fā)送探測(cè)報(bào)文段。若發(fā)送了10個(gè)探測(cè)報(bào)文段,每一個(gè)相隔75秒,
還沒有響應(yīng)就認(rèn)為客戶端出了故障,因而終止該連接。
- 四、TCP和UDP的區(qū)別
我這里簡(jiǎn)單列舉幾個(gè),因?yàn)槲疫€沒有研究UDP這個(gè)協(xié)議。
1、基于連接與無連接;UDP是無連接的,即發(fā)送數(shù)據(jù)之前不需要建立連接
2、TCP保證數(shù)據(jù)正確性
,UDP可能丟包,TCP保證數(shù)據(jù)順序,UDP不保證。也就是說,通過TCP連接傳送的數(shù)據(jù),無差錯(cuò),不丟失,不重復(fù),且按序到達(dá);UDP盡最大努力交付
,即不保證可靠交付Tcp通過校驗(yàn)和,重傳控制,序號(hào)標(biāo)識(shí),滑動(dòng)窗口、確認(rèn)應(yīng)答實(shí)現(xiàn)可靠傳輸。如丟包時(shí)的重發(fā)控制,還可以對(duì)次序亂掉的分包進(jìn)行順序控制。
3、UDP具有較好的實(shí)時(shí)性,工作效率比TCP高
,適用于對(duì)高速傳輸和實(shí)時(shí)性有較高的通信或廣播通信。
4、每一條TCP連接只能是點(diǎn)到點(diǎn)的;UDP支持一對(duì)一,一對(duì)多,多對(duì)一和多對(duì)多的交互通信。
5、TCP對(duì)系統(tǒng)資源要求較多,UDP對(duì)系統(tǒng)資源要求較少。
二十八、IOS 保證線程同步方式&性能對(duì)比
- @synchronized
- NSLock
- NSRecursiveLock
- dispatch_semaphore
- NSCondition
- pthread_mutex
- OSSpinLock。
文章 http://www.lxweimin.com/p/4edf98a61483
二十九、數(shù)據(jù)庫
文章 http://www.lxweimin.com/p/d8b980b41de4
三十、iOS中UITableViewCell的重用機(jī)制原理?
- 重用實(shí)現(xiàn)分析
查看UITableView頭文件,會(huì)找到NSMutableArray* visiableCells
,和NSMutableDictnery* reusableTableCells
兩個(gè)結(jié)構(gòu)。visiableCells內(nèi)保存當(dāng)前顯示的cells,reusableTableCells保存可重 用的cells
TableView顯示之初,reusableTableCells為空,那么tableView dequeueReusableCellWithIdentifier:CellIdentifier返回nil。開始的cell都是通過 [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]來創(chuàng)建,而且cellForRowAtIndexPath只是調(diào)用最大顯示cell數(shù)的 次數(shù)
比如:有100條數(shù)據(jù),iPhone一屏最多顯示10個(gè)cell。程序最開始顯示TableView的情況是:
1. 用[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]創(chuàng)建10次cell,并給cell指定同樣的重用標(biāo)識(shí)(當(dāng)然,可以為不同顯示類型的 cell指定不同的標(biāo)識(shí))。并且10個(gè)cell全部都加入到visiableCells數(shù)組,reusableTableCells為空。
2. 向下拖動(dòng)tableView,當(dāng)cell1完全移出屏幕,并且cell11(它也是alloc出來的,原因同上)完全顯示出來的時(shí)候。cell11加入到 visiableCells,cell1移出visiableCells,cell1加入到reusableTableCells。
3. 接著向下拖動(dòng)tableView,因?yàn)閞eusableTableCells中已經(jīng)有值,所以,當(dāng)需要顯示新的 cell,cellForRowAtIndexPath再次被調(diào)用的時(shí)候,tableView dequeueReusableCellWithIdentifier:CellIdentifier,返回cell1。cell1加入到 visiableCells,cell1移出reusableTableCells;cell2移出visiableCells,cell2加入到 reusableTableCells。之后再需要顯示的Cell就可以正常重用了。
所以整個(gè)過程并不難理解,但需要注意正是因?yàn)檫@樣的原因:配置Cell的時(shí)候一定要注意,對(duì)取出的重用的cell做重新賦值,不要遺留老數(shù)據(jù)
。
- 一些情況
使用過程中,我注意到,并不是只有拖動(dòng)超出屏幕的時(shí)候才會(huì)更新reusableTableCells表,還有:
1. reloadData,這種情況比較特殊。一般是部分?jǐn)?shù)據(jù)發(fā)生變化,需要重新刷新cell顯示的內(nèi)容時(shí)調(diào)用。在 cellForRowAtIndexPath調(diào)用中,所有cell都是重用的。我估計(jì)reloadData調(diào)用后,把visiableCells中所有 cell移入reusableTableCells,visiableCells清空。cellForRowAtIndexPath調(diào)用后,再把 reuse的cell從reusableTableCells取出來,放入到visiableCells。
2. reloadRowsAtIndex,刷新指定的IndexPath。如果調(diào)用時(shí)reusableTableCells為空,那么 cellForRowAtIndexPath調(diào)用后,是新創(chuàng)建cell,新的cell加入到visiableCells。老的cell移出 visiableCells,加入到reusableTableCells。于是,之后的刷新就有cell做reuse了。
三十一、遇到tableView卡頓嘛?會(huì)造成卡頓的原因大致有哪些?
1.最常用的就是cell的重用, 注冊(cè)重用標(biāo)識(shí)符
如果不重用cell時(shí),每當(dāng)一個(gè)cell顯示到屏幕上時(shí),就會(huì)重新創(chuàng)建一個(gè)新的cell
如果有很多數(shù)據(jù)的時(shí)候,就會(huì)堆積很多cell。
如果重用cell,為cell創(chuàng)建一個(gè)ID,每當(dāng)需要顯示cell 的時(shí)候,都會(huì)先去緩沖池中尋找可循環(huán)利用的cell,如果沒有再重新創(chuàng)建cell
2.避免cell的重新布局
cell的布局填充等操作 比較耗時(shí),一般創(chuàng)建時(shí)就布局好
如可以將cell單獨(dú)放到一個(gè)自定義類,初始化時(shí)就布局好
3.提前計(jì)算并緩存cell的屬性及內(nèi)容
當(dāng)我們創(chuàng)建cell的數(shù)據(jù)源方法時(shí),編譯器并不是先創(chuàng)建cell 再定cell的高度
而是先根據(jù)內(nèi)容一次確定每一個(gè)cell的高度,高度確定后,再創(chuàng)建要顯示的cell,滾動(dòng)時(shí),每當(dāng)cell進(jìn)入憑虛都會(huì)計(jì)算高度,提前估算高度告訴編譯器,編譯器知道高度后,緊接著就會(huì)創(chuàng)建cell,這時(shí)再調(diào)用高度的具體計(jì)算方法,這樣可以方式浪費(fèi)時(shí)間去計(jì)算顯示以外的cell
4.減少cell中控件的數(shù)量
盡量使cell得布局大致相同,不同風(fēng)格的cell可以使用不用的重用標(biāo)識(shí)符,初始化時(shí)添加控件,
不適用的可以先隱藏
5.不要使用ClearColor,無背景色,透明度也不要設(shè)置為0
渲染耗時(shí)比較長
6.使用局部更新
如果只是更新某組的話,使用reloadSection進(jìn)行局部更
7.加載網(wǎng)絡(luò)數(shù)據(jù),下載圖片,使用異步加載,并緩存
8.少使用addView 給cell動(dòng)態(tài)添加view
9.按需加載cell,cell滾動(dòng)很快時(shí),只加載范圍內(nèi)的cell
10.不要實(shí)現(xiàn)無用的代理方法,tableView只遵守兩個(gè)協(xié)議
11.緩存行高:estimatedHeightForRow不能和HeightForRow里面的layoutIfNeed同時(shí)存在,這兩者同時(shí)存在才會(huì)出現(xiàn)“竄動(dòng)”的bug。所以我的建議是:只要是固定行高就寫預(yù)估行高來減少行高調(diào)用次數(shù)提升性能。如果是動(dòng)態(tài)行高就不要寫預(yù)估方法了,用一個(gè)行高的緩存字典來減少代碼的調(diào)用次數(shù)即可
12.不要做多余的繪制工作。在實(shí)現(xiàn)drawRect:的時(shí)候,它的rect參數(shù)就是需要繪制的區(qū)域,這個(gè)區(qū)域之外的不需要進(jìn)行繪制。例如上例中,就可以用CGRectIntersectsRect、CGRectIntersection或CGRectContainsRect判斷是否需要繪制image和text,然后再調(diào)用繪制方法。
13.預(yù)渲染圖像。當(dāng)新的圖像出現(xiàn)時(shí),仍然會(huì)有短暫的停頓現(xiàn)象。解決的辦法就是在bitmap context里先將其畫一遍,導(dǎo)出成UIImage對(duì)象,然后再繪制到屏幕;
14.使用正確的數(shù)據(jù)結(jié)構(gòu)來存儲(chǔ)數(shù)據(jù)。
三十二、runloop 使用
????????????????????????????????????????????????????????????????????????????????????????????????????????????概念:
運(yùn)行循環(huán),保持程序的運(yùn)行,處理應(yīng)用中的各種事件,有事就做,沒事休息,可以節(jié)省CPU的資源 ,提高程序性能
1、講講 RunLoop,項(xiàng)目中有用到嗎?
2、RunLoop內(nèi)部實(shí)現(xiàn)邏輯?
3、Runloop和線程的關(guān)系?
每條線程都有唯一的一個(gè)與之對(duì)應(yīng)的RunLoop對(duì)象
RunLoop保存在一個(gè)全局的Dictionary里,線程作為key,RunLoop作為value
主線程的RunLoop已經(jīng)自動(dòng)創(chuàng)建好了,子線程的RunLoop需要主動(dòng)創(chuàng)建
RunLoop在第一次獲取時(shí)創(chuàng)建,在線程結(jié)束時(shí)銷毀
4、timer 與 Runloop 的關(guān)系?
5、程序中添加每3秒響應(yīng)一次的NSTimer,當(dāng)拖動(dòng)tableview時(shí)timer可能無法響應(yīng)要怎么解決?
6、Runloop 是怎么響應(yīng)用戶操作的, 具體流程是什么樣的?
7、說說RunLoop的幾種狀態(tài)?
8、Runloop的mode作用是什么?
1、Runloop 的應(yīng)用:
NSTimer 、 imageview 顯示、performselector、常駐線程、自動(dòng)釋放池
2、Runloop 相關(guān)類
//
CFRunLoopRef
// 代表運(yùn)行模式:每次啟動(dòng),只能制定一個(gè)模式,如果需要切換,只能退出當(dāng)前roop,這樣做的目的是為了區(qū)分開不同的 timer/source/observer
CFRunLoopModeRef
// 事件輸入源
// 1. Source1 : 基于Port的線程間通信 2. Source0 : 觸摸事件,PerformSelectors
CFRunLoopSourceRef
// 基于時(shí)間的觸發(fā)器,但是會(huì)受到 mode 的影響,但是GCD定時(shí)器不會(huì)受到影響
CFRunLoopTimerRef
// 觀察者 監(jiān)聽roop 的狀態(tài)
// 可以監(jiān)聽的時(shí)間點(diǎn):
// 1、即將進(jìn)入kcfRunLoopEntry
// 2、即將處理timer kcfRunLoopBeforeTimers(????????timer)
// 3、即將處理source kcfRunLoopBeforeSources(????????source)
// 4、即將進(jìn)入休眠 kcfRunLoopBeforeWaiting(????????????)
// 5、剛從休眠中喚醒 kcfRunLoopAfterWaiting(??????????????)
// 6、退出 kcfRunLoopExit(????????loop)
CFRunLoopObserverRef
3、Runloop 的實(shí)現(xiàn)機(jī)制 以及在多線程中的使用
實(shí)現(xiàn)機(jī)制:保持程序的運(yùn)行,處理應(yīng)用中的各種事件,有事就做,沒事休息,可以節(jié)省CPU的資源 ,提高程序性能
處理邏輯:
(1)、通知observer ,即將進(jìn)入 runloop
(2)、通知observer ,即將處理 timer
(3)、通知observer ,即將處理 source0
(4)、如果有 source0,處理
(5)、通知observer ,即將休眠
(6)、通知observer ,即將喚醒
(7)、處理未處理的事件
(8)、線程退出
4、autorelease 對(duì)象什么時(shí)候被釋放?
分兩種情況:
1、手動(dòng)干預(yù)釋放:就是制定autoreleasepool ,超出當(dāng)前作用預(yù)就釋放
2、系統(tǒng)自動(dòng)釋放:當(dāng)前runloop退出,就釋放
5、mode 的作用是什么?
主要是用來制定優(yōu)先級(jí)的
6、nstimer 的使用注意事項(xiàng):
(1)、將 nstimer 實(shí)例添加到runloop 的時(shí)候,應(yīng)該注意 類型mode
(2)、不用的時(shí)候 一定要調(diào)用 invalidate 方法 ,不調(diào)用就會(huì)引起內(nèi)存泄漏 而且用 xcode 找不到
7、UITableViewCell 上有一個(gè) UILable ,用于顯示時(shí)間,滑動(dòng)的過程中是否刷新時(shí)間呢?
如果在創(chuàng)建定時(shí)器的過程中使用的是 NSDefaultRunLoopMode 模式,在滑動(dòng)過程中是不會(huì)調(diào)的,因?yàn)?該模式是運(yùn)行在 空閑狀態(tài)下的。默認(rèn)模式的優(yōu)先級(jí)比較低。
8、子線程中performSelector afterDelay
performSelector
今天用幾個(gè)例子來記錄一下performSelector的各種用法和注意事項(xiàng)
performSelector:withObject
此方法同步阻塞當(dāng)前線程 它走完再走后面的方法
performSelectorOnMainThread:withObject:waitUntilDone
此方法可以在主線程或者子線程去調(diào) 但selector方法運(yùn)行在主線程
waitUntilDone:YES 同步阻塞 自己走完再走后面方法
waitUntilDone:NO 異步非阻塞
performSelector:withObject:afterDelay
此方法是異步非阻塞!! 不能在沒有runloop的子線程直接調(diào) 直接調(diào)的話不會(huì)生效
如果想要在子線程中生效可以:
給這個(gè)子線程加runloop
讓這個(gè)方法在一個(gè)你創(chuàng)建的新的帶有runloop的子線程中perform
不用performSelector:withObject:afterDelay改用dispatch_after
1. afterDelay 方式是使用當(dāng)前線程的定時(shí)器在一定時(shí)間后調(diào)用SEL,NO AfterDelay方式是直接調(diào)用SEL.
2. 主線程的runloop默認(rèn)開啟,子線程的runloop默認(rèn)不開啟,所以timer在子線程中是不會(huì)執(zhí)行的,需要手動(dòng)開啟runloop。
三十三、weak 與 assign 的區(qū)別
1、區(qū)別
1.修飾變量類型的區(qū)別
weak 只可以修飾對(duì)象。如果修飾基本數(shù)據(jù)類型,編譯器會(huì)報(bào)錯(cuò)-“Property with ‘weak’ attribute must be of object type”。
assign 可修飾對(duì)象,和基本數(shù)據(jù)類型。當(dāng)需要修飾對(duì)象類型時(shí),MRC時(shí)代使用unsafe_unretained。當(dāng)然,unsafe_unretained也可能產(chǎn)生野指針,所以它名字是"unsafe_”。
2.是否產(chǎn)生野指針的區(qū)別
weak 不會(huì)產(chǎn)生野指針問題。因?yàn)閣eak修飾的對(duì)象釋放后(引用計(jì)數(shù)器值為0),指針會(huì)自動(dòng)被置nil,之后再向該對(duì)象發(fā)消息也不會(huì)崩潰。 weak是安全的。
assign 如果修飾對(duì)象,會(huì)產(chǎn)生野指針問題;如果修飾基本數(shù)據(jù)類型則是安全的。修飾的對(duì)象釋放后,指針不會(huì)自動(dòng)被置空,此時(shí)向?qū)ο蟀l(fā)消息會(huì)崩潰。
二、相似
都可以修飾對(duì)象類型,但是assign修飾對(duì)象會(huì)存在問題。
三、總結(jié)
assign 適用于基本數(shù)據(jù)類型如int,float,struct等值類型,不適用于引用類型。因?yàn)橹殿愋蜁?huì)被放入棧中,遵循先進(jìn)后出原則,由系統(tǒng)負(fù)責(zé)管理?xiàng)?nèi)存。而引用類型會(huì)被放入堆中,需要我們自己手動(dòng)管理內(nèi)存或通過ARC管理。
weak 適用于delegate和block等引用類型,不會(huì)導(dǎo)致野指針問題,也不會(huì)循環(huán)引用,非常安全。