求職筆記-iOS篇

前言

今年年初求職時,整理、回顧了學習iOS開發以來收獲的知識,此篇為當時的筆記。

插一段我對面試的看法。
公司要在短短的幾個小時內要詳細了解求職者,并且求職者可能遠遠大于崗位需求,這個并不是一件簡單的事情。
求職分為幾大部分:
1、簡歷篩選,去掉大部分不符合要求的;
2、筆試,去掉沒有準備的;
3、初面,去掉基礎不扎實的;
4、復試,去掉綜合能力欠缺的;
5、HR面,去掉三觀不正確的;
在這個過程中,一個好的求職者會不斷修改簡歷,已適應不同公司的要求;提前整理、回顧基礎知識,以應對筆試和初試;對過去的工作經歷進行總結,不斷提高自己的綜合能力;并在生活與工作中,培養好的工作習慣和態度
在這個過程中,筆記就顯得很重要。

面試題

這是面試的常問問題,僅供大家參考;
如果覺得有用,不妨點個喜歡

1、strong、weak、unsafe_unretained 這三個修飾符分別是什么?
2、performSelector為什么會內存泄漏?
3、如何對真機的crash日志進行分析?
4、對RunLoop的理解?
5、對象回收時Weak指針自動被置為nil的實現原理?
6、常見的持久化實現方法?
7、動畫中的圖層樹、邏輯樹、動畫樹、顯示樹分別是什么?
8、APP的生命周期(應用程序的狀態)有哪些?
9、多線程中同步方式有哪些?
10、一個十級臺階,你在第一級臺階,每次能往上走一級或者兩級臺階,問走到第十級臺階有多少種方案?

正文

以下是iOS相關的知識點。

異常和捕獲

1、try-catch

@try{
//raise exception
}
@catch (NSException *exception) {
// cannot raise exception
}
@finally {
// execute
}
// execute

2、捕獲
NSSetUncaughtExceptionHandler

3、線上崩潰分析
在上面的捕獲函數中,捕捉堆棧。
[NSThread callStackSymbols]

4、線上卡頓統計
CADisplayLink每幀回調,用時間間隔算幀率;
計算每次runloop的耗時。

UIWindow

UIWindow繼承自UIView,是視圖的容器。
一般的app只需一個UIWindow,在AppDelegate中。
UIWindow的主要作用:

  • 作為最頂層的視圖容器,存放app的視圖;
  • 傳遞觸摸和鍵盤等事件;

KVO與Notification的異同

KVO和Notification本質都是觀察者模式。
KVO是被觀察者直接發消息(-willChange-didChange),耦合性較強,適合某些綁定,比如說界面上的進度條顯示;
Notification是被觀察者發消息給NotificationCenter,再由NotificationCenter轉發出去,耦合性較低,適合登錄、等級變化、監聽全局的某個屬性變化;

Objective-C消息機制的原理

先介紹Objective-C的類結構:

@interface NSObject <NSObject> {
    Class isa  OBJC_ISA_AVAILABILITY;
}
typedef struct objc_class *Class;

每一個OC對象本質上都是一個結構體,包括成員變量列表和成員方法列表,對象通過isa指針指向類;
類本質上也是一個對象,是元類(meteClass)的實例,元類包括類方法的列表,類通過類的isa指針指向元類;
所有的元類繼承根元類,根元類isa指針指向本身;

objc_msgSend方法:objc_msgSend含兩個必要參數:receiver、方法名(selector)
[receiver message];將被轉換為:objc_msgSend(receiver, selector);
帶參數的情況是:objc_msgSend(receiver, selector, arg1, arg2, …);

當向一個對象發送消息時,objc_msgSend方法根據對象的isa指針找到對象的原來類,然后在類的方法列表中查找selector;
如果查找不到,通過Class super_class指針找到父類,并在父類的方法列表查找,直到NSObject類;
查找到selector,objc_msgSend方法根據方法列表的內存地址調用該實現;
每個類都有一個獨立的緩存struct objc_cache *cache,緩存方法調用的結果。

對象回收時Weak指針自動被置為nil的實現原理

Runtime維護著一個Weak表,用于存儲指向某個對象的所有Weak指針;
Weak表是Hash表,Key是所指對象的地址,Value是Weak指針地址的數組;
在對象被回收的時候,經過層層調用,會最終觸發下面的方法將所有Weak指針的值設為nil。

