一份"有點難"的iOS面試題及答案

題目來源:http://mrpeak.cn/blog/ios_interview2/

問題及答案

1.NSString 如何計算字符的個數?

NSString是UTF-16編碼的, 也就是16位的unichar字符的序列. 因此, 通常遍歷其每個字符的方法就是:html

for(int i=0; i<str.length; i++){
    unichar ch = [str characterAtIndex: i];
}
複製代碼

對於「👍🏼」這種Emoji,是用2個16位unichar來表示,它的Unicode是U+1F44D, 用(U+D83D U+DC4D)兩個字符來表示。ios

幸虧,NSString的rangeOfComposedCharacterSequencesForRange:和rangeOfComposedCharacterSequenceAtIndex:兩個方法能夠用來處理這種狀況.程序員

NSRange range;
for(int i=0; i<str.length; i+=range.length){
    range = [str rangeOfComposedCharacterSequenceAtIndex:i];
    NSString *s = [str attributedSubstringFromRange:range];
}
複製代碼

一次遍歷一個子串, 而不是遍歷一個unichar了.數據庫

URL:http://blog.csdn.net/zhouleizhao/article/details/52816744編程

2.PKI體系中加密和簽名的區別?

加密證書和簽名證書均可以用來做非對稱加解密。swift

簽名密鑰對用於數據的完整性檢測,保證防僞造與防抵賴,簽名私鑰的遺失,並不會影響對之前簽名數據的驗證,所以,簽名私鑰無須備份,所以,簽名密鑰不須要也不該該須要第三方來管理。segmentfault

而加密密鑰對用於數據的加密保護若加密私鑰遺失,將致使之前的加密數據沒法解密,這在實際應用中是沒法接受的,加密私鑰應該由可信的第三方(即一般所說的CA)來備份。瀏覽器

URL:http://blog.sina.com.cn/s/blog_49453d720100xran.html緩存

3.如何本身高效實現NSUserdefault?

從使用和原理兩方面講起,使用方面,首先進行調用封裝和key鍵管理,封裝是爲了使用效率,key鍵管理是爲了方便修改和管理。服務器

從原理方面講,NSUserdefault 支持的數據類型有NSString、 NSNumber、NSDate、 NSArray、NSDictionary、BOOL、NSInteger、NSFloat等系統定義的數據類型。若是要進行頻繁的大數據存儲建議使用歸檔和數據庫等底層更優化的方式存儲。

4.解析TCP慢啓動特性?

TCP在鏈接過程的三次握手完成後,開始傳數據,並非一開始向網絡通道中發送大量的數據包,這樣很容易致使網絡中路由器緩存空間耗盡,從而發生擁塞。

TCP使用了一個叫慢啓動門限(ssthresh)的變量,一旦cwnd>=ssthresh(大多數TCP的實現,一般大小都是65536),慢啓動過程結束,擁塞避免階段開始;

擁塞避免:cwnd的值再也不指數級往上升,開始加法增長。此時當窗口中全部的報文段都被確認時,cwnd的大小加1,cwnd的值就隨着RTT開始線性增長,這樣就能夠避免增加過快致使網絡擁塞,慢慢的增長調整到網絡的最佳值。

URL:https://www.cnblogs.com/edisongz/p/6986527.html

5.如何用HTTP實現長鏈接?

輪詢:隔一段時間訪問服務器,服務器無論有沒有新消息都馬上返回。 設置HTTP長鏈接,有過時時間:

在首部字段中設置Connection:keep-alive 和Keep-Alive: timeout=60,代表鏈接創建以後,空閒時間超過60秒以後,就會失效。若是在空閒第58秒時,再次使用此鏈接,則鏈接仍然有效,使用完以後,從新計數,空閒60秒以後過時。

設置HTTP長鏈接,無過時時間: 在首部字段中只設置Connection:keep-alive,代表鏈接永久有效。 URL:https://www.cnblogs.com/shoren/p/http-connection.html

6.HTTP 2.0針對同一個域名的多個請求,會創建多少TCP連接?

