ios面試題目(一)

1.多線程在實際現實中有哪些應用?(網絡操做和大量圖片處理不算)

一般耗時的操做都會放在子線程裏處理,而後再回到主線程來顯示。下面舉幾個例子:html

  1. 咱們要從數據庫提取數據還要將數據分組後顯示,那麼就會開個子線程來處理,處理完成後纔去刷新UI顯示。
  2. 拍照後,會在子線程處理圖片,完成後纔回到主線程來顯示圖片。拍照出來的圖片太大了,所以要作處理。
  3. 音頻、視頻處理會在子線程來操做
  4. 文件較大時,文件操做會在子線程中處理
  5. 作客戶端與服務端數據同步時,會在後臺閒時自動同步

 

二、若是app比較大,怎麼樣減小app的大小?

參考答案:

  1. 將build setting中的Optimization Level設置爲Fastest, Smallest [-Os],在發佈模式下,默認就是這樣設置的
  2. 將build setting 中的Strip Debug Symbols During Copy設置爲YES,在發佈模式下,默認就是這樣設置的
  3. 資源文件查找出全部未使用的,去掉這些永遠不會使用的資源文件
  4. 對嵌入App的音頻進行壓縮處理

三、你在迭代開發中是怎麼處理版本兼容問題?

參考答案:

版本迭代必定要注意兼容老版本,好比新增了字段或者去掉了某些再也不使用的字段,不能引發應用閃退。咱們這裏只談程序代碼兼容新老版本問題,不考慮業務。由於業務是要求後臺來兼容的,一般接口會有版本號控制,用於兼容不一樣版本的客戶端。前端

對於任何一個App,當能夠升級的時候,不會是全部用戶就馬上去升級,一般會有很大一部分的用戶是不肯意馬上升級的。緣由會有不少種,好比我這種的就不會頻繁升級,由於對於我來講,這個App並非每天用,沒有必要升級。ios

那麼,咱們在iOS開發時,如何去兼容老版本的,保證新版本的增長或者刪減不會影響到老版本呢?其實這個問題彷佛並非說有沒有新、老版本問題,更重要的是程序的健壯性問題。算法

對於咱們作前端的,永遠不要相信後臺必定會按照原先約定返回咱們想要的數據結構以及全部字段。數據庫