runtime源碼,objc-weak.m 的 arr_clear_deallocating 函數。
Weak指針如何注冊到Weak表中、如何維護hash表可以參考objc-weak.m中的其它源碼。

從實現中可以看出,Weak指針的使用涉及到Hash表的增刪改查,有一定的性能開銷。
Weak指針的實際應用:

iOS 8 特有iOS相關的漏洞
- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

iOS 8 的UIScrollView的delegate屬性

持久化實現

ios中存儲數據基本上就是plist、sqlite和CoreData (NSUserDefault其實也是plist)
常見的持久化實現:
1、實現NSCoding,配合runtime讀取屬性,再用NSKeyedArchiver存儲到文件中;
2、實現NSCoding,存儲到NSUserDefault;
3、數據庫,使用SQLitePersistentObjects寫入db;
4、使用CoreData;

動畫性能優化

動畫的視圖結構

視圖樹/圖層樹:UIView,每個view對應一個calayer,管理觸摸、手勢等交互事件;
模型樹/邏輯樹(目標幀) :CALayer - modelLayer(),不涉及響應鏈(通過視圖層級關系傳遞觸摸事件的機制)
**呈現樹/動畫樹(當前幀) **:presentationLayer(), 動畫過程中的當前值
渲染樹/顯示樹(下一幀) :圖層和動畫打包提交到渲染服務后反序列化所得樹,被用于生成gl三角形

常見的動畫方式:

  • UIView blockAnimation
  • CAAnimation

動畫耗時在于:
圖片加載、alpha透明、動畫代碼混亂、離屏渲染、幀動畫過多、布局計算、遮罩、圖片過大;

某些問題不可避免,比如說圖片加載、幀動畫等,以下是自己總結的一些經驗:

  • CADisplayLink控制幀動畫的幀率,避免動畫的繪制速率超過幀率

??想想為什么?

  • 避免使用alpha透明的圖片

  • 使用GCD和CAAnimation來管理動畫的流程;

使用NSOperationQueue或許也是解決方案。

  • 減少遮罩以避免離屏渲染,避免光柵化視圖的頻繁更新;
  • 使用代碼布局,避免autolayout;

聊天室中UITableView的優化

聊天室中,消息的顯示使用的是UITableView;
每一條消息是單獨的UITableViewCell,通過富文本顯示聊天消息,耗時操作是:富文本拼接、高度計算、滾動顯示;

優化兩個方面:
業務方向:

  • 下發房間配置文件,房間分普通、熱鬧、火爆等狀態,某些情況下省略不必要的消息,再進行發言等級控制等;
  • 消息合并,對同類型的消息進行合并;

代碼方向:

  • 富文本根據消息內容進行拼接后緩存;
  • 高度在計算過一次之后,同樣緩存;(boundingRectWithSize 可以提前計算出高度)
  • 根據幀率動態加載消息數量,當進行消息追趕的時候,多條消息調用一次insert,用CADisplayLink保證添加速率和幀率一致;
    代碼創建cell
  • 圖像預加載,程序在啟動的時候會進行禮物版本同步,把禮物圖片預先下載好,在顯示直接通過富文本進行圖片拼接;(為了避免鋸齒,圖像大小和顯示使用整數)

TCP/IP

3次握手-建立連接
1、A發送sync報文;seq=x Sync=1
2、B回復ack報文;seq=y Sync=1 ack=x+1
3、A回復ack報文;seq=x+1 Sync=1 ack=y+1

4次握手-斷開連接
1、A端發送FIN,停止發送報文;A進入FIN-WAIT
2、B端發送ACK,表示收到,繼續發送報文; A收到報文進入FIN2-WAIT
3、B端發送FIN,停止發送報文;B進入CLOSE_WAIT
4、A端收到FIN,發送ACK報文,A進入TIME_WAIT狀態

TIME_WAIT經過兩個最大報文段生存時間后,進入CLOSE狀態。(如果A在time_wait過程中,收到FIN報文,表示發送的ACK丟包了,重新發)

如何下載一個超大的文件?支持斷點續下、暫停、取消的功能。

1、NSURLConnection / NSURLSessionTask 實現下載,通過Range字段實現斷點續傳;

存在的內存占用過多的問題。
解決方案:新建文件,然后用NSOutputStream把下載的數據流直接append到文件中。

2、更簡單的解決方案:NSURLSessionDownloadTask。