HTTP 2.0 通訊都在一個鏈接上完成,這個鏈接能夠承載任意數量的雙向數據流。相應地,每一個數據流以消息的形式發送,而消息由一或多個幀組成,這些幀能夠亂序發送,而後再根據每一個幀首部的流標識符從新組裝。

7.數據庫建表的時候索引有什麼用?

建立索引能夠大大提升系統的性能。 第一,經過建立惟一性索引,能夠保證數據庫表中每一行數據的惟一性。

第二,能夠大大加快數據的檢索速度,這也是建立索引的最主要的緣由。

第三,能夠加速表和表之間的鏈接,特別是在實現數據的參考完整性方面特別有意義。

第四,在使用分組和排序子句進行數據檢索時,一樣能夠顯著減小查詢中分組和排序的時間。

第五,經過使用索引,能夠在查詢的過程當中,使用優化隱藏器,提升系統的性能。

URL:http://blog.163.com/happy_2010_zyj/blog/static/1511487562010511115227777/

8.Full Text Search爲何快?

全文索引(Full Text Search)用於模糊查詢比通常的方法好比like用於模糊查詢速度要快的緣由是前者是用空間來換時間,在創建全文索引時主要經過分詞器(lexer),將被索引的表上的那一列的全部值(即文本,要varchar等類型)分割成一個個token_text(好比,英文分詞器BASIC_LEXER以空格,標點符號,_,-,等非字母數字的符號做爲分割標記),並且記錄這些token_text來自表裏的哪些行等信息,最後將這些token_text和這些信息都寫到表DR索引名I中。

有了這張表,全文索引才能夠快速地查找(不管是模糊仍是不模糊查找),可是該表要佔據空間的。 URL:http://blog.csdn.net/caomiao2006/article/details/52075917

9.iOS下如何實現指定線程數目的線程池?

控制線程池中的線程數,來設置線程池中的線程數,也就是併發操做數。默認狀況下是-1,也就是沒有限制,同時運行隊列中的所有操做。

[queue setMaxConcurrentOperationCount:2];
複製代碼

建立線程池: 建立線程池有兩種方式,第一種是OC得方式,第二種是C語言的方式。 OC版:

OC建立線程池的關鍵字是:NSOperationQueue OC線程池的單元是NSInvocationOperation對象,

- (void)creatThreadQueue_OC{
    NSInvocationOperation *task_1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(taskClick_1) object:nil];
    NSInvocationOperation *task_2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(taskClick_2) object:nil];
    [OC_Queue addOperation:task_1];
    [[NSOperationQueue mainQueue] addOperation:task_2];
}
複製代碼

C語言建立一個線程池,C語言線程的單元式「代碼塊」--Block

- (void)creatThreadQueue_C{
    //serial work
    dispatch_sync(C_Queue, ^{
        [self work_1];
    });
   dispatch_sync(dispatch_get_main_queue(), ^{
        [self work_2];
    });
}
複製代碼

URL:http://blog.csdn.net/u012360598/article/details/41925047

10.介紹下iOS設備獲取惟一設備號的歷史變遷。

從IOS5.0(2011年8月份)開始,蘋果宣佈將再也不支持用uniqueIdentifier方法獲取設備的UDID,iOS5如下是能夠用的。在2013年3月21日蘋果已經通知開發者:從2013年5月1日起,訪問UIDIDs的程序將再也不被審覈經過,替代的方案是開發者應該使用「在iOS 6中介紹的Vendor或Advertising標示符」。

Vindor標示符,也是在iOS 6中新增的,跟advertisingIdentifier同樣,該方法返回的是一個 NSUUID對象,能夠得到一個UUID。

iOS 6中另一個新的方法,提供了一個方法advertisingIdentifier,經過調用該方法會返回一個NSUUID實例,最後能夠得到一個UUID,由系統存儲着的。 URL:http://blog.csdn.net/lcg910978041/article/details/51612953

11.函數式編程當中的 first-class function 是什麼意思呢?

First Class。該類型的值能夠做爲函數的參數和返回值,也能夠賦給變量。

結構化程序設計的精髓在於模塊複用和訪存控制。若是說函數實現了代碼複用,那麼在支持First Class Function的語言中,高階函數做爲函數之間的膠水,進一步方便了函數的複用。

