iOS中高級筆試題二
來自: http://www.henishuo.com/ios-middle-hight-interview-two/
前言
最新整理的筆試題,由群里某某群友提供的題目,筆者整理并在此提供參考答案。
招聘高峰期來了,大家都非常積極地準備著跳槽,那么去一家公司面試就會有一堆新鮮的問題,可能不會,也可能會,但是了解不夠深。本篇文章為群里的小伙伴們去某公司的筆試題,由筆者整理并提供筆者個人參考答案。注意,僅供參考,不代表絕對正確。
參考答案不唯一,大家可以根據自己的理解回答,沒有必要跟筆者的一樣。參考筆者的答案,也許給你帶來靈感!
題照(前五題)
1、鏈表不具備的特點是()
A. 可隨機訪問任何一個元素
B. 插入,刪除操作不需要移動元素
C. 無需事先估計存儲空間大小
D. 所欲存儲空間可以是不連續的
這道題是考大學時所學的鏈表知識,其實筆者也忘了很多了。因為在大學時,曾經自己寫過很多鏈表相關的代碼,再加上經常幫同學調試,以及幫助同學講解鏈表相關知識點,因此記憶較深。以下答案純屬個人認知,非百度而來,若有不對之處,請指出。
參考答案: (A)
鏈表不同于數組。鏈表之所有叫鏈表,就是像一條鏈一樣,要過到某個節點處,就得遍歷著找;而數組才具備隨機訪問任何一個元素的能力,數組可以通過索引直接訪問元素,時間復雜度為常量,效率非常高,因此在某些場合上,我們需要數組這樣的數據結構。
B. 鏈表的插入、刪除都不需要移動元素,只需要修改指針的指向就可以了,因為鏈表上的每個節點都是動態分配的,分配在堆上,通過指針來指向每個節點的內存區,要獲取某個節點的值,是需要遍歷一遍才能找到對應的節點的。
C. 因為鏈表上的每個節點是分配在堆上,需要開發人員手動申請內存空間的,因此不像數組在定義時就要指定存儲空間大小。對于鏈表,需要增加一個節點時,直接在堆上申請。當需要刪除某個節點時,可以直接將該節點的內存給釋放掉。
D. 因為鏈接中的節點都是存儲在堆上的,而每個節點之間都有一個指向前一個節點和后一個節點的指針,只要知道鏈表頭指針,就可以通過遍歷查找到任何一個節點。因此,鏈表不同于數組,數組是要連續的內存存儲空間,才能保證以常量時間復雜度快速訪問任意元素;而鏈表不要求每個節點是連接,在堆上申請的內存空間很難得到連續的,而且空間產生內存碎片。
2、關于多線程和多進程編程,下面描述正確的是()
A. 多進程里,子進程可獲取父進程的所有堆和棧的數據;而線程會與同進程的其他線程共享數據,擁有自己的棧空間。
B. 線程因為有自己的獨立棧空間且共享數據,所有執行的開銷相對較大,同時不利于資源管理和保護。
C. 線程的通信速度更快,切換更快,因為他們在同一地址空間內。
D. 線程使用公共變量/內存時需要使用同步機制,因為他們在同一地址空間內。
3、設兩個變量a=19;b=29;在不創建新實例的情況下使a、b的值互換
參考答案:
這道題要求不創建新的實例,只有a、b兩個變量,要交換這兩個變量的值,通常的做法是使用臨時變量來臨時存儲,但是現在要求不使用新的實例,那么有什么辦法呢?
方法就是通過位運算來操作:
a = a ^ b; b = a ^ b; a = a ^ b;
對于題目中的a = 19,也就是對應二進制 00010011 ;而b=29,也就是對應二進制 00011101
- 第一步:a = 00010011 ^ 00011101 => 00001110,將a、b的值都記錄下來了
- 第二步:b = 00001110 ^ 00011101 => 00010011(值為19,也就是b得到了原來的a的值)
- 第三步:a = 00001110 ^ 00010011 => 00011101 (值為29,也就是a得到了原來的b的值)
注意,
符號表示按位異或。所謂按位異或是指對應位置上的二進制數值相同為0,不同為1。
4、使用block時什么情況會發生引用循環,如何解決?
參考答案:
筆者之前寫過這篇文章講了講開發中常見的內存循環引用的案例:
5、為什么要序列化,對象序列化方式
參考答案:
筆者也不是很確定,iOS里的序列化是指歸檔、JSON序列化嗎?實際上歸檔也就是將對象轉換成XML、JSON序列化也就是將對象轉換data。
將對象JSON序列化:
NSLog(@"%s", __FUNCTION__); NSDictionary *dict = @{@"key" : @"value", @"key1" : @"value1", @"key2" : @"value2"}; NSData *data = [NSJSONSerializationdataWithJSONObject:dictoptions:NSJSONWritingPrettyPrintederror:nil]; NSLog(@"%@", [[NSString alloc]initWithData:dataencoding:NSUTF8StringEncoding]);
將對象歸檔:需要遵守NSCoding協議,實現如下方法:
- (void)encodeWithCoder:(NSCoder *)aCoder { [aCoderencodeObject:self.titleforKey:@"title"]; }
如果所謂的序列化不是指這兩種,還請高人指點。
題照(后三題)
7、簡述如何處理UI與耗時操作的通信,有哪些方式及各自的優缺點
參考答案:
- 將耗時的計算和IO操作放在子線程去處理,然后到主線程更新UI。優點是
- 采用預加載方式,將耗時操作提前處理。優點是可讓UI更流暢;缺點是內存會增多,控制加載邏輯比較復雜。
- 采用延遲加載方式,將耗時操作而不立刻使用時,采用延遲加載。優點是界面可提高流暢度;缺點是在需要顯示時還需要加載才能顯示,需要稍稍等待。
不知道說得合不合適,還請高人提出還有哪些方式?
8、如何優化一個TableView
參考答案:
- 若高度一定,直接使用rowHeight屬性而不是使用heightForRowAtIndexPath方法,以減少調用的消耗。若高度是不固定的,heightForRowAtIndexPath所計算的高度應該緩存起來,每次數據源發生變化時,比如刪除、插入、更新行都會重新請求所有的高度。若有100個行,就會有調用100次,因為將高度緩存起來是應該的。同理,heightForHeaderInSection、heightForFooterInSection也應該緩存起來。
- 不要在tableView:cellForRowAtIndexPath:中做太多的計算和IO操作,比如可以將需要的計算提前計算好、IO操作也提前計算好。它應該直接調用來顯示就可以。
- 將計算行高的時間提前到從服務器獲取數據的時候,計算完了高度一并寫回數據庫或者通過轉型為model,將高度放到模型中。但是,最好將高度緩存起來。若一個model的數據有不同的狀態,比如展開與收起狀態,應該也將高度都緩存起來。注意使用異步去計算,計算完成后再回到主線程顯示。
- 在設置顯示圖片時,不要直接設置UIImageView的contentMode屬性自動適應,圖片變形會計算transform,壓縮時會乘以一個矩陣,消耗性能。對于要求性能較高的app,應該將得到的圖片經過處理成UIImageView大小后再呈現。
- 不要將視圖的opaque屬性設置為NO,默認為YES,它表示不透明度。當opque為NO的時候,圖層的半透明取決于圖片和其本身合成的圖層為結果。
- layer添加圓角是比較耗時的,這樣會離屏渲染,需要犧牲更多的性能。比如,圖片顯示有圓角時,可以通過core graphics來生成帶圓角的圖片等。
- 手動繪制cell。繪制cell不建議使用UIView,建議使用CALayer。 UIView的繪制是建立在CoreGraphic上的,其使用的是CPU。CALayer使用的是Core Animation,CPU、GPU都可以使用且由系統自動決定使用哪一個。UIView的繪制,使用的是自下向上的一層一層的繪制,而后渲染。Layer處理的是紋理,利用GPU的 Texture Cache和獨立的浮點數計算單元可以加速紋理的處理。
- 重用cell。防止重復的繪制,減少渲染次數,可提高性能。
- 減少subviews的數量。盡量放在同一層view上顯示。
- 盡量少動態給cell添加子view。用addView給Cell動態添加View,可以初始化時就添加,然后通過hide來控制是否顯示。
想要更深入,不防看看大牛的文章吧: iOS 保持界面流暢的技巧
9、假設讓你設計一關于指示器的開源庫,請設想和設計框架的public API,并指出大概需要如何做、需要注意一些什么方面來使別人容易使用這個框架
參考答案:
設計API的基本準則是:
- 簡單易用
- 易擴展
- 單一功能
注意事項:
- 盡可能不要依賴第三方庫(除非不使用第三庫需要非常大的工作量)。
- 每個API的功能應該是單一的,只做一件事。
- 注意性能、內存問題
- 注意多個HUD顯示、關閉的切換問題
- 樣式問題
分析:
要想讓全工程使用起來非常方便,那最好的方式就是使用單例,比如SVProgressHUD就是通過單例的方式來操作的。將單例封閉在內部,外部并不知道是單例,而外部的調用全是通過類方法的形式來調用,代碼調用是非常簡化的。使用單例的優點是方便管理和調用。缺點就是一直占用內存而不釋放。
當然,我們也可以通過正常的對象創建,在哪里使用就在哪里創建一個對象,自己來管理。這樣的方式在使用的地方不是那么方便,還需要再單獨進行一層封裝,以方便直接調用。但這種方式的好處就是在不需要使用的時候可以釋放掉;缺點就是如果同時創建了多個HUD來顯示時,需要調用者使用代碼邏輯來控制之前的顯示與隱藏或者切換文本等。
筆者覺得,使用單例方式更方便調用一些,外部也不用通過邏輯來管理多個HUD的顯示與隱藏問題,都封裝到內部,由封裝庫的人來維護。
假設設計一個HYBProgressHUB的小例子,隨手寫的,沒有真實寫完整:
typedef NS_ENUM(NSUInteger, HYBProgressHUBMaskType) { kHYBProgressHUBClear, kHYBProgressHUBBlack, kHYBProgressHUBUserEnabled }; @interfaceHYBProgressHUD: NSObject + (void)setDefaultMaskType:(HYBProgressHUBMaskType)defaultMaskType; + (void)show; + (void)showWithText:(NSString *)text; + (void)showWithImage:(NSString *)image; + (void)showWithText:(NSString *)textimage:(UIImage *)image; + (void)showWithText:(NSString *)textmaskType:(HYBProgressHUBMaskType)maskType; + (void)showWithImage:(NSString *)image maskType:(HYBProgressHUBMaskType)maskType; + (void)showWithText:(NSString *)textimage:(UIImage *)image maskType:(HYBProgressHUBMaskType)maskType; + (void)dismiss; + (void)dismissWithText:(NSString *)text; + (void)dismissWithImage:(UIImage *)image; + (void)dismissWithText:(NSString *)textimage:(UIImage *)image; @end
將單例放在實現文件中,并沒有暴露出來:
@implementation HYBProgressHUD + (instancetype)sharedInstance { __blockHYBProgressHUD *singleTon = nil; static dispatch_once_tonceToken; dispatch_once(&onceToken, ^{ singleTon = [[[self class]alloc]init]; }); return singleTon; } @end
因為根據不同的需求,不同的場景,show會有很多種形式,比如不可點擊、可點擊、是否半透明等,因此API也應該針對單一性原則提供對應的API。但是,一個App中大部分的HUD顯示的樣式、方式是相同的,因此,我們可以提供一個默認的全局的呈現樣式,比如調用show這個API要顯示的樣式就是默認的樣式,若不調用,內部也會給一個默認值。
對于dismiss也一樣,可以是直接隱藏,也可以在隱藏之前先提示點什么,比如純文本提示、純圖片提示、文本和圖片組合提示等。
當然,我們還可以擴展API設置dismiss的默認顯示圖片和文字的樣式:
typedef NS_ENUM(NSUInteger, HYBProgressHUBDismissType) { kHYBProgressHUBDismissSuccess, kHYBProgressHUBDismissFailed, kHYBProgressHUBDismissWarnings, kHYBProgressHUBDismissTimeout }; + (void)dismissWithText:(NSString *)texttype:(HYBProgressHUBDismissType)type;
比如在所有的網絡請求的地方,就可以寫一個通用的API,在成功與失敗回調處,統一處理顯示不同的類型提示。
提示:
上面所描述內容為筆者純手工嘗試設計的,不代表足夠合理,寫出來的最主要目的是拋磚引玉,當然我更希望能夠有大神出來指出其中的不足或者加以補充,讓后來者少走彎路。
最后
本來不太想整理這份筆試題的,但是對于其中的幾道題確實很需要認真地思考,另外也希望得到大神們的評論,指出其中的缺陷,或者能夠加以補充。請各位大神們,注入新鮮的血液吧!
參考
關注我
關注 | 賬號 | 備注 |
---|---|---|
Swift/ObjC技術群一 | 324400294 | 群一若已滿,請申請群二 |
Swift/ObjC技術群二 | 494669518 | 群二若已滿,請申請群三 |
Swift/ObjC技術群三 | 461252383 | 群三若已滿,會有提示信息 |
關注微信公眾號 | iOSDevShares | 關注微信公眾號,會定期地推送好文章 |
關注新浪微博賬號 | 標哥Jacky | 關注微博,每次發布文章都會分享到新浪微博 |
關注標哥的GitHub | CoderJackyHuang | 這里有很多的Demo和開源組件 |
關于我 | 進一步了解標哥 | 如果覺得文章對您很有幫助,可捐助我! |
版權聲明:本文為【標哥的技術博客】原創出品,歡迎轉載,轉載時請注明出處!
</div>