最新ios面試試題以及解決思路分析
很多IOS面試都是筆試或者直接上機(jī)操作,我們整理了最新的被問到最多的試題類型,來看下:
使用了第三方庫, 有看他們是怎么實(shí)現(xiàn)的嗎?
例:SD、YY、AFN、MJ等!
<1>.SD為例:
1.入口 setImageWithURL:placeholderImage:options: 會(huì)先把 placeholderImage 顯示,然后 SDWebImageManager 根據(jù) URL 開始處理圖片。 2.進(jìn)入 SDWebImageManagerdownloadWithURL:delegate:options:userInfo:, 交給 SDImageCache 從緩存查找圖片是否已經(jīng)下載 queryDiskCacheForKey:delegate:userInfo:. 3.先從內(nèi)存圖片緩存查找是否有圖片, 如果內(nèi)存中已經(jīng)有圖片緩存,SDImageCacheDelegate 回調(diào) imageCache:didFindImage:forKey:userInfo: 到 SDWebImageManager。 4.SDWebImageManagerDelegate 回調(diào) webImageManager:didFinishWithImage: 到 UIImageView+WebCache 等前端展示圖片。 5.如果內(nèi)存緩存中沒有,生成 NSInvocationOperation 添加到隊(duì)列開始從硬盤查找圖片是否已經(jīng)緩存。 6.根據(jù) URLKey 在硬盤緩存目錄下嘗試讀取圖片文件。 這一步是在 NSOperation 進(jìn)行的操作,所以回主線程進(jìn)行結(jié)果回調(diào) notifyDelegate:。 7.如果上一操作從硬盤讀取到了圖片,將圖片添加到內(nèi)存緩存中 (如果空閑內(nèi)存過小,會(huì)先清空內(nèi)存緩存)。 SDImageCacheDelegate 回調(diào) imageCache:didFindImage:forKey:userInfo:。 進(jìn)而回調(diào)展示圖片。 8.如果從硬盤緩存目錄讀取不到圖片, 說明所有緩存都不存在該圖片,需要下載圖片, 回調(diào) imageCache:didNotFindImageForKey:userInfo:。 9.共享或重新生成一個(gè)下載器 SDWebImageDownloader 開始下載圖片。 10.圖片下載由 NSURLConnection 來做, 實(shí)現(xiàn)相關(guān) delegate 來判斷圖片下載中、下載完成和下載失敗。 11.connection:didReceiveData: 中 利用 ImageIO 做了按圖片下載進(jìn)度加載效果。 12.connectionDidFinishLoading: 數(shù)據(jù)下載完成后交給 SDWebImageDecoder 做圖片解碼處理。 13.圖片解碼處理在一個(gè) NSOperationQueue 完成, 不會(huì)拖慢主線程 UI。如果有需要對下載的圖片進(jìn)行二次處理, 最好也在這里完成,效率會(huì)好很多。 14.在主線程 notifyDelegateOnMainThreadWithInfo: 宣告解碼完成, imageDecoder:didFinishDecodingImage:userInfo 回調(diào)給 SDWebImageDownloader。 15.imageDownloader:didFinishWithImage: 回調(diào)給 SDWebImageManager 告知圖片下載完成。 16.通知所有的 downloadDelegates 下載完成, 回調(diào)給需要的地方展示圖片。 17.將圖片保存到 SDImageCache 中, 內(nèi)存緩存和硬盤緩存同時(shí)保存。 寫文件到硬盤也在以單獨(dú) NSInvocationOperation 完成, 避免拖慢主線程。 18.SDImageCache 在初始化的時(shí)候會(huì)注冊一些消息通知, 在內(nèi)存警告或退到后臺(tái)的時(shí)候清理內(nèi)存圖片緩存 應(yīng)用結(jié)束的時(shí)候清理過期圖片。 19.SDWI 也提供了 UIButton+WebCache 和 MKAnnotationView+WebCache,方便使用。 20.SDWebImagePrefetcher 可以預(yù)先下載圖片, 方便后續(xù)使用。
2.強(qiáng)連通分量了解嘛?
概念:
有向圖強(qiáng)連通分量:在有向圖G中,如果兩個(gè)頂點(diǎn)vi,vj間(vi>vj)有一條從vi到vj的有向路徑,同時(shí)還有一條從vj到vi的有向路徑,則稱兩個(gè)頂點(diǎn)強(qiáng)連通(strongly
connected)。如果有向圖G的每兩個(gè)頂點(diǎn)都強(qiáng)連通,稱G是一個(gè)強(qiáng)連通圖。有向圖的極大強(qiáng)連通子圖,稱為強(qiáng)連通分量(strongly
connected components)。
定義:
有向圖強(qiáng)連通分量:
在有向圖G中,如果兩個(gè)頂點(diǎn)間至少存在一條路徑,稱兩個(gè)頂點(diǎn)強(qiáng)連通(strongly connected)。
如果有向圖G的每兩個(gè)頂點(diǎn)都強(qiáng)連通,則稱G是一個(gè)強(qiáng)連通圖。
非強(qiáng)連通圖有向圖的極大強(qiáng)連通子圖,成為強(qiáng)連通分量(strongly connected components)。
下圖中,子圖{1,2,3,4}為一個(gè)強(qiáng)連通分量,因?yàn)轫旤c(diǎn)1,2,3,4兩兩可達(dá),{5},{6}也分別是兩個(gè)強(qiáng)連通分量。
直接根據(jù)定義,用雙向遍歷取交際的方法求強(qiáng)連通分量,時(shí)間復(fù)雜度為O(N^2+M)。更好的方法是Kosaraju算法或者Tarjan算法
兩者的時(shí)間復(fù)雜度都是O(N+M)。本文介紹的是Tarjan算法。
算法原理:(Tarjan)
need-to-insert-img
Tarjan算法是基于對圖深度優(yōu)先搜索的算法,每個(gè)強(qiáng)連通分量為搜索樹中的一顆子樹。
搜索時(shí),把當(dāng)前搜索樹中未處理的節(jié)點(diǎn)加入一個(gè)堆棧,回溯時(shí)可以盤對棧頂?shù)綏V械墓?jié)點(diǎn)是否為一個(gè)強(qiáng)連通分量。
定義DFN(u)為節(jié)點(diǎn)u搜索的次序編號(hào)(時(shí)間戳)。Low(u)為u或者u的子樹能夠追溯到的最早的棧中的節(jié)點(diǎn)的次序號(hào)。
由定義可以得出:
Low(u)= Min { DFN(u), Low(v)} ((u,v)為樹枝邊,u為v的父節(jié)點(diǎn)DFN(v),(u,v)為指向棧中節(jié)點(diǎn)的后向邊(非橫叉邊))
當(dāng)DFN(u)=Low(u)時(shí),以u(píng)為根的搜索子樹上所有節(jié)點(diǎn)是一個(gè)強(qiáng)連通分量。
3.遇到tableView卡頓嘛?會(huì)造成卡頓的原因大致有哪些?
可能造成tableView卡頓的原因有:
1.最常用的就是cell的重用, 注冊重用標(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對象,然后再繪制到屏幕;
14.使用正確的數(shù)據(jù)結(jié)構(gòu)來存儲(chǔ)數(shù)據(jù)。
4.M、V、C相互通訊規(guī)則你知道的有哪些?
MVC 是一種設(shè)計(jì)思想,一種框架模式,是一種把應(yīng)用中所有類組織起來的策略,它把你的程序分為三塊,分別是:
M(Model):實(shí)際上考慮的是“什么”問題,你的程序本質(zhì)上是什么,獨(dú)立于 UI 工作。是程序中用于處理應(yīng)用程序邏輯的部分,通常負(fù)責(zé)存取數(shù)據(jù)。
C(Controller):控制你 Model 如何呈現(xiàn)在屏幕上,當(dāng)它需要數(shù)據(jù)的時(shí)候就告訴 Model,你幫我獲取某某數(shù)據(jù);當(dāng)它需要 UI 展示和更新的時(shí)候就告訴 View,你幫我生成一個(gè) UI 顯示某某數(shù)據(jù),是 Model 和 View 溝通的橋梁。
V(View):Controller 的手下,是 Controller 要使用的類,用于構(gòu)建視圖,通常是根據(jù) Model 來創(chuàng)建視圖的。
要了解 MVC 如何工作,首先需要了解這三個(gè)模塊間如何通信。
MVC通信規(guī)則
Controller to Model
可以直接單向通信。Controller 需要將 Model 呈現(xiàn)給用戶,因此需要知道模型的一切,還需要有同 Model 完全通信的能力,并且能任意使用 Model 的公共 API。
Controller to View
可以直接單向通信。Controller 通過 View 來布局用戶界面。
Model to View
永遠(yuǎn)不要直接通信。Model 是獨(dú)立于 UI 的,并不需要和 View 直接通信,View 通過 Controller 獲取 Model 數(shù)據(jù)
View to Controller
View 不能對 Controller 知道的太多,因此要通過間接的方式通信。
Target
action。首先 Controller 會(huì)給自己留一個(gè) target,再把配套的 action 交給 View 作為聯(lián)系方式。那么 View
接收到某些變化時(shí),View 就會(huì)發(fā)送 action 給 target 從而達(dá)到通知的目的。這里 View 只需要發(fā)送
action,并不需要知道 Controller 如何去執(zhí)行方法。
代理。有時(shí)候 View 沒有足夠的邏輯去判斷用戶操作是否符合規(guī)范,他會(huì)把判斷這些問題的權(quán)力委托給其他對象,他只需獲得答案就行了,并不會(huì)管是誰給的答案。
DataSoure。View 沒有擁有他們所顯示數(shù)據(jù)的權(quán)力,View 只能向 Controller 請求數(shù)據(jù)進(jìn)行顯示,Controller 則獲取 Model 的數(shù)據(jù)整理排版后提供給 View。
Model 訪問 Controller
同樣的 Model 是獨(dú)立于 UI 存在的,因此無法直接與 Controller 通信,但是當(dāng) Model 本身信息發(fā)生了改變的時(shí)候,會(huì)通過下面的方式進(jìn)行間接通信。
Notification & KVO一種類似電臺(tái)的方法,Model 信息改變時(shí)會(huì)廣播消息給感興趣的人 ,只要 Controller 接收到了這個(gè)廣播的時(shí)候就會(huì)主動(dòng)聯(lián)系 Model,獲取新的數(shù)據(jù)并提供給 View。
從上面的簡單介紹中我們來簡單概括一下 MVC 模式的優(yōu)點(diǎn)。
1.低耦合性
2.有利于開發(fā)分工
3.有利于組件重用
4.可維護(hù)性
5.NStimer準(zhǔn)嗎?談?wù)勀愕目捶ǎ咳绻粶?zhǔn)該怎樣實(shí)現(xiàn)一個(gè)精確的NSTimer?
1.不準(zhǔn)
2.不準(zhǔn)的原因如下:
1、NSTimer加在main runloop中,模式是NSDefaultRunLoopMode,main負(fù)責(zé)所有主線程事件,例如UI界面的操作,復(fù)雜的運(yùn)算,這樣在同一個(gè)runloop中timer就會(huì)產(chǎn)生阻塞。
2、模式的改變。主線程的 RunLoop 里有兩個(gè)預(yù)置的 Mode:kCFRunLoopDefaultMode 和 UITrackingRunLoopMode。
當(dāng)你創(chuàng)建一個(gè) Timer 并加到 DefaultMode 時(shí),Timer 會(huì)得到重復(fù)回調(diào),但此時(shí)滑動(dòng)一個(gè)ScrollView時(shí),RunLoop 會(huì)將 mode 切換為 TrackingRunLoopMode,這時(shí) Timer 就不會(huì)被回調(diào),并且也不會(huì)影響到滑動(dòng)操作。所以就會(huì)影響到NSTimer不準(zhǔn)的情況。
PS:DefaultMode 是 App 平時(shí)所處的狀態(tài),rackingRunLoopMode 是追蹤 ScrollView 滑動(dòng)時(shí)的狀態(tài)。
方法一:
1、在主線程中進(jìn)行NSTimer操作,但是將NSTimer實(shí)例加到main runloop的特定mode(模式)中。避免被復(fù)雜運(yùn)算操作或者UI界面刷新所干擾。
self.timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(showTime) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
2、在子線程中進(jìn)行NSTimer的操作,再在主線程中修改UI界面顯示操作結(jié)果;
- (void)timerMethod2 { NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(newThread) object:nil]; [thread start]; } - (void)newThread { @autoreleasepool { [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(showTime) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] run]; } }
總結(jié):
一開始的時(shí)候系統(tǒng)就為我們將主線程的main runloop隱式的啟動(dòng)了。
在創(chuàng)建線程的時(shí)候,可以主動(dòng)獲取當(dāng)前線程的runloop。每個(gè)子線程對應(yīng)一個(gè)runloop
方法二:
使用示例
使用mach內(nèi)核級(jí)的函數(shù)可以使用mach_absolute_time()獲取到CPU的tickcount的計(jì)數(shù)值,可以通過”mach_timebase_info”函數(shù)獲取到納秒級(jí)的精確度 。然后使用mach_wait_until(uint64_t deadline)函數(shù),直到指定的時(shí)間之后,就可以執(zhí)行指定任務(wù)了。
關(guān)于數(shù)據(jù)結(jié)構(gòu)mach_timebase_info的定義如下:
struct mach_timebase_info {uint32_t numer;uint32_t denom;}; #include #include static const uint64_t NANOS_PER_USEC = 1000ULL; static const uint64_t NANOS_PER_MILLISEC = 1000ULL * NANOS_PER_USEC; static const uint64_t NANOS_PER_SEC = 1000ULL * NANOS_PER_MILLISEC; static mach_timebase_info_data_t timebase_info; static uint64_t nanos_to_abs(uint64_t nanos) { return nanos * timebase_info.denom / timebase_info.numer; } void example_mach_wait_until(int seconds) { mach_timebase_info(&timebase_info); uint64_t time_to_wait = nanos_to_abs(seconds * NANOS_PER_SEC); uint64_t now = mach_absolute_time(); mach_wait_until(now + time_to_wait); }
iOS面試題:騰訊二面以及參考思路:
編譯過程做了哪些事情?
1.C++,Objective C都是編譯語言。編譯語言在執(zhí)行的時(shí)候,必須先通過編譯器生成機(jī)器碼,機(jī)器碼可以直接在CPU上執(zhí)行,所以執(zhí)行效率較高。
iOS開發(fā)目前的常用語言是:Objective和Swift。二者都是編譯語言,換句話說都是需要編譯才能執(zhí)行的。二者的編譯都是依賴于Clang + LLVM. OC和Swift因?yàn)樵砩洗笸‘?,知道一個(gè)即可!
iOS編譯
不管是OC還是Swift,都是采用Clang作為編譯器前端,LLVM(Low level vritual machine)作為編譯器后端。所以簡單的編譯過程如圖
編譯器前端
編譯器前端的任務(wù)是進(jìn)行:語法分析,語義分析,生成中間代碼(intermediate representation )。在這個(gè)過程中,會(huì)進(jìn)行類型檢查,如果發(fā)現(xiàn)錯(cuò)誤或者警告會(huì)標(biāo)注出來在哪一行。
編譯器后端
編譯器后端會(huì)進(jìn)行機(jī)器無關(guān)的代碼優(yōu)化,生成機(jī)器語言,并且進(jìn)行機(jī)器相關(guān)的代碼優(yōu)化。iOS的編譯過程,后端的處理如下
LVVM優(yōu)化器會(huì)進(jìn)行BitCode的生成,鏈接期優(yōu)化等等
LLVM機(jī)器碼生成器會(huì)針對不同的架構(gòu),比如arm64等生成不同的機(jī)器碼。
執(zhí)行一次XCode build的流程
當(dāng)你在XCode中,選擇build的時(shí)候(快捷鍵command+B),會(huì)執(zhí)行如下過程
編譯信息寫入輔助文件,創(chuàng)建編譯后的文件架構(gòu)(name.app)
處理文件打包信息,例如在debug環(huán)境下
執(zhí)行CocoaPod編譯前腳本
例如對于使用CocoaPod的工程會(huì)執(zhí)行CheckPods Manifest.lock
編譯各個(gè).m文件,使用CompileC和clang命令。
編譯各個(gè).m文件,使用CompileC和clang命令。
1.CompileC ClassName.o ClassName.m normal x86_64 objective-c com.apple.compilers.llvm.clang.1_0.compiler 2.export.US-ASCII 3.export PATH="..." 4.clang-x objective-c -arch x86_64 -fmessage-length=0 -fobjc-arc... -Wno-missing-field-initializers ... -DDEBUG=1 ... -isysroot iPhoneSimulator10.1.sdk -fasm-blocks ... -I 上文提到的文件 -F 所需要的Framework-iquote 所需要的Framework ... -c ClassName.c -o ClassName.o
通過這個(gè)編譯的命令,我們可以看到
2.字典大致實(shí)現(xiàn)原理;
一:字典原理
NSDictionary(字典)是使用hash表來實(shí)現(xiàn)key和value之間的映射和存儲(chǔ)的
方法:- (void)setObject:(id)anObject forKey:(id)aKey;
Objective-C中的字典NSDictionary底層其實(shí)是一個(gè)哈希表
二:哈希原理
散列表(Hash table,也叫哈希表),是根據(jù)關(guān)鍵碼值(Key value)而直接進(jìn)行訪問的數(shù)據(jù)結(jié)構(gòu)。也就是說,它通過把關(guān)鍵碼值映射到表中一個(gè)位置來訪問記錄,以加快查找的速度。這個(gè)映射函數(shù)叫做散列函數(shù),存放記錄的數(shù)組叫做散列表。
給定表M,存在函數(shù)f(key),對任意給定的關(guān)鍵字值key,代入函數(shù)后若能得到包含該關(guān)鍵字的記錄在表中的地址,則稱表M為哈希(Hash)表,函數(shù)f(key)為哈希(Hash) 函數(shù)。
哈希概念:哈希表的本質(zhì)是一個(gè)數(shù)組,數(shù)組中每一個(gè)元素稱為一個(gè)箱子(bin),箱子中存放的是鍵值對。
三:哈希存儲(chǔ)過程
1.根據(jù) key 計(jì)算出它的哈希值 h。
2.假設(shè)箱子的個(gè)數(shù)為 n,那么這個(gè)鍵值對應(yīng)該放在第 (h % n) 個(gè)箱子中。
3.如果該箱子中已經(jīng)有了鍵值對,就使用開放尋址法或者拉鏈法解決沖突。
在使用拉鏈法解決哈希沖突時(shí),每個(gè)箱子其實(shí)是一個(gè)鏈表,屬于同一個(gè)箱子的所有鍵值對都會(huì)排列在鏈表中。
哈希表還有一個(gè)重要的屬性: 負(fù)載因子(load factor),它用來衡量哈希表的空/滿程度,一定程度上也可以體現(xiàn)查詢的效率,計(jì)算公式為:
負(fù)載因子 = 總鍵值對數(shù) / 箱子個(gè)數(shù)
負(fù)載因子越大,意味著哈希表越滿,越容易導(dǎo)致沖突,性能也就越低。因此,一般來說,當(dāng)負(fù)載因子大于某個(gè)常數(shù)(可能是 1,或者 0.75 等)時(shí),哈希表將自動(dòng)擴(kuò)容。
哈希表在自動(dòng)擴(kuò)容時(shí),一般會(huì)創(chuàng)建兩倍于原來個(gè)數(shù)的箱子,因此即使 key 的哈希值不變,對箱子個(gè)數(shù)取余的結(jié)果也會(huì)發(fā)生改變,因此所有鍵值對的存放位置都有可能發(fā)生改變,這個(gè)過程也稱為重哈希(rehash)。
哈希表的擴(kuò)容并不總是能夠有效解決負(fù)載因子過大的問題。假設(shè)所有 key 的哈希值都一樣,那么即使擴(kuò)容以后他們的位置也不會(huì)變化。雖然負(fù)載因子會(huì)降低,但實(shí)際存儲(chǔ)在每個(gè)箱子中的鏈表長度并不發(fā)生改變,因此也就不能提高哈希表的查詢性能。
基于以上總結(jié),細(xì)心的朋友可能會(huì)發(fā)現(xiàn)哈希表的兩個(gè)問題:
1.如果哈希表中本來箱子就比較多,擴(kuò)容時(shí)需要重新哈希并移動(dòng)數(shù)據(jù),性能影響較大。
2.如果哈希函數(shù)設(shè)計(jì)不合理,哈希表在極端情況下會(huì)變成線性表,性能極低。
3.block和函數(shù)指針的理解;
相似點(diǎn):
函數(shù)指針和Block都可以實(shí)現(xiàn)回調(diào)的操作,聲明上也很相似,實(shí)現(xiàn)上都可以看成是一個(gè)代碼片段。
函數(shù)指針類型和Block類型都可以作為變量和函數(shù)參數(shù)的類型。(typedef定義別名之后,這個(gè)別名就是一個(gè)類型)
不同點(diǎn):
函數(shù)指針只能指向預(yù)先定義好的函數(shù)代碼塊(可以是其他文件里面定義,通過函數(shù)參數(shù)動(dòng)態(tài)傳入的),函數(shù)地址是在編譯鏈接時(shí)就已經(jīng)確定好的。
Block本質(zhì)是Objective-C對象,是NSObject的子類,可以接收消息。
函數(shù)里面只能訪問全局變量,而Block代碼塊不光能訪問全局變量,還擁有當(dāng)前棧內(nèi)存和堆內(nèi)存變量的可讀性(當(dāng)然通過__block訪問指示符修飾的局部變量還可以在block代碼塊里面進(jìn)行修改)。
從內(nèi)存的角度看,函數(shù)指針只不過是指向代碼區(qū)的一段可執(zhí)行代碼,而block實(shí)際上是程序運(yùn)行過程中在棧內(nèi)存動(dòng)態(tài)創(chuàng)建的對象,可以向其發(fā)送copy消息將block對象拷貝到堆內(nèi)存,以延長其生命周期。
4.一般開始做一個(gè)項(xiàng)目,你的架構(gòu)是如何思考的?
參考文章一
參考文章二
5.你了解的UIKit結(jié)構(gòu)?
相關(guān)文章
iOS如何跳轉(zhuǎn)到App Store下載評(píng)分頁面示例代碼
最近在工作中遇到一個(gè)需求,需要跳轉(zhuǎn)到App Store下載評(píng)分,通過查找相關(guān)的資料最終解決了,下面這篇文章主要給大家介紹了關(guān)于iOS如何跳轉(zhuǎn)到App Store下載評(píng)分頁面的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧。2017-12-12IOS開發(fā) 支持https請求以及ssl證書配置詳解
這篇文章主要介紹了IOS開發(fā) 支持https請求以及ssl證書配置詳解的相關(guān)資料,需要的朋友可以參考下2017-02-02iOS 防止按鈕多次點(diǎn)擊造成多次響應(yīng)的方法
這篇文章主要介紹了iOS 防止按鈕多次點(diǎn)擊造成多次響應(yīng)的方法的相關(guān)資料,這里對多次點(diǎn)擊造成的響應(yīng)提供了解決辦法,需要的朋友可以參考下2016-11-11iOS體驗(yàn)性優(yōu)化之RTL適配右滑返回的實(shí)現(xiàn)
這篇文章主要給大家介紹了關(guān)于iOS體驗(yàn)性優(yōu)化之RTL適配右滑返回實(shí)現(xiàn)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2018-01-01