項目處理
1、介紹一下實習的項目,任務分工做了哪些工作?介紹實習內容?
2、項目里面的數據存儲都用了哪些?知道iOS里面有哪些數據存儲方法?什么時候該用哪些方法存儲?
3、有A B C D E五個類,都要監聽登錄和注冊的通知,發通知給它們五個控制器麻煩,就寫了一個單例類,負責發通知,需要接受通知的就實現delegate,因為單例類里面的數組引用了這幾個VC,導致不釋放,怎么解決?類似NSTimer,不知道什么時機移除VC(可以從這方面考慮:NSNotificationCenter,直接在dealloc里面remove掉就行)因為VC被引用,所以不會執行到dealloc方法,先看下NSNotificationCenter是怎么實現的吧
4、發布出去的版本,怎么收集crash日志?不使用bugly等第三方平臺或者這些第三方平臺是怎么收集crash日志的?
5、解決過的最精彩的crash問題?
6、項目里面遇到過死鎖嗎?怎么解決?數據庫訪問本來就是線程安全的,不會造成死鎖啊。什么是死鎖?
7、WWDC2016公布了哪些新特性?對蘋果系列的最新特性有關注嗎?
8、為什么做iOS開發,不做安卓開發?
9、你最出色的是哪方面?iOS開發,iOS開發的哪一方面?
10、一般開始做一個項目,你的架構是如何思考的?
11、容錯處理你們一般是注意哪些?
答:在團隊協作開發中,由于每個團隊成員的水平不一,很難控制代碼的質量,保證代碼的健壯性,經常會發生由于后臺返回異常數據造成APP崩潰閃退的情況,為了避免這樣的情況項目中做一些容錯處理,顯得格外重要,極大程度上降低了因為數據容錯不到位產生崩潰閃退的概率。例如:字典,數組,野指針,NSNull等等。
12、如果項目開始容錯處理沒做,如何防止攔截潛在的崩潰?
答:(1)category給類添加方法用來替換掉原本存在潛在的崩潰的方法;(2)利用runtime方法交換技術,將系統方法替換成類添加新的方法;(3)利用異常的捕獲來防止程序的崩潰,并且進行相應的處理。
13、簡述push原理,push的證書和其它的右什么不一樣?
14、iOS crash后的調試方法?還有用戶的錯誤日志,如何找到出錯的代碼地址?iOS工具的一些使用?
原理知識問答
1、內存管理
1、autorelease嵌套,系統怎么處理?
答:在NSAutoReleasePool中會有一個array保存所有需要被autorelease的對象, 由于我們要確保在保存對象時array不會對該對象進行強引用(retainCount plus 1), 我們需要用CFMutableArrayRef。
由于每一個線程都有自己的autoReleasePool,所以我們需要保存該線程中所創建的所有autoreleasepools,每創建一個autoreleasepool, 我們可以把它放入一個stack里,然后將這個stack保存起來,例如:?
????NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary];
????NSString *key = @"com.my.thread-local.releasepool";
????CFMutableArrayRef stack = threadDict[key];
????if (!stack) {
?????? stack = CFArrayCreateMutable(NULL, 0, NULL);
?????? [threadDict setObject:(id)stack forKey:key];
????}
????當dealloc的時候,首先遍歷當前autoReleasePool里所有對象,發送release,然后release保存所有對象的CFMutableArray (CFRelease(_objects))。 然后遍歷保存在thread里的stack,由于我們將所有在該線程內創建的autoreleasepool都存入這個stack里,我們只需要release所有在self之后的出現的autoreleasepool, 然后把self從stack里移除。由于每一個autoreleasepool都遵從這樣的邏輯,這其實就是一個遞歸的調用。
2、arc原理?
答:ARC (Automatic Reference Counting),在對象被創建時,ARC會保存一大堆關于該對象的信息:對象類型、所有的屬性等等,當我們不再需要該對象的時候,ARC會幫助我們銷毀該對象。
????當我們alloc、init一個對象實例時,編譯器會在該實例使用完后插入objc_release去銷毀該對象。如果我們是在使用properties的時候,該property的getter會被寫成:
? - (Test *)test {
??????return objc_retainAutoreleaseReturnValue(_test);
?}
????可以看到,所有的properties都被retain/autorelease了, 當引用properties時,編譯器還會將caller改寫為:objc_retainAutoreleaseReturnValue([self test]);這里出現了兩次的retain/autorelease,而編譯器會優化的只使用一次。
3、arc和mrc怎么破循環應用?
答:?使用__weak或__unsafe_unretained
4、ARC和MRC的本質區別是什么?
5、autorelease變量什么時候釋放?子線程里面,需要加autoreleasepool嗎?那子線程中的autorelease變量什么時候釋放?
答:
(1)手動添加的是大括號結束的時候釋放,系統自動釋放是在當前runloop循環結束的時候。
(2)
(3)
6、如果父類有一個成員變量A,子類有A,B兩個變量,父類指針指向了子類,父類執行delete方法,子類的變量會被釋放嗎?怎么才能被釋放?執行子類的delete方法,兩個變量會被釋放嗎?
7、內存泄漏可能出現的幾種原因?怎么處理?
答:(1)第三方框架不當使用,block、delegate和NSTimer的循環引用,非OC對象內存處理,地圖類處理,大次數循環內存暴漲。
(2)非OC對象處理:非OC對象,其需要手動執行釋放操作例:CGImageRelease(ref),否則會造成大量的內存泄漏導致程序崩潰;其他的對于CoreFoundation框架下的某些對象或變量需要手動釋放、C語言代碼中的malloc等需要對應free。
地圖類內存泄漏處理:地圖是比較耗費App內存的,因此在根據文檔實現某地圖相關功能的同時,需要注意內存的正確釋放,大體需要注意的有需在使用完畢時將地圖、代理等滯空為nil;注意地圖中標注(大頭針)的復用,并且在使用完畢時清空標注數組等。
2、線程處理
1、線程安全?
答:不知道要問什么,問lock?還是其他?lock的話有:NSLock、OSSpinLock、NSRecursiveLock、pthread_mutex_t。 我們還可以用serial dispatch_queue_t來作lock。還有dispatch_barrier也可以。至于用哪個,就要具體分析了。
2、NSOpearation可不可以停止?
答:?調用cancel方法可以將NSOperationQueue當前狀態設為cancelled,在operation運行中我們要不斷的檢查當前的operationQueue的狀態,看isCancelled返回是否為真,若為真,則立刻結束operation。
3、NSThread,GCD,NSOperation相關的。開啟一條線程的方法?線程可以取消嗎?
4、子線程中調用connection方法,為什么不回調?
答:因為沒有加入runloop,執行完任務就銷毀了,所以沒有回調。
5、GCD和NSOperation的區別?
3、網絡請求
????1、簡述http狀態碼及請求過程,自己寫http框架,緩存,異步,并發高性能的解決方案?
答:根據我的經驗,用過的HTTP狀態碼有: 200 OK, 201 Created, 302 Redirect, 304 Not Modified, 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 408 Request Time out, 500 Internal Error, 503 Server Not Available。網上能找到全部的狀態碼,但個人覺得記住一些常用的就足夠了,當碰到特殊情況要使用其他狀態碼,查資料就好了。
????對于http框架,在ios中,通常通過封裝NSURLSession來完成網絡層的開發,主要注意的是網絡層應獨立,只完成與后臺API的通信,把數據處理或其他與網絡通信無關的內容分離開來。
????緩存,除非有特殊要求,個人建議還是使用NSURLCache或者NSCache來完成。如果服務器支持的話,應該好好利用304狀態碼的特性,這樣會節省流量,而且網絡響應會快些。
????異步這個我覺得不用多說了吧?NSURLSession都是異步的。
????對于并發高性能:需要知道的是,NSURLSession在iOS中最多可以有4個tasks同時運行,所以應該復用所創建的NSURLSession, 在它之上創建不同的tasks。如果像是tableview中加載圖片,可以創建一個隊列(queue), 如果tasks超過4個,把超過的放入這個隊列中,當之前的任務完成時,檢查隊列中有沒有等待的,如果有,把它們從隊列中取出來,然后[task resume]。
????2、在杭州HTTP請求服務器響應快,可能離服務器距離近,而在深圳訪問就很慢很慢,會是什么原因?如果用戶投訴,怎么分析這個問題?
????3、TCP建立連接的過程,斷開連接的過程,為什么是四次握手?
2、socket編程簡述
3、asihttp代碼原理 ,異步請求的原理,異步請求最大數目,為什么只能這么多?
4、http請求方式?
4、優化處理
1、UI、動畫及動畫優化方案,UITableViewCell優化方案?
答:??UI, 動畫優化要根據實際情況以及profiling的結果來進行具體分析,光這樣問還真不知道該怎么回答。
????UITableViewCell的優化也是如此,但是一般的套路是profiling, 盡量少加subviews, 減少off-screen rendering, 比如圓角圖片,可以在下載圖片時在后臺直接畫圓角在圖片中。下載圖片時盡量使用caching。在加載數據時,盡量減少數據處理的時間,盡量不要fetching core data 等等。
2、造成UITabelView卡頓的原因有哪些?
答:1.最常用的就是cell的重用, 注冊重用標識符
如果不重用cell時,每當一個cell顯示到屏幕上時,就會重新創建一個新的cell,當有很多數據的時候,就會堆積很多cell。
如果重用cell,為cell創建一個ID,每當需要顯示cell 的時候,都會先去緩沖池中尋找可循環利用的cell,如果沒有再重新創建cell。
2.避免cell的重新布局
cell的布局填充等操作比較耗時,一般創建時就布局好;如可以將cell單獨放到一個自定義類,初始化時就布局好。
3.提前計算并緩存cell的屬性及內容
當我們創建cell的數據源方法時,編譯器并不是先創建cell再定cell的高度,而是先根據內容一次確定每一個cell的高度,高度確定后,再創建要顯示的cell,滾動時,每當cell進入憑虛都會計算高度,提前估算高度告訴編譯器,編譯器知道高度后,緊接著就會創建cell,這時再調用高度的具體計算方法,這樣可以方式浪費時間去計算顯示以外的cell。
4.減少cell中控件的數量
盡量使cell得布局大致相同,不同風格的cell可以使用不用的重用標識符,初始化時添加控件,不適用的可以先隱藏。
5.不要使用ClearColor,無背景色,透明度也不要設置為0
渲染耗時比較長。
6.使用局部更新
如果只是更新某組的話,使用reloadSection進行局部。
7.加載網絡數據,下載圖片,使用異步加載,并緩存
8.少使用addView 給cell動態添加view
9.按需加載cell,cell滾動很快時,只加載范圍內的cell
10.不要實現無用的代理方法,tableView只遵守兩個協議
11.緩存行高:estimatedHeightForRow不能和HeightForRow里面的layoutIfNeed同時存在,這兩者同時存在才會出現“竄動”的bug。所以我的建議是:只要是固定行高就寫預估行高來減少行高調用次數提升性能。如果是動態行高就不要寫預估方法了,用一個行高的緩存字典來減少代碼的調用次數即可
12.不要做多余的繪制工作。在實現drawRect:的時候,它的rect參數就是需要繪制的區域,這個區域之外的不需要進行繪制。例如上例中,就可以用CGRectIntersectsRect、CGRectIntersection或CGRectContainsRect判斷是否需要繪制image和text,然后再調用繪制方法。
13.預渲染圖像。當新的圖像出現時,仍然會有短暫的停頓現象。解決的辦法就是在bitmap context里先將其畫一遍,導出成UIImage對象,然后再繪制到屏幕;
14.使用正確的數據結構來存儲數據。
5、Runtime、RunLoop
1、Runtime是什么?
2、Runloop是什么?
3、說一下runtime?為什么OC里面是發消息,而C/C++是函數調用?
4、NSTimer時間準嗎?為什么不準?如果不準該怎么實現一個精準的NSTimer?
答:(1)不準;
(2)不準的原因:NSTimer加在main RunLoop中,模式是NSDefaultRunLoopMode,main負責所有主線程時間,例如UI界面的操作,復雜的運算,這樣在同一個RunLoop中timer就會產生阻塞;當模式的改變時,主線程RunLoop里有兩個預置的Mode:kCFRunLoopDefaultMode和UITrackingRunLoopMode,當你創建一個timer并加到DefaultMode時,timer會得到重復回調,但此時滑動一個ScrollView時,RunLoop會將mode切換為UITrackingRunLoopMode,這時timer就不會被回調,并且也不會影響到滑動操作,所以會影響到NSTimer不準的情況。
(3)
方法一:
在主線程中進行NSTimer操作,但是將NSTimer實例加到main runloop的特定mode(模式)中。避免被復雜運算操作或者UI界面刷新所干擾。
self.timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(showTime) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
在子線程中進行NSTimer的操作,再在主線程中修改UI界面顯示操作結果;
- (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]; }
}
總結:
一開始的時候系統就為我們將主線程的main runloop隱式的啟動了。
在創建線程的時候,可以主動獲取當前線程的runloop。每個子線程對應一個runloop
方法二:
使用mach內核級的函數可以使用mach_absolute_time()獲取到CPU的tickcount的計數值,可以通過”mach_timebase_info”函數獲取到納秒級的精確度 。然后使用mach_wait_until(uint64_t deadline)函數,直到指定的時間之后,就可以執行指定任務了。
關于數據結構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);
}
方法三:直接使用GCD替代!
6、數據存儲處理
1、本地數據庫海量數據如何提高查詢效率和存儲效率?
答:在ios中存儲數據基本上就是plist, sqlite 和core data (NSUserDefault其實也是plist), plist建議用在存儲簡單而且數據量不大的情況,而且對于查詢沒有太多要求的。sqlite可以高效的查詢和存儲數據,但是缺點是:C API, 要自己做封裝,而且每次都需要讀寫硬盤,對數據變化不敏感,要手動更新界面從而反應數據中的變化
在iOS開發中,除非有特殊需求,一般都建議使用Core Data.?
????如何提高查詢效率:(1)設置合適的index;(2)優化predicate,對于string類型,盡量不要使用"==";(3)使用batchSize;(4) 合理使用batchLimit;(5)對于需要用到的relationship objects,可以使用setRelationshipKeyPathsForPrefetching來減少Faulting overhead;(6)可以使用batchFaulting來減少Faulting overhead。
????如何提高存儲效率:(1) 盡量避免在main thread中寫數據;(2)不要在Core Data中保存圖片,文件等數據;(3)對于刪除,更新,盡量使用batch;(4)注意調用[NSManagedObjectContext save:]的時機,盡量是由在后臺運行的NSManagedObjectContext來完成寫入。
2、在block里面使用_property會造成循環引用嗎?怎么解決?除了使用self->_property,可以使用valueforkey來訪問嗎 在block里面可以修改它的值嗎setvalueforkey?可以修改它的值,可以用valueforkey來解決,顯式的的使用self,block外先持有self的弱引用。
3、sqlite中插入特殊字符的方法和接收到處理方法?
4、1.CoreData的架構?CoreData的fault機制?CoreData的優勢?2.OC語言的特點是什么(或是和其他語言的區別)?OC runtime為什么可以動態添加變量和方法?
7、生命周期
1、Viewcontroller的生命周期?
2、viewcontroller的一些方法的說明viewDidLoad, viewWillDisappear, viewWillAppear方法的順序和作用?
8、設計模式
1、MVC相互通訊規則知道哪些?
答:MVC是一種設計思想、框架模式和一種把應用中所有類組織起來的策略,把程序分成三塊,分別是:
M(Model):負責存取數據。
V(View):用于構建視圖,一般根據Model來創建視圖。
C(Controller):控制你Model如何呈現在屏幕上,當它需要數據的時候就告訴Model,你幫我獲取某某數據;當它需要UI展示和更新的時候就告訴View,你幫我生成一個UI顯示某某數據,是MOdel和View的溝通橋梁。
C to M
可以直接單向通信。Controller 需要將 Model 呈現給用戶,因此需要知道模型的一切,還需要有同 Model 完全通信的能力,并且能任意使用 Model 的公共 API。
C to V
可以直接單向通信。Controller 通過 View 來布局用戶界面。
M to V
永遠不要直接通信。Model 是獨立于 UI 的,并不需要和 View 直接通信,View 通過 Controller 獲取 Model 數據。
V to C?
View 不能對 Controller 知道的太多,因此要通過間接的方式通信。
Target
action:首先 Controller 會給自己留一個 target,再把配套的 action 交給 View 作為聯系方式。那么 View接收到某些變化時,View 就會發送 action 給 target 從而達到通知的目的。這里 View 只需要發送action,并不需要知道 Controller 如何去執行方法。
代理:有時候 View 沒有足夠的邏輯去判斷用戶操作是否符合規范,他會把判斷這些問題的權力委托給其他對象,他只需獲得答案就行了,并不會管是誰給的答案。
DataSoure:View 沒有擁有他們所顯示數據的權力,View 只能向 Controller 請求數據進行顯示,Controller 則獲取 Model 的數據整理排版后提供給 View。
M to C
同樣的 Model 是獨立于 UI 存在的,因此無法直接與 Controller 通信,但是當 Model 本身信息發生了改變的時候,會通過下面的方式進行間接通信。
Notification & KVO一種類似電臺的方法,Model 信息改變時會廣播消息給感興趣的人 ,只要 Controller 接收到了這個廣播的時候就會主動聯系 Model,獲取新的數據并提供給 View。
?MVC 模式的優點:(1)低耦合性;(2)有利于開發分工;(3)有利于組件重用;(4)可維護性。
9、其他
1、說下OC發消息的過程
2、索引的缺點?
答:(1) 需要空間儲存索引;(2) 創建和維護索引需要耗費時間;(3)當刪除,插入和更新數據時,索引也需要進行更新,這樣降低了寫數據的速度。
3、斷點續傳怎么實現?需要設置什么?
答:?可使用NSURLSession來完成. 主要通過以下的方法
????- (void)cancelByProducingResumeData:(void (^)(NSData *resumeData))completionHandler;
????- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData;
????如果不是使用NSURLSession, 則要麻煩一些,首先必需在暫停時記錄下當前已接收的文件長度,在下一次開始時設置HTTP header里的Range:
????NSString *range = [NSString stringWithFormat:@"bytes=%lld-", self.receivedLength];
????[request setValue:range forHTTPHeaderField:@"Range"];
4、什么是OC對象?union是OC對象嗎? block是OC對象嗎?
答:
(1)每個 Objective-C 對象都是指向某塊內存數據的指針,所以在聲明變量時,類型后面要跟一個“*”字符:Class的定義:一個結構體
(2)Union不是OC對象
(3)block是特殊的OC對象,定義是個結構體類型,其他OC對象分配在堆上,block是分配在棧上。
5、id是什么類型?
答:是一個指針類型的,可以指向任意OC對象類型的通用對象類型。定義也是結構體。
6、自定義一個類,有兩個方法,一個是以new開頭的,另一個不是以new開發的,方法里面都是alloc init方法,這兩個方法有什么不同?引用計數變化?ARC下,編譯器會插入什么語句?
7、在init方法里面,設置背景顏色,會生效嗎?
答:會生效。為什么會?
8、了解UIKit結構?
9、OC中的鎖是什么?有哪些?常用的有哪里?
答:(1)在計算機科學中,鎖是一種同步機制,用于在存在多線程的環境中實施對資源的訪問機制,可以理解為它是用于排除并發的一種策略。
(2)iOS中鎖的種類:遞歸鎖、條件鎖、分布式鎖、一般鎖(根據NSLock類里面的分類進行劃分)。
(3)@synchronized(關鍵字加鎖)、NSLock(対象鎖)、NSCondition、NSConditionLock(條件鎖)、NSRecursiveLock(遞歸鎖)、pthread_mutex(互斥鎖)、dispatch_semaphore(信號量實現加鎖(GCD))、OSSpinLock、pthread_rwlock、POSIX Conditions、os_unfair_lock。
10、自旋鎖和互斥鎖的異同點?
答:(1)共同點:都能保證同一時間只有一個線程訪問共享資源。都能保證線程安全。
(2)不同點:
互斥鎖:如果共享數據已經有其他線程加鎖了,線程會進入休眠狀態等待鎖。一旦被訪問的資源被解鎖,則等待資源的線程會被喚醒。
自旋鎖:如果共享數據已經有其他線程加鎖了,線程會以死循環的方式等待鎖,一旦被訪問的資源被解鎖,則等待資源的線程會立即執行。
自旋鎖的效率高于互斥鎖
使用自旋鎖時要注意:
由于自旋時不釋放CPU,因而持有自旋鎖的線程應該盡快釋放自旋鎖,否則等待該自旋鎖的線程會一直在哪里自旋,這就會浪費CPU時間。
持有自旋鎖的線程在sleep之前應該釋放自旋鎖以便其他可以獲得該自旋鎖。內核編程中,如果持有自旋鎖的代碼sleep了就可能導致整個系統掛起。
使用任何鎖都需要消耗系統資源(內存資源和CPU時間),這種資源消耗可以分為兩類:
1.建立鎖所需要的資源
2.當線程被阻塞時所需要的資源
11、用C/C++/OC,任選其一,實現自旋或互斥?
答:(1)原理:
互斥鎖:線程會從sleep(加鎖)——>running(解鎖),過程中有上下文的切換,cpu的搶占,信號的發送等開銷。
自旋鎖:線程一直是running(加鎖——>解鎖),死循環檢測鎖的標志位,機制不復雜。
(2)
12、編譯做過哪些事情?
答:C++,Objective-C都是編譯語言,編譯語言在執行的時候,必須先通過編譯器生成機器碼,機器碼可以直接在CPU上執行,所以執行效率高。
iOS開發目前的常用語言是:Objective和Swift。二者都是編譯語言,換句話說都是需要編譯才能執行的。二者的編譯都是依賴于Clang + LLVM. OC和Swift因為原理上大同小異,知道一個即可!
不管是OC還是Swift,都是采用Clang作為編譯器前端,LLVM(Low level vritual machine)作為編譯器后端。所以簡單的編譯過程如圖:
編譯器前端(Clang)的任務:語法分析,語義分析,生成中間代碼(intermediate representation )。在這個過程中,會進行類型檢查,如果發現錯誤或者警告會標注出來在哪一行。
編譯器后端(LLVM(Low level vritual machine))的任務:對機器無關的代碼優化,生成機器語言,并且進行機器相關的代碼優化。
執行一次Xcode build的流程(當你在Xcode中,選擇build的時候(快捷鍵command+B)):
(1)編譯信息寫入輔助文件,創建編譯后的文件架構(name.app);
(2)處理文件打包信息,例如在debug環境下:
Entitlements: {
"application-identifier"="app的bundleid";
"aps-environment"=development;
}
(3)執行CocoaPod編譯前腳本,例如對于使用CocoaPod的工程會執行CheckPods Manifest.lock
(4)編譯各個.m文件,使用CompileC和clang命令:
1.CompileC ClassName.o ClassName.m normal x86_64 objective-c com.apple.compilers.llvm.clang.1_0.compiler
2.export LANG=en_US.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
13、frame 和 bounds 的 區別 ,bound的大小改變frame 改變嗎?
第三方框架問答
1、項目里面使用到什么網絡庫,用過ASIHTTP庫嗎?
2、使用過哪些第三方庫?
答:AFNetworking、SDWebImage、MBProgressHUD、MJRefresh、Masonry
3、SDWebImage的實現過程
(1)入口?setImageWithURL:placeholderImage:options: 會先把?placeholderImage?顯示,然后?SDWebImageManager?根據?URL?開始處理圖片;
(2)進入?SDWebImageManagerdownloadWithURL:delegate:options:userInfo:交給?SDImageCache?從緩存查找圖片是否已經下載?queryDiskCacheForKey:delegate:userInfo:。
(3)先從內存圖片緩存查找是否有圖片,如果內存中已經有圖片緩存,SDImageCacheDelegate?回調?imageCache:didFindImage:forKey:userInfo:?到?SDWebImageManager;
(4)SDWebImageManagerDelegate?回調?webImageManager:didFinishWithImage:到?UIImageView+WebCache?等前端展示圖片;
(5)如果內存緩存中沒有,生成?NSInvocationOperation添加到隊列開始從硬盤查找圖片是否已經緩存;
(6)根據?URLKey?在硬盤緩存目錄下嘗試讀取圖片文件。這一步是在?NSOperation?進行的操作,所以回主線程進行結果回調?notifyDelegate:;
(7)如果上一操作從硬盤讀取到了圖片,將圖片添加到內存緩存中(如果空閑內存過小,會先清空內存緩存),SDImageCacheDelegate?回調?imageCache:didFindImage:forKey:userInfo:進而回調展示圖片;
(8)如果從硬盤緩存目錄讀取不到圖片,說明所有緩存都不存在該圖片,需要下載圖片,回調?imageCache:didNotFindImageForKey:userInfo:;
(9)共享或重新生成一個下載器?SDWebImageDownloader?開始下載圖片;
(10)圖片下載由?NSURLConnection?來做,實現相關?delegate?來判斷圖片下載中、下載完成和下載失敗;
(11)connection:didReceiveData:?中利用?ImageIO?做了按圖片下載進度加載效果。
(12)connectionDidFinishLoading:?數據下載完成后交給?SDWebImageDecoder?做圖片解碼處理。
(13)圖片解碼處理在一個?NSOperationQueue?完成,不會拖慢主線程?UI。如果有需要對下載的圖片進行二次處理,最好也在這里完成,效率會好很多;
(14)在主線程?notifyDelegateOnMainThreadWithInfo: 宣告解碼完成,imageDecoder:didFinishDecodingImage:userInfo 回調給?SDWebImageDownloader;
(15)imageDownloader:didFinishWithImage:回調給?SDWebImageManager?告知圖片下載完成;
(16)通知所有的?downloadDelegates?下載完成,回調給需要的地方展示圖片;
(17)將圖片保存到?SDImageCache?中,內存緩存和硬盤緩存同時保存,寫文件到硬盤也在以單獨?NSInvocationOperation?完成,避免拖慢主線程;
(18)SDImageCache?在初始化的時候會注冊一些消息通知,在內存警告或退到后臺的時候清理內存圖片緩存應用結束的時候清理過期圖片;
(19)SDWI?也提供了?UIButton+WebCache?和MKAnnotationView+WebCache,方便使用;
(20)SDWebImagePrefetcher?可以預先下載圖片,方便后續使用。
數據結構相關問答
1、數據結構與算法相關。知道哪些數據結構?
答:線性表(具體點 數組)連接、棧、隊列、二叉樹、堆。
2、什么是完全二叉樹?堆是什么數據結構?
答:若設二叉樹的深度為h,除第 h 層外,其它各層 (1~h-1) 的結點數都達到最大個數,第 h 層所有的結點都連續集中在最左邊,這就是完全二叉樹。
3、向量和鏈表的區別?什么時候選擇vector?什么時候選擇使用鏈表?
4、強連通分量了解嗎?
答:
(1)概念:有向圖強連通分量:在有向圖G中,如果兩個頂點vi,vj間(vi>vj)有一條從vi到vj的有向路徑,同時還有一條從vj到vi的有向路徑,則稱兩個頂點強連通(strongly connected)。如果有向圖G的每兩個頂點都強連通,稱G是一個強連通圖。有向圖的極大強連通子圖,稱為強連通分量(strongly connected components)。
(2)定義:
有向圖強連通分量:
在有向圖G中,如果兩個頂點間至少存在一條路徑,稱兩個頂點強連通(strongly connected)。
如果有向圖G的每兩個頂點都強連通,則稱G是一個強連通圖。
非強連通圖有向圖的極大強連通子圖,成為強連通分量(strongly connected components)。
下圖中,子圖{1,2,3,4}為一個強連通分量,因為頂點1,2,3,4兩兩可達,{5},{6}也分別是兩個強連通分量。
有向圖強連通分量
直接根據定義,用雙向遍歷取交際的方法求強連通分量,時間復雜度為O(N^2+M)。更好的方法是Kosaraju算法或者Tarjan算法兩者的時間復雜度都是O(N+M)。本文介紹的是Tarjan算法。
原理:
Tarjan算法是基于對圖深度優先搜索的算法,每個強連通分量為搜索樹中的一顆子樹。
搜索時,把當前搜索樹中未處理的節點加入一個堆棧,回溯時可以盤對棧頂到棧中的節點是否為一個強連通分量。
定義DFN(u)為節點u搜索的次序編號(時間戳)。Low(u)為u或者u的子樹能夠追溯到的最早的棧中的節點的次序號。
由定義可以得出:
Low(u)= Min { DFN(u), Low(v)} ((u,v)為樹枝邊,u為v的父節點DFN(v),(u,v)為指向棧中節點的后向邊(非橫叉邊))
當DFN(u)=Low(u)時,以u為根的搜索子樹上所有節點是一個強連通分量。
5、iOS中哪里用到棧了?開發過程中哪里用到鏈表了?棧的特點,鏈表的特點
6、字典的實現原理?
答:(1)NSDictionary(字典)是使用hash表來實現key和value之間的映射和存儲的方法:
-?(void)setObject:(id)anObject?forKey:(id)aKey;
Objective-C中的字典NSDictionary底層其實是一個哈希表。
(2)哈希原理
散列表(Hash table,也叫哈希表),是根據關鍵碼值(Key value)而直接進行訪問的數據結構。也就是說,它通過把關鍵碼值映射到表中一個位置來訪問記錄,以加快查找的速度。這個映射函數叫做散列函數,存放記錄的數組叫做散列表。給定表M,存在函數f(key),對任意給定的關鍵字值key,代入函數后若能得到包含該關鍵字的記錄在表中的地址,則稱表M為哈希(Hash)表,函數f(key)為哈希(Hash) 函數。
哈希概念:哈希表的本質是一個數組,數組中每一個元素稱為一個箱子(bin),箱子中存放的是鍵值對。
(3)哈希存儲過程:根據key計算它的哈希值h;假設箱子的個數為n,那么這個鍵值對應該放在第(h%n)個箱子中;如果該箱子中已經有了鍵值對,就使用開放尋址法或者拉鏈法解決沖突。
在使用拉鏈法解決哈希沖突時,每個箱子其實是一個鏈表,屬于同一個箱子的所有鍵值對都會排列在鏈表中。
哈希表還有一個重要的屬性: 負載因子(load factor),它用來衡量哈希表的空/滿程度,一定程度上也可以體現查詢的效率,計算公式為:
負載因子 = 總鍵值對數 / 箱子個數
負載因子越大,意味著哈希表越滿,越容易導致沖突,性能也就越低。因此,一般來說,當負載因子大于某個常數(可能是 1,或者 0.75 等)時,哈希表將自動擴容。
哈希表在自動擴容時,一般會創建兩倍于原來個數的箱子,因此即使 key 的哈希值不變,對箱子個數取余的結果也會發生改變,因此所有鍵值對的存放位置都有可能發生改變,這個過程也稱為重哈希(rehash)。
哈希表的擴容并不總是能夠有效解決負載因子過大的問題。假設所有 key 的哈希值都一樣,那么即使擴容以后他們的位置也不會變化。雖然負載因子會降低,但實際存儲在每個箱子中的鏈表長度并不發生改變,因此也就不能提高哈希表的查詢性能。
基于以上總結,細心的朋友可能會發現哈希表的兩個問題:
1.如果哈希表中本來箱子就比較多,擴容時需要重新哈希并移動數據,性能影響較大。
2.如果哈希函數設計不合理,哈希表在極端情況下會變成線性表,性能極低。
3.block和函數指針的理解;
相似點:
函數指針和Block都可以實現回調的操作,聲明上也很相似,實現上都可以看成是一個代碼片段。
函數指針類型和Block類型都可以作為變量和函數參數的類型。(typedef定義別名之后,這個別名就是一個類型)
不同點:
函數指針只能指向預先定義好的函數代碼塊(可以是其他文件里面定義,通過函數參數動態傳入的),函數地址是在編譯鏈接時就已經確定好的。
Block本質是Objective-C對象,是NSObject的子類,可以接收消息。
函數里面只能訪問全局變量,而Block代碼塊不光能訪問全局變量,還擁有當前棧內存和堆內存變量的可讀性(當然通過__block訪問指示符修飾的局部變量還可以在block代碼塊里面進行修改)。
從內存的角度看,函數指針只不過是指向代碼區的一段可執行代碼,而block實際上是程序運行過程中在棧內存動態創建的對象,可以向其發送copy消息將block對象拷貝到堆內存,以延長其生命周期。
7、談談你對數組和鏈表認識,還有你是怎么用他們的?
簡單算法相關問答
1、100個數,找出其中重復的數?
2、10個數,找出其中最大數和最小數,沒有值相等的。
3、歸并排序的過程
4、堆排序的過程、快排的過程
5、冒泡排序法
答:
NSMutableArray *arr = [[NSMutableArray alloc] initwithArray:@[@"1",@"2",@"6",@"4"]];
for (int i = 0; i < arr.count-1; i++) {
? ? ?for (int j = 0; j < arr.count-1-i; j++) {
? ? ? ? ? ? int a = [[arr objectWithIndex:j] intValue];
? ? ? ? ? ??int b = [[arr objectWithIndex:j+1] intValue];
? ? ? ? ? ?if (a < b) {
? ? ? ? ? ? ? ? [arr replaceObjectAtIndex:j withObject:[NSString stringWithFormat:@"%d",b]];
? ? ? ? ? ? ? ? [arr replaceObjectAtIndex:j+1 withObject:[NSString stringWithFormat:@"%d",a]];
? ? ? ? ? ?}
? ? }
}
6、用最有效的代碼實現 1. 對一個排序整型數組去重 2. 對一個排序整型數組找出其中兩數和為K的組合 3. 救兩個數組的交集
7、猴子摘香蕉,共50個,一次可以摘一個或兩個,問摘法種數?
答:?
斐波那契數列
long long fun1(long long n) {
? ? return n > 1 ? fun1(n-1) + fun1(n-2) : 1;
}
long long fun2(long long n) {
? ? ? ?long long a1 = 1, a2 = 1, t = 0;
? ? ? ?for (int i=1; i < n; i++) {
? ? ? ? ? ?t = a1 + a2;
? ? ? ? ? ?a1 = a2;
? ? ? ? ? ?a2 = t;
? ? ? ? }
? ? ? ?return n > 1 ? t : 1;
}
8、求循環數組的頭?請參考網上很多代碼,對于鏈表的話,有兩個指針,一個走一步,一個走兩步,就能確定是否是循環數組。
9、交換兩個數組 使他們的和盡量最小
10、二叉樹前序遍歷非DFS實現
答:DFS:深度優先搜索
其他語言相關知識
1、C++相關的。什么是虛函數?虛函數是怎么實現的?什么是多態?
2、為什么類的析構函數設置成虛函數?為什么構造函數不設置成虛函數?
3、GPUimage的濾鏡鏈問題,NSDictionary的實現,以及復雜度。
參考網站:
http://www.lxweimin.com/p/dd17bdcff9f7
http://www.lxweimin.com/p/92653db0e76a
http://www.cocoachina.com/bbs/read.php?tid=460991
1. void merge (int &a[], int count) { int i = 0, j = i+1 while ( i!=j && j