假設接口返回來的數據是這樣的,咱們須要經過類型判斷,確保不會由於接口變化返回無效數據而引發閃退。固然,當接口返回的數據結構與咱們原先約定的不同時,一般是由於後臺出錯了,所以爲了程序更健壯,咱們應該要容得下後臺的錯誤:編程

 
AFHTTPRequestOperation *op = [selfPostRequestWithUrl:urlparams:paramscompletion:^(id responseObject) {
  BOOL isSuccess = NO;
  if ([responseObjectisKindOfClass:[NSDictionary class]]) {          NSDictionary *response = responseObject[@"response"];     if ([responseisKindOfClass:[NSDictionary class]]) {              NSArray *resultList = response[@"resultList"];       if ([resultListisKindOfClass:[NSArray class]]) {         NSArray *listModels = [HYBCosmesisModelobjectArrayWithKeyValuesArray:resultList];         isSuccess = YES;         completion(listModels);       }     }   }      if (!isSuccess) {     // 表示出錯     completion(nil);   } }errorBlock:^(NSError *error) {   errorBlock(error); }];   

而咱們在使用的時候,對於字符串、數組、字典都應該要作一下類型判斷和空處理。好比:swift

 
if ([responseisKindOfClass:[NSDictionary class]]) {   NSString *value = response[@"blogName"];   if (!kIsEmptyString(value)) {     // Do my job   }      NSArray *array = response[@"array"];   if ([arrayisKindOfClass:[NSArray class]]) {     // Do my job   } }   

對於業務方面的話,由後臺來作版本控制,經過在接口作添加公共參數,[email protected] 後端

�要調用的是哪一個版本的接口。設計模式

 

四、你和後端服務器是怎麼進行交互的

參考答案:

這個問題很是簡單,可是對於新手就不太清楚了。在不少小公司裏,前端好像什麼都不須要管,只等後臺給你一個接口及參數說明就能夠了,根本不清楚後端爲何要這麼設計這個接口。數組

那筆者也來聊聊如何與後端服務器交互:

  1. 在需求肯定,定下了開發的週期後,就須要準備開發了。
  2. iOS、安卓及後端各端主要負責人員在瞭解完需求後,開始分析本期需求須要哪些接口,是否須要新的接口,是否須要改動原有的接口等。在三端統一後,後端接口負責人肯定哪天出接口文檔及接口假數據。爲何要三端一塊兒定接口呢?由於即便是後端接口負責人,也不必定對原有的業務和原有的接口所有都瞭解,任何一方的瞭解加起來才能肯定是否可行。
  3. 若是App尚未開發過,首先開發一款新的App,那麼iOS、安卓端的架構師,或者主要開發負責人,須要與後端接口負責人共同分析需求,而後初步寫出初版本接口文檔,而後各方再各自好好看看、分析分析接口是否合理,參數是否合理,結構是否合理等。這數據的結構會決定着整個網絡框架的搭建。

好了,就扯談這些吧~

 

五、怎麼用GCD加載多張圖片以後,把圖片放到融合到一張圖片裏?

參考答案:

使用Dispatch Group追加block到Global Group Queue,這些block若是所有執行完畢,就會執行Main Dispatch Queue中的結束處理的block。

當放到group中的全部請求都完成時,纔會回調dispatch  group notify的block: 

 
dispatch_queue_tqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_tgroup = dispatch_group_create();
dispatch_group_async(group, queue, ^{ /*加載圖片1 */ }); dispatch_group_async(group, queue, ^{ /*加載圖片2 */ }); dispatch_group_async(group, queue, ^{ /*加載圖片3 */ }); dispatch_group_notify(group, dispatch_get_main_queue(), ^{     // 合併圖片 });   

六、使用GCD的時候,如何在一個group裏添加幾個任務的依賴關係(這幾個任務放在一個組中)

參考答案:

這個不太清楚想問什麼,筆者翻看了看GCD中dispatch  group t裏,也沒有什麼能夠設置同一個組內的任務依賴關係的,就看到dispatch  group wait這個API: 

 
long
dispatch_group_wait(dispatch_group_tgroup, dispatch_time_ttimeout);
 

這個API是等待group中的全部任務都執行完畢才能繼續往下執行其它任務。它是同步地等待任務執行完畢。好比,A、B、C、D四個任務,要求A、B執行完畢後,C、D才能開始執行,那麼能夠經過這樣作:

 
dispatch_queue_tqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_tgroup = dispatch_group_create();
 
dispatch_group_async(group, queue, ^{ /* 任務A */ }); dispatch_group_async(group, queue, ^{ /* 任務B */ }); dispatch_group_notify(group, dispatch_get_main_queue(), ^{     dispatch_group_async(group, queue, ^{ /* 任務C */ });     dispatch_group_async(group, queue, ^{ /* 任務D */ }); });   

或者能夠這樣:

 
dispatch_queue_tqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_tgroup = dispatch_group_create();
 
dispatch_group_async(group, queue, ^{ /* 任務A */ }); dispatch_group_async(group, queue, ^{ /* 任務B */ }); // 同步等待A、B執行 dispatch_group_wait(group, DISPATCH_TIME_FOREVER); dispatch_release(group);   // 從新建立組 group = dispatch_group_create(); dispatch_group_async(group, queue, ^{ /* 任務C */ }); dispatch_group_async(group, queue, ^{ /* 任務D */ }); dispatch_group_notify(group, dispatch_get_main_queue(), ^{     // C、D執行完畢後,想幹嗎就幹嗎去吧 });   

不知道筆者對題目的理解是否到位,上面的代碼是隨手寫的,可能單詞會寫錯~~~

 

7 iOS如何在用戶修改頭像後正常顯示

 

方案一

筆者所能想到的方案:

筆者針對這個問題,第一想到的就是經過圖片的摘要驗證。服務端在接口中返回用戶信息時,連同圖片的摘要(md5)值也下發到客戶端,而後每次App登陸時,服務端都將最新的用戶信息返回來,客戶端將本地所緩存的用戶頭像取出,也生成摘要(md5)五,與服務端所返回來的md5值比較,若相同表示沒有頭像沒有修改過;若不相同,表示頭像已經修改過。

缺點:只要從新登陸或者App在後臺自動登陸後,才能更新。也就是說,若是用戶沒有退出登陸,或者沒有過時而不會自動登陸,頭像也沒有更新得了。

方案二

在微博上收集到你們的方案。給URL添加一個參數version,當圖片修改以後,URL的version發生變化,那麼就會從新下載圖片來緩存。

缺點:與方案一相似,要求從新請求數據才能獲得最新的URL。

方案三

在修改圖片時,要求不能使用相同的名字,這樣連接路徑是同樣的,可是由於名字不一樣而找不到。此時,就會從新獲取圖片而不是緩存的。能夠在文件名中帶上前綴進行上傳,譬如avatar-3/v1.jpg,更新後改成avatar-3/v2.jpg。

方案四

客戶端在請求頭加上If-Modified-Since字段,代表請求此時間後最新的文件資源,服務端也會在響應頭返回這個last-modified字段表示上次修改時間。

 

第二部分:

1 iOS基礎

1.1 父類實現深拷貝時,子類如何實現深度拷貝。父類沒有實現深拷貝時,子類如何實現深度拷貝。

  • 深拷貝同淺拷貝的區別:淺拷貝是指針拷貝,對一個對象進行淺拷貝,至關於對指向對象的指針進行復制,產生一個新的指向這個對象的指針,那麼就是有兩個指針指向同一個對象,這個對象銷燬後兩個指針都應該置空。深拷貝是對一個對象進行拷貝,至關於對對象進行復制,產生一個新的對象,那麼就有兩個指針分別指向兩個對象。當一個對象改變或者被銷燬後拷貝出來的新的對象不受影響。

  • 實現深拷貝須要實現NSCoying協議,實現- (id)copyWithZone:(NSZone *)zone 方法。當對一個property屬性含有copy修飾符的時候,在進行賦值操做的時候實際上就是調用這個方法。

  • 父類實現深拷貝以後,子類只要重寫copyWithZone方法,在方法內部調用父類的copyWithZone方法,以後實現本身的屬性的處理

  • 父類沒有實現深拷貝,子類除了須要對本身的屬性進行處理,還要對父類的屬性進行處理。

1.2 KVO,NSNotification,delegate及block區別

  • KVO就是cocoa框架實現的觀察者模式,通常同KVC搭配使用,經過KVO能夠監測一個值的變化,好比View的高度變化。是一對多的關係,一個值的變化會通知全部的觀察者。
  • NSNotification是通知,也是一對多的使用場景。在某些狀況下,KVO和NSNotification是同樣的,都是狀態變化以後告知對方。NSNotification的特色,就是須要被觀察者先主動發出通知,而後觀察者註冊監聽後再來進行響應,比KVO多了發送通知的一步,可是其優勢是監聽不侷限於屬性的變化,還能夠對多種多樣的狀態變化進行監聽,監聽範圍廣,使用也更靈活。

  • delegate 是代理,就是我不想作的事情交給別人作。好比狗須要吃飯,就經過delegate通知主人,主人就會給他作飯、盛飯、倒水,這些操做,這些狗都不須要關心,只須要調用delegate(代理人)就能夠了,由其餘類完成所須要的操做。因此delegate是一對一關係。

  • block是delegate的另外一種形式,是函數式編程的一種形式。使用場景跟delegate同樣,相比delegate更靈活,並且代理的實現更直觀。

  • KVO通常的使用場景是數據,需求是數據變化,好比股票價格變化,咱們通常使用KVO(觀察者模式)。delegate通常的使用場景是行爲,需求是須要別人幫我作一件事情,好比買賣股票,咱們通常使用delegate。
    Notification通常是進行全局通知,好比利好消息一出,通知你們去買入。delegate是強關聯,就是委託和代理雙方互相知道,你委託別人買股票你就須要知道經紀人,經紀人也不要知道本身的顧客。Notification是弱關聯,利好消息發出,你不須要知道是誰發的也能夠作出相應的反應,同理發消息的人也不須要知道接收的人也能夠正常發出消息。

1.3 KVC若是實現,如何進行鍵值查找。KVO如何實現

請看這兩篇博文 KVC KVO

1.4 將一個函數在主線程執行的4種方法

  • GCD方法,經過向主線程隊列發送一個block塊,使block裏的方法能夠在主線程中執行。
dispatch_async(dispatch_get_main_queue(), ^{ //須要執行的方法 });
  • NSOperation 方法
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue]; //主隊列 NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ //須要執行的方法 }]; [mainQueue addOperation:operation];
  • NSThread 方法
[self performSelector:@selector(method) onThread:[NSThread mainThread] withObject:nil waitUntilDone:YES modes:nil]; [self performSelectorOnMainThread:@selector(method) withObject:nil waitUntilDone:YES]; [[NSThread mainThread] performSelector:@selector(method) withObject:nil];
  • RunLoop方法
[[NSRunLoop mainRunLoop] performSelector:@selector(method) withObject:nil]; 

1.5 如何讓計時器調用一個類方法

  • 計時器只能調用實例方法,可是能夠在這個實例方法裏面調用靜態方法。
  • 使用計時器須要注意,計時器必定要加入RunLoop中,而且選好model才能運行。scheduledTimerWithTimeInterval方法建立一個計時器並加入到RunLoop中因此能夠直接使用。
  • 若是計時器的repeats選擇YES說明這個計時器會重複執行,必定要在合適的時機調用計時器的invalid。不能在dealloc中調用,由於一旦設置爲repeats 爲yes,計時器會強持有self,致使dealloc永遠不會被調用,這個類就永遠沒法被釋放。好比能夠在viewDidDisappear中調用,這樣當類須要被回收的時候就能夠正常進入dealloc中了。
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES]; -(void)timerMethod { //調用類方法 [[self class] staticMethod]; } -(void)invalid { [timer invalid]; timer = nil; }

1.6 如何重寫類方法

  • 一、在子類中實現一個同基類名字同樣的靜態方法
  • 二、在調用的時候不要使用類名調用,而是使用[self class]的方式調用。原理,用類名調用是早綁定,在編譯期綁定,用[self class]是晚綁定,在運行時決定調用哪一個方法。

1.7 NSTimer建立後,會在哪一個線程運行。

  • 用scheduledTimerWithTimeInterval建立的,在哪一個線程建立就會被加入哪一個線程的RunLoop中就運行在哪一個線程
  • 本身建立的Timer,加入到哪一個線程的RunLoop中就運行在哪一個線程。

1.8 id和NSObject*的區別

  • id是一個 objc_object 結構體指針,定義是
typedef struct objc_object *id
  • id能夠理解爲指向對象的指針。全部oc的對象 id均可以指向,編譯器不會作類型檢查,id調用任何存在的方法都不會在編譯階段報錯,固然若是這個id指向的對象沒有這個方法,該崩潰仍是會崩潰的。

  • NSObject *指向的必須是NSObject的子類,調用的也只能是NSObjec裏面的方法不然就要作強制類型轉換。

  • 不是全部的OC對象都是NSObject的子類,還有一些繼承自NSProxy。NSObject *可指向的類型是id的子集。

個人理解若是有錯漏請必定指出,很是感謝!

如下內容後續補充

iOS 核心框架

  • CoreAnimation
  • CoreGraphics
  • CoreLocation
  • AVFoundation
  • Foundation

iOS核心機制

  • UITableView 重用
  • ObjC內存管理;自動釋放池,ARC如何實現
  • runloop
  • runtime
  • Block的定義、特性、內存區域、如何實現
  • Responder Chain
  • NSOperation
  • GCD

數據結構

  • 8大排序算法
  • 二叉樹實現
  • 二分查找實現

面向對象編程

  • 封裝、繼承、多態

  • 設計模式6個原則

  • 設計一個類的功能,如何劃分粒度(單一職責)

  • 接口隔離。

  • 若是有一個鳥類,有飛的動做,一個鴕鳥繼承它是合適的嗎(里氏替換)

  • 類之間的依賴如何依賴偶合度最小(依賴倒轉)
    高層依賴低層,低層不能依賴高層。依賴接口,不能依賴具體的類。

  • 若是A要調用C函數,但C是B的成員類,應該如何設計?(迪米特)

  • 如何設計類,能作到只增長代碼,而不修改代碼,有哪些經驗(開放封閉)
    經過設計模式解決。

計算機技術

  • 計算機網絡: TCP/IP、HTTPCDN、SPDY
  • 計算機安全: RSA、AES、DES
  • 操做系統:線程、進程、堆棧、死鎖、調度算法

iOS新特性、新技術

    • iOS7 UIDynamic、SpritKit、新佈局、扁平化
    • iOS8 應用程序擴展、HealthKit、SceneKit、CoreLocation、TouchID、PhotoKit
    • iOS9
    • Apple Watch
    • 第三方庫:SDWebImage、AFNetwork、JSONKit、wax
    • swift
相關文章
相關標籤/搜索