缺點:下載完成之后才能獲得完整的文件,如果在下載過程中直接關閉退出程序,會丟失數據,因為數據保存在內存;

斷點續傳

http實現斷點續傳的關鍵地方就是在httprequest中加入“Range”頭。
Range頭域可以請求實體的一個或者多個子范圍。例如,

表示頭500個字節:bytes=0-499
表示第二個500字節:bytes=500-999
表示最后500個字節:bytes=-500
表示500字節以后的范圍:bytes=500-

利用NSOutputStream寫文件,在任務完成的代理方法里面,NSOutputStream關閉并且清空,對應的task清空,對應的session清空;
在 NSURLRequest中有一個HTTPBodyStream,可以方便的接受服務器返回的流數據。

HTTP協議

http(超文本傳輸協議)是一個基于請求與響應模式的、無狀態的、應用層的協議,常基于TCP的連接方式
http請求由三部分組成,分別是:請求行、消息報頭、請求正文。
常見狀態碼:
200 成功
400 請求的語法錯誤
403 Forbidden
404 not found 服務器找不到請求的資源
408 Request Time out
500 服務器內部錯誤

請求頭
GET 請求方法、地址、協議版本
GET /foo.php?first_name=John&last_name=Doe&action=Submit HTTP/1.1

請求體(POST請求有)
form-data

NSURLRequest 的allHTTPHeaderFields 可以看到以下屬性

Cache-Control →no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Connection →keep-alive
Content-Encoding →gzip
Content-Type →text/html; charset=utf-8
Date →Fri, 10 Mar 2017 13:35:42 GMT
Expires →Thu, 19 Nov 1981 08:52:00 GMT
Pragma →no-cache
Server →nginx
Transfer-Encoding →chunked
X-Powered-By →PHP/5.4.16

HTTP響應也是由三個部分組成,分別是:狀態行、消息報頭、響應正文

HTTP/1.1 200 OK // 包含了HTTP協議版本、狀態碼、狀態英文名稱
Server: Apache-Coyote/1.1 // 服務器的類型
Content-Type: image/jpeg // 返回數據的類型
Content-Length: 56811 // 返回數據的長度
Date: Mon, 23 Jun 2014 12:54:52 GMT // 響應的時間

NSHTTPURLResponse的allHTTPHeaderFields 可以看到以上屬性

iOS目錄結構


Documents 是常用文檔目錄,會和iTunes同步;
Library 是資源庫文件,里面有Caches和Preference兩大目錄;
Caches一般存放緩存文件,較大;
Preference存放個人設置文件,iTunes會同步;
tmp 目錄是臨時文件,應用關閉后,可能會被刪除。

說道文件夾,就離不開序列化。
NSKeyedArchiver
實現NSCoding協議即可實現序列化;
配合運行時機制,可以動態實現將類的所有屬性序列化。
相對應的,可以用 NSKeyedUnarchiver 實現反序列化。

APP的生命周期

應用程序的狀態

  • Not running未運行:程序沒啟動;
  • Inactive未激活:程序在前臺運行,未接收到事件;
  • Active激活:程序在前臺運行,接受到事件;
  • Backgroud后臺:程序在后臺運行,在后臺停留一段時間后進入掛起狀態(Suspended),如果有音樂、下載等特殊任務的程序可以長期處于Backgroud狀態;
  • Suspended掛起:程序在后臺且不運行,當收到系統內存不足的warning時被清除出內存;


問題1:UIAlertView彈出的時候,APP處于哪一個狀態?
低電量提出彈出的時候,APP又處于哪一個狀態?

Inactive和Background。

在加載到前臺過程中,經歷了Launch和Running兩大狀態;
start->main() -> UIApplicationMain() -> Load UI file -> willFinishLaunchingWithOptions: -> Restore UI state -> didFinish
Active App => Application Become Active
接著就是不斷進行RunLoop。
還有一種:加載應用程序到后臺(在后臺打開網易云音樂)
前面的start部分一致,但最終進入的不是Foreground狀態,而是Background狀態;
在Background長時間不運行,會導致應用程序進入Suspended狀態;

線程安全問題

線程之間的資源共享,本質是對同一對象、變量、文件等進行修改和訪問,主要有以下同步方式:

  • 加鎖;
  • 原子操作;
  • sync代碼塊;
@synchronized( 同一對象){
  線程執行代碼;
  }

NSOperationQueue 可以停止隊列還沒執行
suspended
但是不能終止當前操作。