URL:https://www.zhihu.com/question/27460623

12.如何使用runtime hook一個class的某個方法,又如何hook某個instance的方法?

藉助Runtime的Method Swizzling(方法替換)以及Associated Object(關聯對象)對相關類進行擴展。

static dispatch_once_t onceToken;  
    dispatch_once(&onceToken, ^{  
        SEL selA = @selector(sendAction:to:forEvent:);  
        SEL selB = @selector(mySendAction:to:forEvent:);  
        Method methodA =   class_getInstanceMethod(self,selA);  
        Method methodB = class_getInstanceMethod(self, selB);  
        BOOL isAdd = class_addMethod(self, selA, method_getImplementation(methodB), method_getTypeEncoding(methodB));  
        if (isAdd) {  
            class_replaceMethod(self, selB, method_getImplementation(methodA), method_getTypeEncoding(methodA));  
        }else{  
            method_exchangeImplementations(methodA, methodB);  
        }  
    });  
複製代碼

URL:http://blog.csdn.net/lyl123_456/article/details/52462621

13.談下Objective C都有哪些鎖機制,你通常用哪一個?

1)NSLock

iOS中對於資源搶佔的問題可使用同步鎖NSLock來解決,使用時把須要加鎖的代碼(之後暫時稱這段代碼爲」加鎖代碼「)放到NSLock的lock和unlock之間,一個線程A進入加鎖代碼以後因爲已經加鎖,另外一個線程B就沒法訪問,只有等待前一個線程A執行完加鎖代碼後解鎖,B線程才能訪問加鎖代碼。

2)@synchronized代碼塊

使用@synchronized解決線程同步問題相比較NSLock要簡單一些,平常開發中也更推薦使用此方法。

3)使用GCD解決資源搶佔問題

在GCD中提供了一種信號機制,也能夠解決資源搶佔問題(和同步鎖的機制並不同)。

4)擴展--控制線程通訊

因爲線程的調度是透明的,程序有時候很難對它進行有效的控制,爲了解決這個問題iOS提供了NSCondition來控制線程通訊(同前面GCD的信號機制相似)。

5)iOS中的其餘鎖

NSRecursiveLock :遞歸鎖,有時候「加鎖代碼」中存在遞歸調用,遞歸開始前加鎖,遞歸調用開始後會重複執行此方法以致於反覆執行加鎖代碼最終形成死鎖,這個時候可使用遞歸鎖來解決。使用遞歸鎖能夠在一個線程中反覆獲取鎖而不形成死鎖,這個過程當中會記錄獲取鎖和釋放鎖的次數,只有最後二者平衡鎖才被最終釋放。

NSDistributedLock:分佈鎖,它自己是一個互斥鎖,基於文件方式實現鎖機制,能夠跨進程訪問。

pthread_mutex_t:同步鎖,基於C語言的同步鎖機制,使用方法與其餘同步鎖機制相似。

URL:http://blog.csdn.net/roger_jin/article/details/45307951

14.聊下HTTP post的body體使用form-urlencoded和multipart/form-data的區別。

1)application/x-www-form-urlencoded: 窗體數據被編碼爲名稱/值對,這是標準且默認的編碼格式。當action爲get時候,客戶端把form數據轉換成一個字串append到url後面,用?分割。當action爲post時候,瀏覽器把form數據封裝到http body中,而後發送到server。

2)multipart/form-data: multipart表示的意思是單個消息頭包含多個消息體的解決方案。multipart媒體類型對發送非文本的各媒體類型是有用的。通常多用於文件上傳。 multipart/form-data只是multipart的一種。目前經常使用的有如下這些類型(注:任何一種執行時沒法識別的multipart子類型都被視爲子類型"mixed") URL:http://blog.csdn.net/soonfly/article/details/52082547

15.讓你設計一種機制檢測UIViewController的內存泄漏,你會怎麼作?

若是Controller被釋放了,但其曾經持有過的子對象若是還存在,那麼這些子對象就是泄漏的可疑目標。

