卓同學昨天寫了一篇文章《4道過濾菜鳥的iOS面試題》。我手癢決定默寫一個參考答案。後來發現不認真回答被大家噴成狗,所以決定積極改造,重新做人。下面就是修編之後的答案。
1. struct和class的區別
swift中,class是引用型別,struct是值型別。值型別在傳遞和賦值時將進行復制,而引用型別則只會使用引用物件的一個”指向”。所以他們兩者之間的區別就是兩個型別的區別。
class有這幾個功能struct沒有的:
- class可以繼承,這樣子類可以使用父類的特性和方法
- 型別轉換可以在runtime的時候檢查和解釋一個例項的型別
- 可以用deinit來釋放資源
- 一個類可以被多次引用
struct也有這樣幾個優勢:
- 結構較小,適用於複製操作,相比於一個class的例項被多次引用更加安全。
- 無須擔心記憶體memory leak或者多執行緒衝突問題
順便提一下,array在swift中是用struct實現的。Apple重寫過一次array,然後複製就是深度拷貝了。要是多次拷貝且不進行修改的話,所有arrays指向的都是同一個實體地址,只是指標移動,所以效能上還是不錯的。當然要是修改的話,array就會重新拷貝一份,這個時候開銷就有點大了。
下面引用貓神OneV的部落格:
1 2 3 4 5 6 |
var arr = [0,0,0] var newArr = arr arr[0] = 1 //Check arr and newArr arr //[1, 0, 0] newArr // before beta3:[1, 0, 0], after beta3:[0, 0, 0] |
所以可以猜測其實在背後 Array和 Dictionary的行為並不是像其他 struct 那樣簡單的在棧上分配,而是類似參照那樣,通過棧上指向堆上位置的指標來實現的。而對於它的複製操作,也是在相對空間較為寬裕的堆上來完成的。當然,現在還無法(或者說很難)拿到最後的彙編碼,所以這只是一個猜測而已。
補充:
C語言中,struct與的class的區別:
struct只是作為一種複雜資料型別定義,不能用於物件導向程式設計。
C++中,struct和class的區別:
對於成員訪問許可權以及繼承方式,class中預設的是private的,而struct中則是public的。class還可以用於表示模板型別,struct則不行。
2. 介紹一下觀察者模式
觀察者模式(Observer Pattern):定義物件間的一種一對多依賴關係,使得每當一個物件狀態發生改變時,其相關依賴物件皆得到通知並被自動更新。
在IOS中典型的推模型實現方式為NSNotificationCenter和KVO。
NSNotificationCenter
- 觀察者Observer,通過NSNotificationCenter的addObserver:selector:name:object介面來註冊對某一型別通知感興趣。在註冊時候一定要注意,NSNotificationCenter不會對觀察者進行引用計數+1的操作,我們在程式中釋放觀察者的時候,一定要去報從center中將其登出了。
- 通知中心NSNotificationCenter,通知的樞紐。
- 被觀察的物件,通過postNotificationName:object:userInfo:傳送某一型別通知,廣播改變。
- 通知物件NSNotification,當有通知來的時候,Center會呼叫觀察者註冊的介面來廣播通知,同時傳遞儲存著更改內容的NSNotification物件。
KVO
KVO的全稱是Key-Value Observer,即鍵值觀察。是一種沒有中心樞紐的觀察者模式的實現方式。一個主題物件管理所有依賴於它的觀察者物件,並且在自身狀態發生改變的時候主動通知觀察者物件。
- 註冊觀察者
[object addObserver:self forKeyPath:property options:NSKeyValueObservingOptionNew context:]。 - 更改主題物件屬性的值,即觸發傳送更改的通知。
- 在制定的回撥函式中,處理收到的更改通知。
- 登出觀察者 [object removeObserver:self forKeyPath:property]。
3.在一個https連線的網站裡,輸入賬號密碼點選登入後,到伺服器返回這個請求前,中間經歷了什麼
這個非常得深非常得廣,我來大概說一下。
- 前端會打包一個請求,包括url,埠啊,你的賬號密碼等等。賬號密碼登陸應該用的是Post方式。所以相關的使用者資訊會被載入到body裡面。這個請求應該包含三個方面:網路地址,協議,資源路徑。
- 一般會先請求DNS伺服器。DNS伺服器負責將你的網路地址解析成IP地址,這個IP地址對應網上一臺機器。這其中可能發生Hosts Hijack和ISP failure的問題。
- 協議是獲取資源的方式HTTP,FTP,UDP,不同協議有不同的格式,有些是process-to-process的,有些是host-to-host的。
- 你會和後臺的埠之間建立一個socket連線,socket一般都是以file descriptor的方式解析請求。
- 後臺的web伺服器會響應請求,資料返回到瀏覽器。假如路徑不對,會出現404的錯誤。
- 一般訪問伺服器之前可能會訪問一下proxy。這玩意是個代理,有時候當防火牆用,有時候當cache使。如果後臺是reverse-proxy結構,那麼實際上有多個web伺服器藏在proxy之後按需處理請求,而你訪問的永遠是proxy,這樣可以解決過載問題。
- 有時候訪問完web伺服器後還要訪問一下file伺服器,主要是請求資料庫裡的一些資訊。
- 伺服器將相應打包,直接或通過proxy(大多數時候)返回給你。
4.在一個app中間有一個button,在你手觸控螢幕點選後,到這個button收到點選事件,中間發生了什麼
響應鏈大概有以下幾個步驟
- 裝置將touch到的UITouch和UIEvent物件打包, 放到當前活動的Application的事件佇列中
- 單例的UIApplication會從事件佇列中取出觸控事件並傳遞給單例UIWindow
- UIWindow使用hitTest:withEvent:方法查詢touch操作的所在的檢視view
RunLoop這邊我大概講一下
- 主執行緒的RunLoop被喚醒
- 通知Observer,處理Timer和Source 0
- Springboard接受touch event之後轉給App程式
- RunLoop處理Source 1,Source1 就會觸發回撥,並呼叫_UIApplicationHandleEventQueue() 進行應用內部的分發。
- RunLoop處理完畢進入睡眠,此前會釋放舊的autorelease pool並新建一個autorelease pool
深挖請去看此文深入理解RunLoop
UIResponder是UIView的父類,UIView是UIControl的父類。
宣告一下,第3題依然有很大缺陷,不過因為深挖的地方太多,本文不可能完全兼顧,只能拋磚引玉。另外文章的目的是以面試題為引進行學習,所以寫得有點多,可能與面試技巧和時間有衝突。