本篇文章是承接上篇文章 iOS 進階+面試(二)
二十一覆履、可變數(shù)組與不可變數(shù)組用什么修飾:原因乖仇?
地址http://www.reibang.com/p/27305b08b0f2
二十二、nsstring 使用什么關鍵字修飾?
地址http://www.reibang.com/p/9b77d61d76fe
二十三、線上項目崩潰鹿寨,日志處理?
友盟, 集成需要在
-(void)viewWillAppear:(BOOL)animated
-(void)viewWillDisappear:(BOOL)animated
詳解 : 用友盟詳細說明一下
- 報表中心中下載錯誤
- 將 友盟Crash分析工具與下載的錯誤報表放同一文件夾中, 打開 終端 , 先拖入友盟Crash分析工具** 再拖入 錯誤報表 , 按回車
- 進入友盟 個人中心 -> 錯誤分析 -> 錯誤列表 -> 點擊列表中錯誤進入界面
2. 點擊 右上角 進入 [報表中心] 下載該錯誤. 將 友盟Crash分析工具與下載的錯誤報表放同一文件夾中, 打開 終端 , 先拖入友盟Crash分析工具 再拖入 錯誤報表 , 按回車.
- 終端 運行完成后 , 會顯示錯誤的位置與行數(shù)
二十四薪夕、談談多線程的理解脚草?
- 使用線程可以把程序中占據時間長的任務放到后臺去處理,如圖片寥殖、視頻的下載
- 充分利用系統(tǒng)的多核 發(fā)揮多核處理器的優(yōu)勢玩讳,并發(fā)執(zhí)行讓系統(tǒng)運行的更快、更流暢嚼贡,用戶體驗更好
缺點:
更多的線程需要更多的內存空間
當多個線程對同一個資源出現(xiàn)爭奪的時候要注意線程安全的問題熏纯。
二十五、iPhone x max這個你們是怎樣適配的粤策?
iOS11之前導航欄默認高度為64pt(這里高度指statusBar + NavigationBar)樟澜,iOS11之后如果設置了prefersLargeTitles = YES則為96pt,默認情況下還是64pt,但在iPhoneX上由于劉海的出現(xiàn)statusBar由以前的20pt變成了44pt秩贰,所以iPhoneX上高度變?yōu)?8pt霹俺,如果項目里隱藏了導航欄加了自定義按鈕之類的,這里需要注意適配一下毒费。
之前是按照定義宏變量適配的丙唧,這個感覺每次新出手機都要重新適配新手機,iOS11 新出安全區(qū)域的概念觅玻,這是我們可以根據安全區(qū)域來適配想际,
問題:
- 導航欄圖層及對titleView布局的影響
iOS11之前導航欄的title是添加在UINavigationItemView上面,而navigationBarButton則直接添加在UINavigationBar上面溪厘,如果設置了titleView胡本,則titleView也是直接添加在UINavigationBar上面。iOS11之后畸悬,大概因為largeTitle的原因侧甫,視圖層級發(fā)生了變化,如果沒有給titleView賦值蹋宦,則titleView會直接添加在_UINavigationBarContentView上面披粟,如果賦值了titleView,則會把titleView添加在_UITAMICAdaptorView上妆档,而navigationBarButton被加在了_UIButtonBarStackView上僻爽,然后他們都被加在了_UINavigationBarContentView上,如圖:
所以如果你的項目是自定義的navigationBar贾惦,那么在iOS11上運行就可能出現(xiàn)布局錯亂的bug,解決辦法是重寫UINavigationBar的layoutSubviews方法敦捧,調整布局须板,上代碼:
- (void)layoutSubviews {
[super layoutSubviews];
//注意導航欄及狀態(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設備上運行出現(xiàn)最多問題應該就是tableview莫名奇妙的偏移20pt或者64pt了习瑰。。原因是iOS11棄用了automaticallyAdjustsScrollViewInsets屬性秽荤,取而代之的是UIScrollView新增了contentInsetAdjustmentBehavior屬性甜奄,這一切的罪魁禍首都是新引入的safeArea,關于safeArea適配這篇文章iOS 11 安全區(qū)域適配總結講的很詳細窃款,感興趣的可以看下课兄,我直接貼適配代碼,因為低版本直接用contentInsetAdjustmentBehavior會報警告晨继,所有定義了如下的宏(感謝@炒雞范的指正烟阐,之前的宏犯了個低級錯誤...現(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高度與設置不符的問題,在iOS11中如果不實現(xiàn) -tableView: viewForHeaderInSection:和-tableView: viewForFooterInSection: 蜒茄,則-tableView: heightForHeaderInSection:和- tableView: heightForFooterInSection:不會被調用唉擂,導致它們都變成了默認高度,這是因為tableView在iOS11默認使用Self-Sizing檀葛,tableView的estimatedRowHeight玩祟、estimatedSectionHeaderHeight、 estimatedSectionFooterHeight三個高度估算屬性由默認的0變成了UITableViewAutomaticDimension屿聋,解決辦法簡單粗暴空扎,就是實現(xiàn)對應方法或把這三個屬性設為0。
如果你使用了Masonry胜臊,那么你需要適配safeArea
if (@available(iOS 11.0, *)) {
make.edges.equalTo()(self.view.safeAreaInsets)
} else {
make.edges.equalTo()(self.view)
}
- TabBarController
在viewWillAppear時 tabbar高度是49(默認高度勺卢?)
在viewDidAppear時 tabbar高度是83(真實準確高度)
可我在viewDidLoad時候就開始繪制界面了 如何適配?
具體的實現(xiàn)邏輯就是寫一個繼承UITabBarController的類然后修改類里面的方法
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
if (@available(iOS 11.0, *)){
for (UIView *view in self.view.subviews) {
if ([view isKindOfClass:[UITabBar class]]) {
//x的位置不變 y的位置你自己調調到UI滿意 寬不變 高也不能變 最終只是改變一下y的相對位置
view.frame = CGRectMake(view.frame.origin.x, self.view.bounds.size.height-64, view.frame.size.width, 83);
}
}
}
}
之前這么寫有一個問題,就是會出現(xiàn)tabbar在push和pop的時候有上移下移的問題,后來查了一些資料解決了這個問題,在需要展示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 拉下項目代碼
git status 查看狀態(tài)
git checkout --readme.txt 把readme.txt文件在工作去的修改全部撤銷
git rm 用于刪除一個文件
git branch dev 創(chuàng)建dev分支
git checkout dev 跳轉到dev分支 //注意當前的要先提交然后再跳轉
git checkout -b dev 創(chuàng)建并切換到dev分支
git branch 查看當前分支
二十七黑忱、http中的三次握手和四次揮手?
1:客戶端向服務器發(fā)出連接請求報文
2:TCP服務器收到請求報文后勒魔,如果同意連接甫煞,則發(fā)出確認報文
3:TCP客戶進程收到確認后,還要向服務器給出確認
思考:為什么要三次握手呢冠绢,有人說兩次握手就好了抚吠?
舉例:已失效的連接請求報文段。
client發(fā)送了第一個連接的請求報文弟胀,但是由于網絡不好楷力,這個請求沒有立即到達服務端,而是在某個網絡節(jié)點中滯留了孵户,直到某個時間才到達server萧朝,本來這已經是一個失效
的報文,但是server端接收到這個請求報文后夏哭,還是會想client發(fā)出確認的報文检柬,表示同意連接。假如不采用三次握手竖配,那么只要server發(fā)出確認何址,新的建立就連接了,但其實這個
請求是失效的請求进胯,client是不會理睬server的確認信息用爪,也不會向服務端發(fā)送確認的請求,但是server認為新的連接已經建立起來了龄减,并一直等待client發(fā)來數(shù)據项钮,這樣,server的
很多資源就沒白白浪費掉了,采用三次握手就是為了防止這種情況的發(fā)生烁巫,server會因為收不到確認的報文署隘,就知道client并沒有建立連接。這就是三次握手的作用亚隙。
- TCP的四次揮手 磁餐?
1、TCP發(fā)送一個FIN(結束)阿弃,用來關閉客戶到服務端的連接诊霹。
2、服務端收到這個FIN渣淳,他發(fā)回一個ACK(確認)脾还,確認收到序號為收到序號+1,和SYN一樣入愧,一個FIN將占用一個序號
3鄙漏、 服務端發(fā)送一個FIN(結束)到客戶端,服務端關閉客戶端的連接棺蛛。
4怔蚌、客戶端發(fā)送ACK(確認)報文確認,并將確認的序號+1旁赊,這樣關閉完成
思考:那么為什么是4次揮手呢桦踊?
為了確保數(shù)據能夠完成傳輸。
關閉連接時终畅,當收到對方的FIN報文通知時籍胯,它僅僅表示對方沒有數(shù)據發(fā)送給你了;但未必你所有的數(shù)據都全部發(fā)送給對方了离福,所以你可以未必會馬上會關閉SOCKET,也
即你可能還需要發(fā)送一些數(shù)據給對方之后芒炼,再發(fā)送FIN報文給對方來表示你同意現(xiàn)在可以關閉連接了,所以它這里的ACK報文和FIN報文多數(shù)情況下都是分開發(fā)送的术徊。
可能有人會有疑問,tcp我握手的時候為何ACK(確認)和SYN(建立連接)是一起發(fā)送鲸湃。揮手的時候為什么是分開的時候發(fā)送呢 ????
因為當Server端收到Client端的SYN連接請求報文后赠涮,可以直接發(fā)送SYN+ACK報文。其中ACK報文是用來應答的暗挑,
思考:客戶端突然掛掉了怎么辦笋除?
正常連接時,客戶端突然掛掉了炸裆,如果沒有措施處理這種情況垃它,那么就會出現(xiàn)客戶端和服務器端出現(xiàn)長時期的空閑。解決辦法是在服務器端設置保活計時器国拇,每當服務器收到
客戶端的消息洛史,就將計時器復位。超時時間通常設置為2小時酱吝。若服務器超過2小時沒收到客戶的信息也殖,他就發(fā)送探測報文段。若發(fā)送了10個探測報文段务热,每一個相隔75秒忆嗜,
還沒有響應就認為客戶端出了故障,因而終止該連接崎岂。
- 四捆毫、TCP和UDP的區(qū)別
我這里簡單列舉幾個,因為我還沒有研究UDP這個協(xié)議冲甘。
1绩卤、基于連接與無連接;UDP是無連接的,即發(fā)送數(shù)據之前不需要建立連接
2损合、TCP保證數(shù)據正確性
省艳,UDP可能丟包,TCP保證數(shù)據順序嫁审,UDP不保證跋炕。也就是說,通過TCP連接傳送的數(shù)據律适,無差錯辐烂,不丟失,不重復捂贿,且按序到達;UDP盡最大努力交付
纠修,即不保證可靠交付Tcp通過校驗和,重傳控制厂僧,序號標識扣草,滑動窗口、確認應答實現(xiàn)可靠傳輸颜屠。如丟包時的重發(fā)控制辰妙,還可以對次序亂掉的分包進行順序控制。
3甫窟、UDP具有較好的實時性密浑,工作效率比TCP高
,適用于對高速傳輸和實時性有較高的通信或廣播通信粗井。
4尔破、每一條TCP連接只能是點到點的;UDP支持一對一街图,一對多,多對一和多對多的交互通信懒构。
5餐济、TCP對系統(tǒng)資源要求較多,UDP對系統(tǒng)資源要求較少痴脾。
二十八颤介、IOS 保證線程同步方式&性能對比
- @synchronized
- NSLock
- NSRecursiveLock
- dispatch_semaphore
- NSCondition
- pthread_mutex
- OSSpinLock。
文章 http://www.reibang.com/p/4edf98a61483
二十九赞赖、數(shù)據庫
文章 http://www.reibang.com/p/d8b980b41de4
三十滚朵、iOS中UITableViewCell的重用機制原理?
- 重用實現(xiàn)分析
查看UITableView頭文件前域,會找到NSMutableArray* visiableCells
辕近,和NSMutableDictnery* reusableTableCells
兩個結構。visiableCells內保存當前顯示的cells匿垄,reusableTableCells保存可重 用的cells
TableView顯示之初移宅,reusableTableCells為空,那么tableView dequeueReusableCellWithIdentifier:CellIdentifier返回nil椿疗。開始的cell都是通過 [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]來創(chuàng)建漏峰,而且cellForRowAtIndexPath只是調用最大顯示cell數(shù)的 次數(shù)
比如:有100條數(shù)據,iPhone一屏最多顯示10個cell届榄。程序最開始顯示TableView的情況是:
1. 用[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]創(chuàng)建10次cell浅乔,并給cell指定同樣的重用標識(當然,可以為不同顯示類型的 cell指定不同的標識)铝条。并且10個cell全部都加入到visiableCells數(shù)組靖苇,reusableTableCells為空。
2. 向下拖動tableView班缰,當cell1完全移出屏幕贤壁,并且cell11(它也是alloc出來的,原因同上)完全顯示出來的時候埠忘。cell11加入到 visiableCells脾拆,cell1移出visiableCells,cell1加入到reusableTableCells莹妒。
3. 接著向下拖動tableView假丧,因為reusableTableCells中已經有值,所以动羽,當需要顯示新的 cell,cellForRowAtIndexPath再次被調用的時候渔期,tableView dequeueReusableCellWithIdentifier:CellIdentifier运吓,返回cell1渴邦。cell1加入到 visiableCells,cell1移出reusableTableCells拘哨;cell2移出visiableCells谋梭,cell2加入到 reusableTableCells。之后再需要顯示的Cell就可以正常重用了倦青。
所以整個過程并不難理解瓮床,但需要注意正是因為這樣的原因:配置Cell的時候一定要注意,對取出的重用的cell做重新賦值产镐,不要遺留老數(shù)據
隘庄。
- 一些情況
使用過程中,我注意到癣亚,并不是只有拖動超出屏幕的時候才會更新reusableTableCells表丑掺,還有:
1. reloadData,這種情況比較特殊述雾。一般是部分數(shù)據發(fā)生變化街州,需要重新刷新cell顯示的內容時調用。在 cellForRowAtIndexPath調用中玻孟,所有cell都是重用的唆缴。我估計reloadData調用后,把visiableCells中所有 cell移入reusableTableCells黍翎,visiableCells清空面徽。cellForRowAtIndexPath調用后,再把 reuse的cell從reusableTableCells取出來玩敏,放入到visiableCells斗忌。
2. reloadRowsAtIndex,刷新指定的IndexPath旺聚。如果調用時reusableTableCells為空织阳,那么 cellForRowAtIndexPath調用后,是新創(chuàng)建cell砰粹,新的cell加入到visiableCells唧躲。老的cell移出 visiableCells,加入到reusableTableCells碱璃。于是弄痹,之后的刷新就有cell做reuse了。
三十一嵌器、遇到tableView卡頓嘛肛真?會造成卡頓的原因大致有哪些?
1.最常用的就是cell的重用爽航, 注冊重用標識符
如果不重用cell時蚓让,每當一個cell顯示到屏幕上時乾忱,就會重新創(chuàng)建一個新的cell
如果有很多數(shù)據的時候,就會堆積很多cell历极。
如果重用cell窄瘟,為cell創(chuàng)建一個ID,每當需要顯示cell 的時候趟卸,都會先去緩沖池中尋找可循環(huán)利用的cell蹄葱,如果沒有再重新創(chuàng)建cell
2.避免cell的重新布局
cell的布局填充等操作 比較耗時,一般創(chuàng)建時就布局好
如可以將cell單獨放到一個自定義類锄列,初始化時就布局好
3.提前計算并緩存cell的屬性及內容
當我們創(chuàng)建cell的數(shù)據源方法時图云,編譯器并不是先創(chuàng)建cell 再定cell的高度
而是先根據內容一次確定每一個cell的高度,高度確定后右蕊,再創(chuàng)建要顯示的cell琼稻,滾動時,每當cell進入憑虛都會計算高度饶囚,提前估算高度告訴編譯器帕翻,編譯器知道高度后,緊接著就會創(chuàng)建cell萝风,這時再調用高度的具體計算方法嘀掸,這樣可以方式浪費時間去計算顯示以外的cell
4.減少cell中控件的數(shù)量
盡量使cell得布局大致相同,不同風格的cell可以使用不用的重用標識符规惰,初始化時添加控件睬塌,
不適用的可以先隱藏
5.不要使用ClearColor,無背景色歇万,透明度也不要設置為0
渲染耗時比較長
6.使用局部更新
如果只是更新某組的話揩晴,使用reloadSection進行局部更
7.加載網絡數(shù)據,下載圖片贪磺,使用異步加載硫兰,并緩存
8.少使用addView 給cell動態(tài)添加view
9.按需加載cell,cell滾動很快時寒锚,只加載范圍內的cell
10.不要實現(xiàn)無用的代理方法劫映,tableView只遵守兩個協(xié)議
11.緩存行高:estimatedHeightForRow不能和HeightForRow里面的layoutIfNeed同時存在,這兩者同時存在才會出現(xiàn)“竄動”的bug刹前。所以我的建議是:只要是固定行高就寫預估行高來減少行高調用次數(shù)提升性能泳赋。如果是動態(tài)行高就不要寫預估方法了,用一個行高的緩存字典來減少代碼的調用次數(shù)即可
12.不要做多余的繪制工作喇喉。在實現(xiàn)drawRect:的時候祖今,它的rect參數(shù)就是需要繪制的區(qū)域,這個區(qū)域之外的不需要進行繪制拣技。例如上例中衅鹿,就可以用CGRectIntersectsRect撒踪、CGRectIntersection或CGRectContainsRect判斷是否需要繪制image和text,然后再調用繪制方法大渤。
13.預渲染圖像。當新的圖像出現(xiàn)時掸绞,仍然會有短暫的停頓現(xiàn)象泵三。解決的辦法就是在bitmap context里先將其畫一遍,導出成UIImage對象衔掸,然后再繪制到屏幕烫幕;
14.使用正確的數(shù)據結構來存儲數(shù)據。
三十二敞映、runloop 使用
????????????????????????????????????????????????????????????????????????????????????????????????????????????概念:
運行循環(huán)昵宇,保持程序的運行华蜒,處理應用中的各種事件,有事就做,沒事休息癣漆,可以節(jié)省CPU的資源 ,提高程序性能
1楔脯、講講 RunLoop喇肋,項目中有用到嗎?
2档桃、RunLoop內部實現(xiàn)邏輯枪孩?
3、Runloop和線程的關系藻肄?
每條線程都有唯一的一個與之對應的RunLoop對象
RunLoop保存在一個全局的Dictionary里蔑舞,線程作為key,RunLoop作為value
主線程的RunLoop已經自動創(chuàng)建好了,子線程的RunLoop需要主動創(chuàng)建
RunLoop在第一次獲取時創(chuàng)建嘹屯,在線程結束時銷毀
4攻询、timer 與 Runloop 的關系?
5抚垄、程序中添加每3秒響應一次的NSTimer蜕窿,當拖動tableview時timer可能無法響應要怎么解決?
6呆馁、Runloop 是怎么響應用戶操作的桐经, 具體流程是什么樣的?
7浙滤、說說RunLoop的幾種狀態(tài)阴挣?
8、Runloop的mode作用是什么纺腊?
1畔咧、Runloop 的應用:
NSTimer 茎芭、 imageview 顯示、performselector誓沸、常駐線程梅桩、自動釋放池
2、Runloop 相關類
//
CFRunLoopRef
// 代表運行模式:每次啟動拜隧,只能制定一個模式宿百,如果需要切換,只能退出當前roop洪添,這樣做的目的是為了區(qū)分開不同的 timer/source/observer
CFRunLoopModeRef
// 事件輸入源
// 1. Source1 : 基于Port的線程間通信 2. Source0 : 觸摸事件垦页,PerformSelectors
CFRunLoopSourceRef
// 基于時間的觸發(fā)器,但是會受到 mode 的影響干奢,但是GCD定時器不會受到影響
CFRunLoopTimerRef
// 觀察者 監(jiān)聽roop 的狀態(tài)
// 可以監(jiān)聽的時間點:
// 1痊焊、即將進入kcfRunLoopEntry
// 2、即將處理timer kcfRunLoopBeforeTimers(????????timer)
// 3忿峻、即將處理source kcfRunLoopBeforeSources(????????source)
// 4薄啥、即將進入休眠 kcfRunLoopBeforeWaiting(????????????)
// 5、剛從休眠中喚醒 kcfRunLoopAfterWaiting(??????????????)
// 6炭菌、退出 kcfRunLoopExit(????????loop)
CFRunLoopObserverRef
3罪佳、Runloop 的實現(xiàn)機制 以及在多線程中的使用
實現(xiàn)機制:保持程序的運行,處理應用中的各種事件黑低,有事就做赘艳,沒事休息,可以節(jié)省CPU的資源 克握,提高程序性能
處理邏輯:
(1)蕾管、通知observer ,即將進入 runloop
(2)菩暗、通知observer 掰曾,即將處理 timer
(3)、通知observer 停团,即將處理 source0
(4)旷坦、如果有 source0,處理
(5)佑稠、通知observer 秒梅,即將休眠
(6)、通知observer 舌胶,即將喚醒
(7)捆蜀、處理未處理的事件
(8)、線程退出
4、autorelease 對象什么時候被釋放辆它?
分兩種情況:
1誊薄、手動干預釋放:就是制定autoreleasepool ,超出當前作用預就釋放
2锰茉、系統(tǒng)自動釋放:當前runloop退出呢蔫,就釋放
5、mode 的作用是什么飒筑?
主要是用來制定優(yōu)先級的
6咐刨、nstimer 的使用注意事項:
(1)、將 nstimer 實例添加到runloop 的時候扬霜,應該注意 類型mode
(2)、不用的時候 一定要調用 invalidate 方法 而涉,不調用就會引起內存泄漏 而且用 xcode 找不到
7著瓶、UITableViewCell 上有一個 UILable ,用于顯示時間,滑動的過程中是否刷新時間呢啼县?
如果在創(chuàng)建定時器的過程中使用的是 NSDefaultRunLoopMode 模式材原,在滑動過程中是不會調的,因為 該模式是運行在 空閑狀態(tài)下的季眷。默認模式的優(yōu)先級比較低余蟹。
8、子線程中performSelector afterDelay
performSelector
今天用幾個例子來記錄一下performSelector的各種用法和注意事項
performSelector:withObject
此方法同步阻塞當前線程 它走完再走后面的方法
performSelectorOnMainThread:withObject:waitUntilDone
此方法可以在主線程或者子線程去調 但selector方法運行在主線程
waitUntilDone:YES 同步阻塞 自己走完再走后面方法
waitUntilDone:NO 異步非阻塞
performSelector:withObject:afterDelay
此方法是異步非阻塞!! 不能在沒有runloop的子線程直接調 直接調的話不會生效
如果想要在子線程中生效可以:
給這個子線程加runloop
讓這個方法在一個你創(chuàng)建的新的帶有runloop的子線程中perform
不用performSelector:withObject:afterDelay改用dispatch_after
1. afterDelay 方式是使用當前線程的定時器在一定時間后調用SEL子刮,NO AfterDelay方式是直接調用SEL.
2. 主線程的runloop默認開啟威酒,子線程的runloop默認不開啟,所以timer在子線程中是不會執(zhí)行的挺峡,需要手動開啟runloop葵孤。
三十三、weak 與 assign 的區(qū)別
1橱赠、區(qū)別
1.修飾變量類型的區(qū)別
weak 只可以修飾對象尤仍。如果修飾基本數(shù)據類型,編譯器會報錯-“Property with ‘weak’ attribute must be of object type”狭姨。
assign 可修飾對象宰啦,和基本數(shù)據類型。當需要修飾對象類型時饼拍,MRC時代使用unsafe_unretained赡模。當然,unsafe_unretained也可能產生野指針惕耕,所以它名字是"unsafe_”纺裁。
2.是否產生野指針的區(qū)別
weak 不會產生野指針問題。因為weak修飾的對象釋放后(引用計數(shù)器值為0),指針會自動被置nil欺缘,之后再向該對象發(fā)消息也不會崩潰栋豫。 weak是安全的。
assign 如果修飾對象谚殊,會產生野指針問題丧鸯;如果修飾基本數(shù)據類型則是安全的。修飾的對象釋放后嫩絮,指針不會自動被置空丛肢,此時向對象發(fā)消息會崩潰。
二剿干、相似
都可以修飾對象類型蜂怎,但是assign修飾對象會存在問題。
三置尔、總結
assign 適用于基本數(shù)據類型如int,float,struct等值類型杠步,不適用于引用類型。因為值類型會被放入棧中榜轿,遵循先進后出原則幽歼,由系統(tǒng)負責管理棧內存。而引用類型會被放入堆中谬盐,需要我們自己手動管理內存或通過ARC管理甸私。
weak 適用于delegate和block等引用類型,不會導致野指針問題飞傀,也不會循環(huán)引用皇型,非常安全助析。