今天下午去面試去面試一家初創公司,而後又接到到了丁香園的電話面試,這篇blog記錄一下面試的一些問題,有的回答的還行,有點感受不太好,主要是有些英文單詞說的太low了估計被鄙視了吧,下面給你們總結一下面試的一些問題,有些回答是摘要一些大神blog的出處,都有給原連接,但願見諒~~ios
這個問得其實不是很難,主要看你了不瞭解了,我由於瞭解一些後臺的東西,因此回答的還行,下面我給你們看兩幅圖片你們就基本瞭解了:git
總結一下,其實http請求就是發送和接受報文,報文的具體格式就如上圖所示,具體由三部分構成,GET 和 POST比較明顯的不一樣就是請求方式和參數的位置不一樣,其餘原理的不一樣你們能夠去下面的連接去看:github
其中請求頭裏面能夠放不少參數,好比報文的大小啊,啥的一些參數,具體能夠百度,這裏就不展開了。web
下面給兩個大神們推薦的連接,你們能夠自行查看:面試
這個問題回答的就比較菜了,程序比較複製,當時特地記了一下,沒想到面試的時候仍是有點蒙,回答的很是菜,如今在普及一下,下面是一篇講的很詳細的blog地址,你們能夠去原地址去看,我下面也簡單總結一下:objective-c
對稱加密是指加密和解密使用相同密鑰的加密算法。它要求發送方和接收方在安全通訊以前,商定一個密鑰。對稱算法的安全性依賴於密鑰,泄漏密鑰就意味着任何人均可以對他們發送或接收的消息解密,因此密鑰的保密性對通訊相當重要。算法
對稱加密算法的優、缺點:數據庫
優勢:算法公開、計算量小、加密速度快、加密效率高。編程
缺點:
1)交易雙方都使用一樣鑰匙,安全性得不到保證;swift
2)每對用戶每次使用對稱加密算法時,都須要使用其餘人不知道的唯一鑰匙,這會使得發收信雙方所擁有的鑰匙數量呈幾何級數增加,密鑰管理成爲用戶的負擔。
3)能提供機密性,可是不能提供驗證和不能否認性。
這種加密或許理解起來比較困難,這種加密指的是能夠生成公鑰和私鑰。凡是公鑰加密的數據,公鑰自身不能解密,而須要私鑰才能解密;凡是私鑰加密的數據,私鑰不能解密,須要公鑰才能解密。這種算法事實上有不少,經常使用的是RSA,其基於的數學原理是兩個大素數的乘積很容易算,而拿到這個乘積去算出是哪兩個素數相乘就很複雜了,具體原理有興趣能夠自行研究。
非對稱加密相比對稱加密更加安全,但也存在兩個明顯缺點:
1)CPU計算資源消耗很是大。一次徹底TLS握手,密鑰交換時的非對稱解密計算量佔整個握手過程的90%以上。而對稱加密的計算量只至關於非對稱加密的0.1%,若是應用層數據也使用非對稱加解密,性能開銷太大,沒法承受。
2)非對稱加密算法對加密內容的長度有限制,不能超過公鑰長度。好比如今經常使用的公鑰長度是2048位,意味着待加密內容不能超過256個字節。
因此公鑰加密目前只能用來做密鑰交換或者內容簽名,不適合用來作應用層傳輸內容的加解密。
首先服務器端用非對稱加密(RSA)產生公鑰和私鑰。而後把公鑰發給客 戶端,路徑或許有人會截取,可是沒有用,由於用公鑰加密的文件只有私鑰能夠解密,而私鑰永遠都不會離開服務器的。當公鑰到達客戶端以後,客戶端會用對稱加密產生一個祕鑰而且用公鑰來加密發送給服務器端,這個祕鑰就是之後用來通訊的鑰匙。這樣服務器端收到公鑰加密的祕鑰時就能夠用私鑰來解公鑰從而得到祕鑰。這樣的話客戶端和服務器端都得到了祕鑰,信息交流相對是安全的。流程圖以下:
聽起來確實是挺安全的,但實際上,還有一種更惡劣的攻擊是這種方法無 法防範的,這就是傳說中的「中間人攻擊」。在身份認證的過程當中,出現了一個「中間人」攔截咱們的信息,他有意想要知道大家的消息。咱們將這個中間人稱爲M。當服務器第一次給客戶端發送公鑰的時候,途徑M。M知道你要進行密鑰交換了,它把公鑰扣了下來,僞裝本身是客戶端,僞造了一個僞祕鑰(對稱加密產生的),而後用服務器發來的公鑰加密了僞祕鑰發還給服務器,這樣服務器覺得和客戶端完成了密鑰交換,實際上服務器是和M完成了密鑰交換(得到了僞祕鑰)。同時M假扮成服務器自行用非對稱加密產生僞公鑰和僞私鑰,與客戶端進行祕鑰交換,拿到客戶端發送過來的祕鑰。如今客戶端拿着祕鑰,M拿着祕鑰和爲僞祕鑰,服務器拿着僞祕鑰,整個交流的過程就是:
還有不少你們直接去大神的blog去看吧,寫的很詳細,我這就點到爲止了~~
當聽到這麼問題的時候仍是有點倉促的,隱約記得是經過二進制的頭部的標識來區分的,當時也不太肯定就含糊的回答了一下,說是經過二進制文件的頭部標識來區分的,看面試官的樣子不是很滿意,回答百度學習一波,百度結果以下所示,附帶原連接:
能夠經過二進制頭識別文件類型,可使用UE或者WinHex軟件打開:
1). JPEG/JPG
2). TGA
3). PNG
4). GIF
5). BMP
6). PCX
7). TIFF
8). ICO
9). CUR
10). IFF
11). ANI
以上是一些文件的區別方式,回答的總方向仍是對的,可能回答的不夠好,下次就知道了。
這個問題比較尷尬,由於英文不太好,加上平時用的也很少,回答的比較吞吞吐吐,就說了NSLock
、@synchronized
和dispatch的semaphore
,其中有些單詞的讀法還不太準,想一想就很尷尬,下面大概總結一下,有一下幾種:
下面總結一下,說實話太多有點記不過來了 - . -,附帶詳細的原文地址:
各類線程鎖 | 使用場景和簡單介紹 |
---|---|
@synchronized |
適用線程很少,任務量不大的多線程加鎖 |
NSLock |
比較經常使用的一種鎖,性能通常 |
dispatch_semaphore_t |
使用信號來作加鎖,性能很好 |
NSCondition |
使用其作多線程之間的通訊調用不是線程安全的 |
NSConditionLock |
單純加鎖性能很是低,比NSLock低不少,可是能夠用來作多線程處理不一樣任務的通訊調用 |
NSRecursiveLock |
遞歸鎖的性能出奇的高,可是隻能做爲遞歸使用,因此限制了使用場景 |
NSDistributedLock |
由於是MAC開發的,就不討論了 |
POSIX(pthread_mutex) |
底層的api,複雜的多線程處理建議使用,而且能夠封裝本身的多線程 |
OSSpinLock |
性能也很是高,惋惜出現了線程問題 |
再總結一下,總的意思就是通常用dispatch_semaphore_t
就好了,再簡單點用NSLock
,另外帶一個swift
出的一個線程鎖的方式:
func synchronized(lock: AnyObject, closure: () -> ()) {
objc_sync_enter(lock)
closure()
objc_sync_exit(lock)
}複製代碼
這個問題我是接着上一個問題以後回答的,感受線程安全主要是數據競爭帶來的,下面簡單講解一下:
線程安全的代碼能夠從多個線程或併發任務安全地調用,而不會形成任何問題(數據損壞,系統崩潰等)。例如當你多線程編程時,你用let定義一個數組,由於它是隻讀的,你能在同一時間不一樣線程去使用它,而不會形成線程安全的問題,然而當你用var定義一個數組時就不同了,它不是線程安全的,當多個線程在同一時間訪問和修改數組時會產生不可預知的結果。
這個問題回答的通常般吧,說了一下簡單的構造和實現,而後讓我說具體類的時候有點心累了,由於確實記得不是很清楚了,下面簡單總結一下一些主要的類:
SDWebImageManager
SDWebImageCombinedOperation
SDImageCache
SDWebImageDownloader
這是一些簡單的類,你們想要詳細瞭解能夠去這篇文章去看,很是詳細!!!
跟上個問題同樣,簡單的回答了一下,都怪本身沒仔細專研過這些,只是簡單看過,停留在應用層面上,下面一樣簡單介紹一下,附帶大神blog地址吧:
Manager
SessionDelegate
ResponseSerialization
URLStringConvertible
這是一些簡單的類,你們想要詳細瞭解能夠去這篇文章去看,很是詳細!!!
這個幸虧用過了,不過也沒深刻過,就簡單抽象的講了一下響應式編程的思想,而後從應用使用方面講解了一下:RxSwift
的目的是讓讓數據/事件流和異步任務可以更方便的序列化處理,可以使用swift
進行響應式編程;讓後讓我說一下RxSwift
裏面有哪些Subjects
,這個就比較尷尬了,這讓我只用過PublishSubject
和Driver
的人情何以堪,下面一樣列一下Subjects
列表和大神地址:
PublishSubject
ReplaySubject
BehaviorSubject
Variable
Driver
下面是大神blog,有詳細介紹你們能夠去閱讀~~~
這個也簡單用過,也是沒往深刻研究,也是大概說了一下使用過程,和多線程數據共享的坑,首先realm
是一個跨平臺移動數據庫引擎,支持iOS
、OS X
(Objective-C
和Swift
)以及Android
,核心數據引擎C++
打造,並非創建在SQLite
之上的ORM
。
廢話很少說,直接上代碼:
let person = Person(name: "Jane")
try! realm.write {
realm.add(person)
}
// 如下是跨線程必要的操做,先建一個Reference
let personRef = ThreadSafeReference(to: person)
// 而後在須要返回數據的線程裏面去resolve
DispatchQueue(label: "background").async {
let realm = try! Realm()
guard let person = realm.resolve(personRef) else {
// person 已被刪除
return
}
try! realm.write {
person.name = "Jane Doe"
}
}複製代碼
這裏是官方中文文檔,你們能夠去看看,很是詳細~~~
runtimer
和runloop
由於看過一篇文章寫的特別好,有必定了解,說了runtime
的一些主要功能和應用的地方,下面簡單介紹一下:
RunTime
簡稱運行時;其中用的比較多的就是用類目給某個類動態添加屬性。
RunLoop
簡單來講就是事件循環,保持APP一直處於存活方式的一種機制,讓線程能隨時處理事件但並不退出,下面有一篇超級棒的RunLoop
文章給你們介紹一下,我這就不展開說了,瞭解RunLoop
看那篇文章足夠了。
這個回答的就比較輕鬆了,下面隨便列幾個吧,你們有其餘的能夠補充一下:
NSUserDefaults
plist
NSKeyedArchiver
SQL
coredata
realm
主要經過NSURLCache
對請求的數據進行緩存,具體實現能夠去這個github上去查看~~~~
詳情看這篇blog,這裏簡單陳述一下,其實在iOS9
出了一個方法,調用一下就清除了:
NSSet *websiteDataTypes = [WKWebsiteDataStore allWebsiteDataTypes];
//// Date from
NSDate *dateFrom = [NSDate dateWithTimeIntervalSince1970:0];
//// Execute
[[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:websiteDataTypes modifiedSince:dateFrom completionHandler:^{
// Done
}];複製代碼
主要用到的類有NSHTTPCookie
,你們一樣也能夠去大神的blog去查看~~~~
這個問題回答的不太好,說實話當時連續面試了兩家,鬧着已經有點蒙了,這裏借用喵神翻譯的一本書上的原話來描述一下:
autorelease
它會將接受該消息的對象放到一個預先創建的自動釋放池 (auto release pool
) 中,並在 自動釋放池收到 drain
消息時將這些對象的引用計數減一,而後將它們從池子中移除 (這一過程形象地稱爲「抽乾池子」)。」
【摘錄來自: 王巍 (onevcat). 「Swifter - Swift 必備 Tips (第三版)」。 iBooks. 】
實現原理的話大概就是被autorelease
標記的類會被加入一個池子,當這個池子drain
時裏面的引用計數會減1。
說實話其實這個問題當時比較吵,聽的不是很清楚,問了好幾遍問題,挺尷尬的,下面簡單介紹一下吧,由於這個在swift
中用的比較多:
extension
在swift
中相似oc
的類目,能夠擴展方法,計算屬性,不能添加存儲屬性;extension
讓類實現某個協議,通常這個用的也比較多,好比實現Comparable
這個協議;extension
對協議進行擴展,添加默認實現,屬於黑魔法吧,很是好用。前兩點在面試的時候都又提到,最後一點壓根忘了,本身的面試發揮真不是通常的差- . -
幸虧以前看了喵神翻譯的【Swift進階】 ,受益頗深,下面一樣借用喵神的話給你們簡單描述一下,你們能夠去買這本書,仍是挺划算的,下面大量複製喵神書裏面的內容,請見諒:
在 Swift 標準庫中,像是 Array,Dictionary 和 Set 這樣的集合類型是經過一種叫作寫時複製 (copy-on-write) 的技術實現的。咱們這裏有一個整數數組:
var x = [1,2,3]
var y = x複製代碼
若是咱們建立了一個新的變量 y,而且把 x 賦值給它時,會發生複製,如今 x 和 y 含有的是獨立的結構體。在內部,這些 Array 結構體含有指向某個內存的引用。這個內存就是數組中元素所存儲的位置,它們位於堆 (heap) 上。在這個時候,兩個數組的引用指向的是內存中同一個位置,這兩個數組共享了它們的存儲部分。不過,當咱們改變 x 的時候,這個共享會被檢測到,內存將會被複制。這樣一來,咱們得以獨立地改變兩個變量。昂貴的元素複製操做只在必要的時候發生,也就是咱們改變這兩個變量的時候發生複製:
x.append(5)
y.removeLast()
x // [1, 2, 3, 5]
y // [1, 2]複製代碼
若是 Array 結構體中的引用在數組被改變的一瞬間時是惟一的話 (好比,沒有聲明 y),那麼也不會有複製發生,內存的改變將在原地進行。這種行爲就是寫時複製,做爲一個結構體的做者,你並不能免費得到這種特性,你須要本身進行實現。當你本身的類型內部含有一個或多個可變引用,同時你想要保持值語義,而且避免沒必要要的複製時,爲你的類型實現寫時複製是有意義的。
下面看看經過簡單的例子看一下:
var array = [COWStruct()]
array[0].change() // No copy
var otherArray = [COWStruct()]
var x = array[0]
x.change() // Copy複製代碼
然而本身去實現一個寫時複製的話,首先你要判斷引用的惟一性,不是惟一的話進行寫時複製,惟一的話直接改變須要改變的值。
結構體和類主要的區別就是一個是值類型,一個是引用類型;值類型是寫時複製的,引用類型是不會發生寫時複製的;當咱們須要一個簡單不須要繼承、很少變的數據時候咱們首選結構體,由於在數據結構上來講結構體的存取效率是高於類的,反之當咱們須要一個數據結構比較大,須要繼承,變化比較多的時候咱們選擇類,由於在變化的過程當中結構體可能會發生寫時複製,而類不會;下面舉一個簡單的例子:
以Array
和NSMutableArray
來講:
當有一個數組,數據量相對比較小,也不用去常常改變它,只是用來存數據和取數據,咱們首先Array
當數組的數據量很大的時候,而且常常要去對他進行添加,刪除等操做,而且常常賦值給其餘變量的話就推薦使用NSMutableArray
這個是一個比較開發性的問題了,我想到的是用策略模式的方式來簡單實現一下,使用策略模式的好處是方便文件類型的擴展,下面我簡單畫個簡單的UML圖你們看一看吧:
固然這只是一個初步的模型,還有不少細節待考慮,好比文件緩存什麼的,是存本地仍是磁盤,這都得去考慮,小弟只是拋磚引玉給個簡單的思路。
寫完已是深夜了,以上是我丁香園電話面試的一些問題,和以前面試一些回答很差的問題,最後面試完我問了一下丁香園的面試官對我感受怎樣,他說廣度還行深度不夠,我確實又有這點問題,想學的知識比較多,有時候也沒來得及去看實現原理,只是簡單的過一下,沒深刻研究透徹,這是我須要增強的地方,以後若是有二面的話我會在繼續更新的,最後謝謝你們的閱讀~~我是WCL,你們能夠去我github關注一波