RunLoop

此段,部分摘自文章

簡單運行執行runlooprun函數并不會讓系統停住等待事件,而是需要在運行runloop之前添加source,只有在有source的情況下線程才會停下來監聽各種事件。ios整個系統基本上是基于runloop這種架構的,ios程序的main線程整體上也是基于runloop的,各種事件的響應應該也是基于source這種思路。
UIApplicationMain() 函數,這個方法會為main thread 設置一個NSRunLoop 對象;
Run loop同時也負責autorelease pool的創建和釋放;
Run loop接收輸入事件來自兩種不同的來源:輸入源(input source)和定時源(timer source);
典型的子線程異步請求,需要開啟runLoop:AF 的 self.inputStream;
當在其他線程上面執行selector時,目標線程須有一個活動的run loop。對于你創建的線程,這意味著線程在你顯式的啟動run loop之前是不會執行selector方法的,而是一直處于休眠狀態;
蘋果不允許直接創建 RunLoop,它只提供了兩個自動獲取的函數:CFRunLoopGetMain() 和 CFRunLoopGetCurrent()。
一個 RunLoop 包含若干個 Mode,每個 Mode 又包含若干個 Source/Timer/Observer。

RunLoop 和 幀率之間的關系
用戶操作設備,相關的操作事件被系統生成并通過UIKit的指定端口分發。事件在 內部排成隊列,一個個的分發到Main run loop 去做處理。UIApplication對象是第一個接收到時間的對象,它決定事件如何被處理。觸摸事件分發到主窗口,窗口再分發到對應出發觸摸事件的 View。其他的事件通過其他途徑分發給其他對象變量做處理。
大部分的事件可以在你的應用里分發,類似于觸摸事件,遠程操控事件(線控耳機等) 都是由app的 responder objects 對象處理的。Responder objects 在你的app里到處都是,比如:UIApplication 對象,view對象,view controller 對象,都是resopnder objects。大部分事件的目標都指定了resopnder object,不過事件也可以傳遞給其他對象。比如,如果view對象不處理事件,可以傳給父類view或者view controller。

一個 RunLoop 包含若干個 Mode,每個 Mode 又包含若干個 Source/Timer/Observer。每次調用 RunLoop 的主函數時,只能指定其中一個 Mode,這個Mode被稱作 CurrentMode。如果需要切換 Mode,只能退出 Loop,再重新指定一個 Mode 進入。這樣做主要是為了分隔開不同組的 Source/Timer/Observer,讓其互不影響。

main():
    file_fd = open ("logfile")
    x_fd = open_display ()
    construct_interface ()
    while changed_fds = select ({file_fd, x_fd}):
        if file_fd in changed_fds:
            data = read_from (file_fd)
            append_to_display (data)
            send_repaint_message ()
        if x_fd in changed_fds:
            process_x_messages ()

CFRunLoop源碼

如何計算幀的持續時間:
用CACurrentMediaTime()記錄當前時間,然后和上一幀記錄的時間去比較。得到真實的每幀持續的時間,然后代替硬編碼的六十分之一秒,來更新UI。

總結

此篇的iOS知識點并不全面,僅僅是求職的一些筆記,后續接著寫工作遇到的iOS相關問題,歡迎關注iOS開發隨筆

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,663評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,125評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,506評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,614評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,402評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,934評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,021評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,168評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,690評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,596評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,288評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,027評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,404評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,662評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,398評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,743評論 2 370

推薦閱讀更多精彩內容

  • 1,NSObject中description屬性的意義,它可以重寫嗎?答案:每當 NSLog(@"")函數中出現 ...
    eightzg閱讀 4,163評論 2 19
  • 1.屬性readwrite,readonly,assign,retain,copy,nonatomic 各是什么作...
    曾令偉閱讀 1,075評論 0 10
  • 喜歡與不喜歡之間只多了一個“不”字,卻隱藏了許許多多的秘密。人,無論在何時何地都會有不同的情緒,無需一探究竟。你說呢?
    莊田木閱讀 142評論 0 0
  • 主要內容:堅持手帳100天給我帶來什么改變關于堅持10000小時 最近做了什么。 很多時候我們覺得自己很忙,但是絕...
    霖霖的手帳閱讀 946評論 2 3
  • 獨處能保持自己做好 要求周圍一切環境都符合心意 其實是對自己的一種苛責
    MaryCeeport閱讀 246評論 0 0