一個小示例:子對象(好比view)創建一個對controller的weak引用,若是Controller被釋放,這個weak引用也隨之置爲nil。那怎麼知道子對象沒有被釋放呢?用一個單例對象每一個一小段時間發出一個ping通知去ping這個子對象,若是子對象還活着就會一個pong通知。因此結論就是:若是子對象的controller已不存在,但還能響應這個ping通知,那麼這個對象就是可疑的泄漏對象。

URL:http://blog.sina.com.cn/s/blog_7e6a4f740102wce9.html

16.經過[UIImage imageNamed:]生成的對象何時被釋放?

使用imageNamed這個方法生成的UIImage對象,會在應用的bundle中尋找圖片,若是找到則Cache到系統緩存中,做爲內存的cache,而程序員是沒法操做cache的,只能由系統自動處理,若是咱們須要重複加載一張圖片,那這無疑是一種很好的方式,由於系統能很快的從內存的cache找到這張圖片,可是試想,若是加載不少很大的圖片的時候,內存消耗過大的時候,就會會強制釋放內存,即會遇到內存警告(memory warnings).

因爲在iOS系統中釋放圖片的內存比較麻煩,因此衝易產生內存泄露。 像[[UIImageView alloc] init]還有一些其餘的 init 方法,返回的都是 autorelease 對象。而 autorelease 不能保證何時釋放,因此不必定在引用計數爲 0 就當即釋放,只能保證在 autoreleasepool 結尾的時候釋放。

像 UIImage 還有 NSData 這種,大部分狀況應該是延遲釋放的,能夠理解爲到 autoreleasepool 結束的時候才釋放。

URL:https://segmentfault.com/q/101000000423089二、http://blog.csdn.net/qq_18505715/article/details/72885498

17.applicationWillEnterForeground和applicationDidBecomeActive都會在哪些場景下被調用?舉例越多越好。

1)applicationWillResignActive(將進入後臺)

對應applicationWillEnterForeground(將進入前臺)

程序將要失去Active狀態時調用,好比按下Home鍵或有電話信息進來,這個方法用來

  • 暫停正在執行的任務;
  • 禁止計時器;
  • 減小OpenGL ES幀率;
  • 若爲遊戲應暫停遊戲;

總結爲一個字:停!

2)applicationDidEnterBackground(已經進入後臺)

對應applicationDidBecomeActive(已經變成前臺)

程序已經進入後臺時調用,這個方法用來

  • 釋放共享資源;
  • 保存用戶數據(寫到硬盤);
  • 做廢計時器;
  • 保存足夠的程序狀態以便下次恢復; 總結爲4個字:釋放、保存!

URL:https://www.cnblogs.com/chenyg32/p/3873301.html

18.如何終止正在運行的工做線程?

iOS 8 之後,經過dispatch_block_cancel能夠cancel掉dispatch_block_t,須要注意的是,未執行的能夠用此方法cancel掉,若已經執行則cancel不掉;

若是想中斷(interrupt)線程,可使用dispatch_block_testcancel方法;值得注意的是,swift3以後DispatchWorkItem代替了dispatch_block_t,有很方便的cancel()和isCancelled可使用。

1)使用退出標誌終止線程 當run方法執行完後,線程就會退出,...return.

2)使用stop方法終止線程 thread.stop();
使用stop方法是很危險的,就象忽然關閉計算機電源,而不是按正常程序關機同樣,可能會產生不可預料的結果

3)使用interrupt方法終止線程 1>線程處於阻塞狀態,如使用了sleep方法,將拋出一個InterruptedException例外。 2>使用while(!isInterrupted()){……}來判斷線程是否被中斷,線程將直接退出。

URL:http://blog.csdn.net/zhanjichun_2008/article/details/6612980、https://www.zhihu.com/question/23919984

19.窮舉iOS下全部的本地持久化方案。

  • plist文件(屬性列表)
  • preference(偏好設置)
  • NSKeyedArchiver(歸檔)
  • SQLite 3
  • CoreData URL:http://www.cocoachina.com/ios/20150720/12610.html

本身網上整理,有不對的地方還請大佬們指點~

相關文章
相關標籤/搜索