2019年的夏天,成都的天氣格外的悶熱。html
由於公司的緣由,致使我不得不考慮去面試一家穩定成熟的大公司,本身從一開始也一直夢想着進入一家能夠獲得廣闊平臺的公司發展,有朝一日能夠當上技術負責人,但是現實老是那麼殘酷,4年了,4年了,每次面試感受本身仍是隻是會回答:我知道,可是沒有深刻研究過。這個我瞭解過,可是尚未處理過。而後就是一個勁的出汗來排解心裏的壓力。3次換工做,面試過30-40次,每次都只是爲了面試而面試(背題),不少東西都記住不。哎~ 我太難了~ 太難了~前端
無論面試是否經過,仍是來總結一下面試常常遇到的問題吧。ios
答: Objective-c的類不能夠有多繼承,OC裏面都是單繼承,多繼承能夠用protocol委託代理來模擬實現 能夠實現多個接口,能夠經過實現多個接口完成OC的多重繼承 Category是類別; ⚠️重寫一個類的方式用繼承好仍是分類好: 重寫一個類的方式用繼承仍是分類.取決於具體狀況.假如目標類有許多的子類.咱們須要拓展這個類又不但願影響到原有的代碼.繼承後比較好. 若是僅僅是拓展方法.分類更好.(不須要涉及到原先的代碼) 分類中方法的優先級比原來類中的方法高,也就是說,在分類中重寫了原來類中的方法,那麼分類中的方法會覆蓋原來類中的方法 ⚠️爲何不要在category中重寫一個類原有的方法: 一、category沒有辦法去代替子類,它不能像子類同樣經過super去調用父類的方法實現。若是category中重寫覆蓋了當前類中的某個方法,那麼這個當前類中的原始方法實現,將永遠不會被執行,這在某些方法裏是致命的。(ps:這裏提一下,+(void)load方法是一個特例,它會在當前類執行完以後再在category中執行。) 二、同時,一個category也不能可靠的覆蓋另外一個category中相同的類的相同的方法。例如UIViewController+A與UIViewController+B,都重寫了viewDidLoad,咱們就沒法控制誰覆蓋了誰。 三、經過觀察頭文件咱們能夠發現,Cocoa框架中的許多類都是經過category來實現功能的,可能不經意間你就覆蓋了這些方法中的其一,有時候就會產生一些沒法排查的異常緣由。 四、category的誕生只是爲了讓開發者更加方便的去拓展一個類,它的初衷並非讓你去改變一個類。 結論: 要重寫方法,固然咱們首推經過子類重寫父類的方法,在一些不方便重寫的狀況下,咱們也能夠在category中用runtime進行method swizzling(方法的偷樑換柱)來實現。
答: * strong表示指向並擁有該對象。其修飾的對象引用計數會增長1。該對象只要引用計數不爲0則不會被銷燬。固然強行將其設爲nil能夠銷燬它。 * weak表示指向但不擁有該對象。其修飾的對象引用計數不會增長。無需手動設置,該對象會自行在內存中銷燬。 * assign主要用於修飾基本數據類型,如NSInteger和CGFloat,這些數值主要存在於棧上。 * weak 通常用來修飾對象,assign通常用來修飾基本數據類型。緣由是assign修飾的對象被釋放後,指針的地址依然存在,形成野指針,在堆上容易形成崩潰。而棧上的內存系統會自動處理,不會形成野指針。 * copy與strong相似。不一樣之處是strong的複製是多個指針指向同一個地址,而copy的複製每次會在內存中拷貝一份對象,指針指向不一樣地址。copy通常用在修飾有可變對應類型的不可變對象上,如NSString, NSArray, NSDictionary。 * Objective-C 中,基本數據類型的默認關鍵字是atomic, readwrite, assign;普通屬性的默認關鍵字是atomic, readwrite, strong。
答: 用 @property 聲明 NSString、NSArray、NSDictionary 常用 copy 關鍵字,是由於他們有對應的可變類型:NSMutableString、NSMutableArray、NSMutableDictionary,他們之間可能進行賦值操做(就是把可變的賦值給不可變的),爲確保對象中的字符串值不會無心間變更,應該在設置新屬性值時拷貝一份。 1\. 由於父類指針能夠指向子類對象,使用 copy 的目的是爲了讓本對象的屬性不受外界影響,使用 copy 不管給我傳入是一個可變對象仍是不可對象,我自己持有的就是一個不可變的副本。 2\. 若是咱們使用是 strong ,那麼這個屬性就有可能指向一個可變對象,若是這個可變對象在外部被修改了,那麼會影響該屬性。 //總結:使用copy的目的是,防止把可變類型的對象賦值給不可變類型的對象時,可變類型對象的值發送變化會無心間篡改不可變類型對象原來的值。
答: 淺拷貝:只複製指向對象的指針,而不復制引用對象自己。 深拷貝:複製引用對象自己。內存中存在了兩份獨立對象自己,當修改A時,A_copy不變。
iOS深淺拷貝c++
答:Objective-C的內存管理主要有三種方式ARC(自動內存計數)、手動內存計數、內存池。 1). 自動內存計數ARC:由Xcode自動在App編譯階段,在代碼中添加內存管理代碼。 2). 手動內存計數MRC:遵循內存誰申請、誰釋放;誰添加,誰釋放的原則。 3). 內存釋放池Release Pool:把須要釋放的內存統一放在一個池子中,當池子被抽乾後(drain),池子中全部的內存空間也被自動釋放掉。內存池的釋放操做分爲自動和手動。自動釋放受runloop機制影響。
答: 1\. 分類有名字,類擴展沒有分類名字,是一種特殊的分類。 2\. 分類只能擴展方法(屬性僅僅是聲明,並沒真正實現),類擴展能夠擴展屬性、成員變量和方法。 3\. 繼承能夠增長,修改或者刪除方法,而且能夠增長屬性。
iOS中Category和Extension 原理詳解git
IOS 分類(category)、擴展(Extension)和繼承(inheritance)的區別?程序員
答: 主要是將數據類型的肯定由編譯時,推遲到了運行時。簡單來講, 運行時機制使咱們直到運行時纔去決定一個對象的類別,以及調用該類別對象指定方法。
答: KVC(key-value-coding)鍵值編碼,是一種間接訪問實例變量的方法。提供一種機制來間接訪問對象的屬性。 一、給私有變量賦值。 二、給控件的內部屬性賦值(如自定義UITextFiled的clearButton,或placeholder的顏色,通常可利用runtime獲取控件的內部屬性名,Ivar *ivar = class_getInstanceVariable獲取實例成員變量)。 [textField setValue:[UIColor redColor] forKeyPath:@"placeholderLabel.textColor"]; 三、結合Runtime,model和字典的轉換(setValuesForKeysWithDictionary,class_copyIvarList獲取指定類的Ivar成員列表) KVO是一種基於KVC實現的觀察者模式。當指定的被觀察的對象的屬性更改了,KVO會以自動或手動方式通知觀察者。 事例:監聽 ScrollView 的 contentOffSet屬性 [scrollview addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];
KVO圖面試
答: 1\. 在block內部使用外部指針且會形成循環引用狀況下,須要用__weak修飾外部指針: __weak typeof(self) weakSelf = self; 2\. 在block內部若是調用了延時函數還使用弱指針會取不到該指針,由於已經被銷燬了,須要在block內部再將弱指針從新強引用一下。 __strong typeof(self) strongSelf = weakSelf; 3\. 若是須要在block內部改變外部棧區變量的話,須要在用__block修飾外部變量。
答: 1.從管理方式來說 對於棧來說,是由編譯器自動管理,無需咱們手工控制; 對於堆來講,釋放工做由程序員控制,容易產生內存泄露(memory leak) 2.從申請大小大小方面講 棧空間比較小 堆控件比較大 3.從數據存儲方面來說 棧空間中通常存儲基本類型,對象的地址 堆空間通常存放對象自己,block的copy等
答: # 堆 堆是一種通過排序的樹形數據結構,每一個節點都有一個值,一般咱們所說的堆的數據結構是指二叉樹。因此堆在數據結構中一般能夠被看作是一棵樹的數組對象。並且堆須要知足一下兩個性質: 1)堆中某個節點的值老是不大於或不小於其父節點的值; 2)堆老是一棵徹底二叉樹。 堆分爲兩種狀況,有最大堆和最小堆。將根節點最大的堆叫作最大堆或大根堆,根節點最小的堆叫作最小堆或小根堆,在一個擺放好元素的最小堆中,父結點中的元素必定比子結點的元素要小,但對於左右結點的大小則沒有規定誰大誰小。 堆經常使用來實現優先隊列,堆的存取是隨意的,這就如同咱們在圖書館的書架上取書,雖然書的擺放是有順序的,可是咱們想取任意一本時沒必要像棧同樣,先取出前面全部的書,書架這種機制不一樣於箱子,咱們能夠直接取出咱們想要的書。 # 棧 棧是限定僅在表尾進行插入和刪除操做的線性表。咱們把容許插入和刪除的一端稱爲棧頂,另外一端稱爲棧底,不含任何數據元素的棧稱爲空棧。棧的特殊之處在於它限制了這個線性表的插入和刪除位置,它始終只在棧頂進行。 棧是一種具備後進先出的數據結構,又稱爲後進先出的線性表,簡稱 LIFO(Last In First Out)結構。也就是說後存放的先取,先存放的後取,這就相似於咱們要在取放在箱子底部的東西(放進去比較早的物體),咱們首先要移開壓在它上面的物體(放進去比較晚的物體)。 堆棧中定義了一些操做。兩個最重要的是PUSH和POP。PUSH操做在堆棧的頂部加入一個元素。POP操做相反,在堆棧頂部移去一個元素,並將堆棧的大小減一。 棧的應用—遞歸 # 隊列 隊列是隻容許在一端進行插入操做、而在另外一端進行刪除操做的線性表。容許插入的一端稱爲隊尾,容許刪除的一端稱爲隊頭。它是一種特殊的線性表,特殊之處在於它只容許在表的前端進行刪除操做,而在表的後端進行插入操做,和棧同樣,隊列是一種操做受限制的線性表。 隊列是一種先進先出的數據結構,又稱爲先進先出的線性表,簡稱 FIFO(First In First Out)結構。也就是說先放的先取,後放的後取,就如同行李過安檢的時候,先放進去的行李在另外一端老是先出來,後放入的行李會在最後面出來。
答: 多態在面嚮對象語言中指同一個接口有多種不一樣的實現方式,在OC中,多態則是不一樣對象對同一消息的不一樣響應方式;子類經過重寫父類的方法來改變同一方法的實現.體現多態性 通俗來說: 多態就父類類型的指針指向子類的對象,在函數(方法)調用的時候能夠調用到正確版本的函數(方法)。 多態就是某一類事物的多種形態.繼承是多態的前提;
答: 分類: 在不修改原有類代碼的狀況下,能夠給類添加方法 Categroy 給類擴展方法,或者關聯屬性, Categroy底層結構也是一個結構體:內部存儲這結構體的名字,那個類的分類,以及對象和類方法列表,協議,屬性信息 經過Runtime加載某個類的全部Category數據 把全部Category的方法、屬性、協議數據,合併到一個大數組中後面參與編譯的Category數據,會在數組的前面 將合併後的分類數據(方法、屬性、協議),插入到類原來數據的前面
答: 協議:協議是一套標準,這個標準中聲明瞭不少方法,可是不關心具體這些方法是怎麼實現的,具體實現是由遵循這個協議的類去完成的。 在OC中,一個類能夠實現多個協議,經過協議能夠彌補單繼承的缺陷可是協議跟繼承不同,協議只是一個方法列表,方法的實現得靠遵循這個協議的類去實現。
答: UIView 繼承 UIResponder,而 UIResponder 是響應者對象,能夠對iOS 中的事件響應及傳遞,CALayer 沒有繼承自 UIResponder,因此 CALayer 不具有響應處理事件的能力。CALayer 是 QuartzCore 中的類,是一個比較底層的用來繪製內容的類,用來繪製UI UIView 對 CALayer 封裝屬性,對 UIView 設置 frame、center、bounds 等位置信息時,其實都是UIView 對 CALayer 進一層封裝,使得咱們能夠很方便地設置控件的位置;例如圓角、陰影等屬性, UIView 就沒有進一步封裝,因此咱們仍是須要去設置 Layer 的屬性來實現功能。 UIView 是 CALayer 的代理,UIView 持有一個 CALayer 的屬性,而且是該屬性的代理,用來提供一些 CALayer 行的數據,例如動畫和繪製。
答: js調用oc的三種方式: 方式一:經過替換js中的function(方法) 方式二:經過注入對象,直接調用對象方法 方式三:利用網頁重定向,截取字符串. oc調用js代碼兩種方式 1.經過webVIew調用 webView stringByEvaluatingJavaScriptFromString: 調用 2.經過JSContext調用[context evaluateScript:];
答: HTTP本質上是一種協議,全稱是Hypertext Transfer Protocol,即超文本傳輸協議。HTTP是一個基於TCP/IP通訊協議來傳遞數據, 該協議用於規定客戶端與服務端之間的傳輸規則,所傳輸的內容不侷限於文本(其實能夠傳輸任意類型的數據)。 一次HTTP能夠看作是一個事務,其工做過程分爲4步: 1.客戶端與服務器創建鏈接 2.創建鏈接後,客戶端給服務端發送請求 3.服務器收到消息後,給與響應操做 4.客戶端收到消息後,展現到屏幕上,斷開鏈接.
答: 區別 1.HTTPS 須要向機構申請 CA 證書,極少免費。 2.HTTP 屬於明文傳輸,HTTPS基於 SSL 進行加密傳輸。 3.HTTP 端口號爲 80,HTTPS 端口號爲 443 。 4.HTTPS 是加密傳輸,有身份驗證的環節,更加安全。 安全 SSL(安全套接層) TLS(傳輸層安全) 以上二者在傳輸層之上,對網絡鏈接進行加密處理,保障數據的完整性,更加的安全。
答: 1.單一職責原則 通俗地講就是一個類只作一件事 CALayer:動畫和視圖的顯示。 UIView:只負責事件傳遞、事件響應。 2.開閉原則 對修改關閉,對擴展開放。 要考慮到後續的擴展性,而不是在原有的基礎上來回修改 3.接口隔離原則 使用多個專門的協議、而不是一個龐大臃腫的協議,如 UITableviewDelegate + UITableViewDataSource 4.依賴倒置原則 抽象不該該依賴於具體實現、具體實現能夠依賴於抽象。 調用接口感受不到內部是如何操做的 5.里氏替換原則 父類能夠被子類無縫替換,且原有的功能不受任何影響 如:KVO 6.迪米特法則 一個對象應當對其餘對象儘量少的瞭解,實現高聚合、低耦合
答: 1.一、swift和OC的共同點: - OC出現過的絕大多數概念,好比引用計數、ARC(自動引用計數)、屬性、協議、接口、初始化、擴展類、命名參數、匿名函數等,在Swift中繼續有效(可能最多換個術語)。 - Swift和Objective-C共用一套運行時環境,Swift的類型能夠橋接到Objective-C(下面我簡稱OC),反之亦然 1.二、swift的優勢: - swift注重安全,OC注重靈活 - swift注重面向協議編程、函數式編程、面向對象編程,OC注重面向對象編程 - swift注重值類型,OC注重指針和引用 - swift是靜態類型語言,OC是動態類型語言 - swift容易閱讀,文件結構和大部分語法簡易化,只有.swift文件,結尾不須要分號 - swift中的可選類型,是用於全部數據類型,而不只僅侷限於類。相比於OC中的nil更加安全和簡明 - swift中的泛型類型更加方便和通用,而非OC中只能爲集合類型添加泛型 - swift中各類方便快捷的高階函數(函數式編程) (Swift的標準數組支持三個高階函數:map,filter和reduce,以及map的擴展flatMap) - swift新增了兩種權限,細化權限。open > public > internal(默認) > fileprivate > private - swift中獨有的元組類型(tuples),把多個值組合成複合值。元組內的值能夠是任何類型,並不要求是相同類型的。
答: Application:存放程序源文件,上架前通過數字簽名,上架後不可修改 Documents:經常使用目錄,iCloud備份目錄,存放數據 Library Caches:存放體積大又不須要備份的數據 Preference:設置目錄,iCloud會備份設置信息 tmp:存放臨時文件,不會被備份,並且這個文件下的數據有可能隨時被清除的可能
答: NSUserDefault 簡單數據快速讀寫 Property list (屬性列表)文件存儲 Archiver (歸檔) SQLite 本地數據庫 CoreData(是iOS5以後纔出現的一個框架,本質上是對SQLite的一個封裝,它提供了對象-關係映射(ORM)的功能,即可以將OC對象轉化成數據,保存在SQLite數據庫文件中,也可以將保存在數據庫中的數據還原成OC對象,經過CoreData管理應用程序的數據模型)
答: - initWithCoder:(NSCoder *)aDecoder:(若是使用storyboard或者xib) - loadView:加載view - viewDidLoad:view加載完畢 - viewWillAppear:控制器的view將要顯示 - viewWillLayoutSubviews:控制器的view將要佈局子控件 - viewDidLayoutSubviews:控制器的view佈局子控件完成 - viewDidAppear:控制器的view徹底顯示 - viewWillDisappear:控制器的view即將消失的時候 - viewDidDisappear:控制器的view徹底消失的時候 - dealloc 控制器銷燬
答: Cocoa包含Foundation和AppKit框架,可用於開發Mac OS X系統的應用程序。 Cocoa Touch包含Foundation和UIKit框架,可用於開發iPhone OS系統的應用程序。 Cocoa是 Mac OS X 的開發環境,Cocoa Touch是 iPhone OS的開發環境。
答: cocoa touch底層技術架構 主要分爲4層: 可觸摸層 Cocoa Touch : UI組件,觸摸事件和事件驅動,系統接口 媒體層 Media: 音視頻播放,動畫,2D和3D圖形 Core Server: 核心服務層,底層特性,文件,網絡,位置服務區等 Core OS: 內存管理,底層網絡,硬盤管理
答: 三種模式都是一個對象傳遞事件給另一個對象,而且不要他們有耦合。 delegate. 一對一 notification 一對多,多對多 KVO 一對一 三者各有本身的特色: delegate 語法簡潔,方便閱讀,易於調試 notification 靈活多變,能夠跨越多個類之間進行使用 KVO 實現屬性監聽,實現model和view同步 能夠根據實際開發遇到的場景來使用不一樣的方式
答: Instruments裏面工具不少,經常使用的有: (1).Time Profiler:性能分析,用來檢測應用CPU的使用狀況.能夠看到應用程序中各個方法正在消耗CPU時間。 (2).Zoombies:檢查是否訪問了殭屍對象,可是這個工具只能從上往下檢查,不智能 (3).Allocations:用來檢查內存,寫算法的那批人也用這個來檢查 (4).Leaks:檢查內存,看是否有內存泄漏 (5).Core Animation:評估圖形性能,這個選項檢查了圖片是否被縮放,以及像素是否對齊。被放縮的圖片會被標記爲黃色,像素不對齊則會標註爲紫色。黃色、紫色越多,性能越差。
答: 選擇排序、冒泡排序、插入排序三種排序算法能夠總結爲以下: 都將數組分爲已排序部分和未排序部分。 選擇排序將已排序部分定義在左端,而後選擇未排序部分的最小元素和未排序部分的第一個元素交換。 冒泡排序將已排序部分定義在右端,在遍歷未排序部分的過程執行交換,將最大元素交換到最右端。 插入排序將已排序部分定義在左端,將未排序部分元的第一個元素插入到已排序部分合適的位置。 /** * 【選擇排序】:最值出如今起始端 * * 第1趟:在n個數中找到最小(大)數與第一個數交換位置 * 第2趟:在剩下n-1個數中找到最小(大)數與第二個數交換位置 * 重複這樣的操做...依次與第三個、第四個...數交換位置 * 第n-1趟,最終可實現數據的升序(降序)排列。 * */ void selectSort(int *arr, int length) { for (int i = 0; i < length - 1; i++) { //趟數 for (int j = i + 1; j < length; j++) { //比較次數 if (arr[i] > arr[j]) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } } } /** * 【冒泡排序】:相鄰元素兩兩比較,比較完一趟,最值出如今末尾 * 第1趟:依次比較相鄰的兩個數,不斷交換(小數放前,大數放後)逐個推動,最值最後出如今第n個元素位置 * 第2趟:依次比較相鄰的兩個數,不斷交換(小數放前,大數放後)逐個推動,最值最後出如今第n-1個元素位置 * …… …… * 第n-1趟:依次比較相鄰的兩個數,不斷交換(小數放前,大數放後)逐個推動,最值最後出如今第2個元素位置 */ void bublleSort(int *arr, int length) { for(int i = 0; i < length - 1; i++) { //趟數 for(int j = 0; j < length - i - 1; j++) { //比較次數 if(arr[j] > arr[j+1]) { int temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } } } /** * 折半查找:優化查找時間(不用遍歷所有數據) * * 折半查找的原理: * 1> 數組必須是有序的 * 2> 必須已知min和max(知道範圍) * 3> 動態計算mid的值,取出mid對應的值進行比較 * 4> 若是mid對應的值大於要查找的值,那麼max要變小爲mid-1 * 5> 若是mid對應的值小於要查找的值,那麼min要變大爲mid+1 * */ // 已知一個有序數組, 和一個key, 要求從數組中找到key對應的索引位置 int findKey(int *arr, int length, int key) { int min = 0, max = length - 1, mid; while (min <= max) { mid = (min + max) / 2; //計算中間值 if (key > arr[mid]) { min = mid + 1; } else if (key < arr[mid]) { max = mid - 1; } else { return mid; } } return -1; }
答: 0、首先顯示佔位圖 一、在webimagecache中尋找圖片對應的緩存,它是以url爲數據索引先在內存中查找是否有緩存; 二、若是沒有緩存,就經過md5處理過的key來在磁盤中查找對應的數據,若是找到就會把磁盤中的數據加到內存中,並顯示出來; 三、若是內存和磁盤中都沒有找到,就會向遠程服務器發送請求,開始下載圖片; 四、下載完的圖片加入緩存中,並寫入到磁盤中; 五、整個獲取圖片的過程是在子線程中進行,在主線程中顯示。
答: AFNetworking是封裝的NSURLSession的網絡請求,由五個模塊組成:分別由NSURLSession,Security,Reachability,Serialization,UIKit五部分組成 NSURLSession:網絡通訊模塊(核心模塊) 對應 AFNetworking中的 AFURLSessionManager和對HTTP協議進行特化處理的AFHTTPSessionManager,AFHTTPSessionManager是繼承於AFURLSessionmanager的 Security:網絡通信安全策略模塊 對應 AFSecurityPolicy Reachability:網絡狀態監聽模塊 對應AFNetworkReachabilityManager Seriaalization:網絡通訊信息序列化、反序列化模塊 對應 AFURLResponseSerialization UIKit:對於iOS UIKit的擴展庫
答: 當一個對象調用setValue方法時,方法內部會作如下操做: 1). 檢查是否存在相應的key的set方法,若是存在,就調用set方法。 2). 若是set方法不存在,就會查找與key相同名稱而且帶下劃線的成員變量,若是有,則直接給成員變量屬性賦值。 3). 若是沒有找到_key,就會查找相同名稱的屬性key,若是有就直接賦值。 4). 若是尚未找到,則調用valueForUndefinedKey:和setValue:forUndefinedKey:方法。 這些方法的默認實現都是拋出異常,咱們能夠根據須要重寫它們。
答: KVO-鍵值觀察機制,原理以下: 1.當給A類添加KVO的時候,runtime動態的生成了一個子類NSKVONotifying_A,讓A類的isa指針指向NSKVONotifying_A類,重寫class方法,隱藏對象真實類信息 2.重寫監聽屬性的setter方法,在setter方法內部調用了Foundation 的 _NSSetObjectValueAndNotify 函數 3._NSSetObjectValueAndNotify函數內部 a) 首先會調用 willChangeValueForKey b) 而後給屬性賦值 c) 最後調用 didChangeValueForKey d) 最後調用 observer 的 observeValueForKeyPath 去告訴監聽器屬性值發生了改變 . 4.重寫了dealloc作一些 KVO 內存釋放
答:通常都是說關於tableView的優化處理, 形成tableView卡頓的緣由 1.沒有使用cell的重用標識符,致使一直建立新的cell 2.cell的從新佈局 3.沒有提早計算並緩存cell的屬性及內容 4.cell中控件的數量過多 5.使用了ClearColor,無背景色,透明度爲0 6.更新只使用tableView.reloadData()(若是隻是更新某組的話,使用reloadSection進行局部更新) 7.加載網絡數據,下載圖片,沒有使用異步加載,並緩存 8.使用addView 給cell動態添加view 9.沒有按需加載cell(cell滾動很快時,只加載範圍內的cell) 10.實現無用的代理方法(tableView只遵照兩個協議) 11.沒有作緩存行高(estimatedHeightForRow不能和HeightForRow裏面的layoutIfNeed同時存在,這二者同時存在纔會出現「竄動」的bug。 建議是:只要是固定行高就寫預估行高來減小行高調用次數提高性能。若是是動態行高就不要寫預估方法了,用一個行高的緩存字典來減小代碼的調用次數便可) 12.作了多餘的繪製工做(在實現drawRect:的時候,它的rect參數就是須要繪製的區域,這個區域以外的不須要進行繪製) 13.沒有預渲染圖像。(當新的圖像出現時,仍然會有短暫的停頓現象。解決的辦法就是在bitmap context裏先將其畫一遍,導出成UIImage對象,而後再繪製到屏幕) 提高tableView的流暢度 *本質上是下降 CPU、GPU 的工做,從這兩個大的方面去提高性能。 1.CPU:對象的建立和銷燬、對象屬性的調整、佈局計算、文本的計算和排版、圖片的格式轉換和解碼、圖像的繪製 2.GPU:紋理的渲染 卡頓優化在 CPU 層面 1.儘可能用輕量級的對象,好比用不到事件處理的地方,能夠考慮使用 CALayer 取代 UIView 2.不要頻繁地調用 UIView 的相關屬性,好比 frame、bounds、transform 等屬性,儘可能減小沒必要要的修改 3.儘可能提早計算好佈局,在有須要時一次性調整對應的屬性,不要屢次修改屬性 4.Autolayout 會比直接設置 frame 消耗更多的 CPU 資源 5.圖片的 size 最好恰好跟 UIImageView 的 size 保持一致 6.控制一下線程的最大併發數量 7.儘可能把耗時的操做放到子線程 8.文本處理(尺寸計算、繪製) 9.圖片處理(解碼、繪製) 卡頓優化在 GPU層面 1.儘可能避免短期內大量圖片的顯示,儘量將多張圖片合成一張進行顯示 2.GPU能處理的最大紋理尺寸是 4096x4096,一旦超過這個尺寸,就會佔用 CPU 資源進行處理,因此紋理儘可能不要超過這個尺寸 3.儘可能減小視圖數量和層次 4.減小透明的視圖(alpha<1),不透明的就設置 opaque 爲 YES 5.儘可能避免出現離屏渲染
答: runtime簡稱運行時。OC是運行時機制,也就是在運行時才作一些處理。例如:C語言在編譯的時候就知道要調用哪一個方法函數,而OC在編譯的時候並不知道要調用哪一個方法函數,只有在運行的時候才知道調用的方法函數名稱,來找到對應的方法函數進行調用。 1.發送消息 【場景:方法調用】 2.交換方法實現(交換系統的方法) 【場景:當第三方框架或者系統原生方法功能不能知足咱們的時候,咱們能夠在保持系統原有方法功能的基礎上,添加額外的功能。】 3.動態添加方法 【場景:若是一個類方法很是多,加載類到內存的時候也比較耗費資源,須要給每一個方法生成映射表,能夠使用動態給某個類,添加方法解決。】 4.利用關聯對象(AssociatedObject)給分類添加屬性 【 場景:分類是不能自定義屬性和變量的,這時候能夠使用runtime動態添加屬性方法; 原理:給一個類聲明屬性,其實本質就是給這個類添加關聯,並非直接把這個值的內存空間添加到類存空間。 】 5.遍歷類的全部成員變量 【 1.NSCoding自動歸檔解檔 場景:若是一個模型有許多個屬性,實現自定義模型數據持久化時,須要對每一個屬性都實現一遍encodeObject 和 decodeObjectForKey方法,比較麻煩。咱們能夠使用Runtime來解決。 原理:用runtime提供的函數遍歷Model自身全部屬性,並對屬性進行encode和decode操做。 2.字典轉模型 原理:利用Runtime,遍歷模型中全部屬性,根據模型的屬性名,去字典中查找key,取出對應的值,給模型的屬性賦值。 3.修改textfield的佔位文字顏色 】 6.利用消息轉發機制解決方法找不到的異常問題
答: 1.直接使用setCornerRadius 【這樣設置會觸發離屏渲染,比較消耗性能。好比當一個頁面上有十幾頭像這樣設置了圓角會明顯感受到卡頓。 注意:png圖片UIImageView處理圓角是不會產生離屏渲染的。(ios9.0以後不會離屏渲染,ios9.0以前仍是會離屏渲染) 】 2.setCornerRadius設置圓角以後,shouldRasterize=YES光柵化 【avatarImageView.layer.shouldRasterize = YES; avatarImageViewUrl.layer.rasterizationScale=[UIScreen mainScreen].scale; //UIImageView不加這句會產生一點模糊 shouldRasterize=YES設置光柵化,能夠使離屏渲染的結果緩存到內存中存爲位圖, 使用的時候直接使用緩存,節省了一直離屏渲染損耗的性能。 可是若是layer及sublayers經常改變的話,它就會一直不停的渲染及刪除緩存從新 建立緩存,因此這種狀況下建議不要使用光柵化,這樣也是比較損耗性能的。 】 3.直接覆蓋一張中間爲圓形透明的圖片(推薦使用) 4.UIImage drawInRect繪製圓角 【這種方式GPU損耗低內存佔用大,並且UIButton上不知道怎麼繪製,能夠用 UIimageView添加個點擊手勢當作UIButton使用。】 5.SDWebImage處理圖片時Core Graphics繪製圓角(暫時感受是最優方法)
答: 從字面上講就是運行循環,它內部就是do-while循環,在這個循環內部不斷地處理各類任務。 一個線程對應一個RunLoop,基本做用就是保持程序的持續運行,處理app中的各類事件。經過runloop,有事運行,沒事就休息,能夠節省cpu資源,提升程序性能。 主線程的run loop默認是啓動的。iOS的應用程序裏面,程序啓動後會有一個以下的main()函數 int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } }
答: RunLoop,是多線程的法寶,即一個線程一次只能執行一個任務,執行完任務後就會退出線程。主線程執行完即時任務時會繼續等待接收事件而不退出。非主線程一般來講就是爲了執行某一任務的,執行完畢就須要歸還資源,所以默認是不運行RunLoop的; 每個線程都有其對應的RunLoop,只是默認只有主線程的RunLoop是啓動的,其它子線程的RunLoop默認是不啓動的,若要啓動則須要手動啓動; 在一個單獨的線程中,若是須要在處理完某個任務後不退出,繼續等待接收事件,則須要啓用RunLoop; NSRunLoop提供了一個添加NSTimer的方法,能夠指定Mode,若是要讓任何狀況下都回調,則須要設置Mode爲Common模式; 實質上,對於子線程的runloop默認是不存在的,由於蘋果採用了懶加載的方式。若是咱們沒有手動調用[NSRunLoop currentRunLoop]的話,就不會去查詢是否存在當前線程的RunLoop,也就不會去加載,更不會建立。
答: 緣由在於滑動時當前線程的runloop切換了mode用於列表滑動,致使timer暫停。 runloop中的mode主要用來指定事件在runloop中的優先級,有如下幾種: * Default(NSDefaultRunLoopMode):默認,通常狀況下使用; * Connection(NSConnectionReplyMode):通常系統用來處理NSConnection相關事件,開發者通常用不到; * Modal(NSModalPanelRunLoopMode):處理modal panels事件; * Event Tracking(NSEventTrackingRunLoopMode):用於處理拖拽和用戶交互的模式。 * Common(NSRunloopCommonModes):模式合集。默認包括Default,Modal,Event Tracking三大模式,能夠處理幾乎全部事件。 回到題中的情境。滑動列表時,runloop的mode由原來的Default模式切換到了Event Tracking模式,timer原來好好的運行在Default模式中,被關閉後天然就中止工做了。 解決方法其一是將timer加入到NSRunloopCommonModes中。其二是將timer放到另外一個線程中,而後開啓另外一個線程的runloop,這樣能夠保證與主線程互不干擾,而如今主線程正在處理頁面滑動。
方法1 [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; 方法2 dispatch_async(dispatch_get_global_queue(0, 0), ^{ timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(repeat:) userInfo:nil repeats:true]; [[NSRunLoop currentRunLoop] run]; });
答: 進程: 1.進程是一個具備必定獨立功能的程序關於某次數據集合的一次運行活動,它是操做系統分配資源的基本單元. 2.進程是指在系統中正在運行的一個應用程序,就是一段程序的執行過程,咱們能夠理解爲手機上的一個app. 3.每一個進程之間是獨立的,每一個進程均運行在其專用且受保護的內存空間內,擁有獨立運行所需的所有資源 線程 1.程序執行流的最小單元,線程是進程中的一個實體. 2.一個進程要想執行任務,必須至少有一條線程.應用程序啓動的時候,系統會默認開啓一條線程,也就是主線程 進程和線程的關係 1.線程是進程的執行單元,進程的全部任務都在線程中執行 2.線程是 CPU 分配資源和調度的最小單位 3.一個程序能夠對應多個進程(多進程),一個進程中可有多個線程,但至少要有一條線程 4.同一個進程內的線程共享進程資源
答: NSThread 面向對象的,須要程序員手動建立線程,但不須要手動銷燬。子線程間通訊很難。 GCD c語言,充分利用了設備的多核,自動管理線程生命週期。比NSOperation效率更高。 NSOperation 基於gcd封裝,更加面向對象,比gcd多了一些功能。 【場景:1.多個網絡請求完成後執行下一步 2.多個網絡請求順序執行後執行下一步 3.異步操做兩組數據時, 執行完第一組以後, 才能執行第二組】
答: 項目中使用 NSOperation 的優勢是 NSOperation 是對線程的高度抽象,在項目中使 用它,會使項目的程序結構更好,子類化 NSOperation 的設計思路,是具備面向對 象的優勢(複用、封裝),使得實現是多線程支持,而接口簡單,建議在複雜項目中 使用。 項目中使用 GCD 的優勢是 GCD 自己很是簡單、易用,對於不復雜的多線程操 做,會節省代碼量,而 Block 參數的使用,會是代碼更爲易讀,建議在簡單項目中 使用。
答: GCD(Grand Central Dispatch), 又叫作大中央調度, 它對線程操做進行了封裝,加入了不少新的特性,內部進行了效率優化,提供了簡潔的C語言接口, 使用更加高效,也是蘋果推薦的使用方式. GCD的隊列能夠分爲2大類型 1.併發隊列(Concurrent Dispatch Queue) 可讓多個任務併發(同時)執行(自動開啓多個線程同時執行任務) 併發功能只有在異步(dispatch_async)函數下才有效 2.串行隊列(Serial Dispatch Queue) 讓任務一個接着一個地執行(一個任務執行完畢後,再執行下一個任務),按照FIFO順序執行.
答: GCD多線程常常會使用 dispatch_sync和dispatch_async函數向指定隊列添加任務,分別是同步和異步 同步:指阻塞當前線程,既要等待添加的耗時任務塊Block完成後,函數才能返回,後面的代碼才能繼續執行 異步:指將任務添加到隊列後,函數當即返回,後面的代碼不用等待添加的任務完成後便可執行,異步提交沒法肯定任務執行順序
答: 柵欄函數 一個dispatch barrier 容許在一個併發隊列中建立一個同步點。當在併發隊列中遇到一個barrier, 他會延遲執行barrier的block,等待全部在barrier以前提交的blocks執行結束。 這時,barrier block本身開始執行。 以後, 隊列繼續正常的執行操做。
答: 一、對稱加密又稱公開密鑰加密,加密和解密都會用到同一個密鑰,若是密鑰被攻擊者得到,此時加密就失去了意義。常見的對稱加密算法有DES、3DES、AES、Blowfish、IDEA、RC五、RC6。 二、非對稱加密又稱共享密鑰加密,使用一對非對稱的密鑰,一把叫作私有密鑰,另外一把叫作公有密鑰;公鑰加密只能用私鑰來解密,私鑰加密只能用公鑰來解密。常見的公鑰加密算法有:RSA、ElGamal、揹包算法、Rabin(RSA的特例)、迪菲-赫爾曼密鑰交換協議中的公鑰加密算法、橢圓曲線加密算法)。
答: 業務分層、解耦,使代碼變得可維護; 有效的拆分、組織日益龐大的工程代碼,使工程目錄變得可維護; 便於各業務功能拆分、抽離,實現真正的功能複用; 業務隔離,跨團隊開發代碼控制和版本風險控制的實現; 模塊化對代碼的封裝性、合理性都有必定的要求,提高開發同窗的設計能力; 在維護好各級組件的狀況下,隨意組合知足不一樣客戶需求;(只須要將以前的多個業務組件模塊在新的主App中進行組裝便可快速迭代出下一個全新App)
答: 分層 基礎功能組件:按功能分庫,不涉及產品業務需求,跟庫Library相似,經過良好的接口拱上層業務組件調用;不寫入產品定製邏輯,經過擴展接口完成定製; 基礎UI組件:各個業務模塊依賴使用,但須要保持好定製擴展的設計 業務組件:業務功能間相對獨立,相互間沒有Model共享的依賴;業務之間的頁面調用只能經過UIBus進行跳轉;業務之間的邏輯Action調用只能經過服務提供; 中間件:target-action,url-block,protocol-class
答: App啓動時間能夠經過xcode提供的工具來度量,在Xcode的Product->Scheme-->Edit Scheme->Run->Auguments中,將環境變量DYLD_PRINT_STATISTICS設爲YES,優化需如下方面入手 dylib loading time 核心思想是減小dylibs的引用 合併現有的dylibs(最好是6個之內) 使用靜態庫 rebase/binding time 核心思想是減小DATA塊內的指針 減小Object C元數據量,減小Objc類數量,減小實例變量和函數(與面向對象設計思想衝突) 減小c++虛函數 多使用Swift結構體(推薦使用swift) ObjC setup time 核心思想同上,這部份內容基本上在上一階段優化事後就不會太過耗時 initializer time 使用initialize替代load方法 減小使用c/c++的attribute((constructor));推薦使用dispatch_once() pthread_once() std:once()等方法 推薦使用swift 不要在初始化中調用dlopen()方法,由於加載過程是單線程,無鎖,若是調用dlopen則會變成多線程,會開啓鎖的消耗,同時有可能死鎖 不要在初始化中建立線程
iOS App 啓動過程(二):從 exec() 到 main()
答: struct是值類型,class是引用類型。 值類型的變量直接包含它們的數據,對於值類型都有它們本身的數據副本,所以對一個變量操做不可能影響另外一個變量。 引用類型的變量存儲對他們的數據引用,所以後者稱爲對象,所以對一個變量操做可能影響另外一個變量所引用的對象。 兩者的本質區別:struct是深拷貝,拷貝的是內容;class是淺拷貝,拷貝的是指針。 property的初始化不一樣:class 在初始化時不能直接把 property 放在 默認的constructor 的參數裏,而是須要本身建立一個帶參數的constructor;而struct能夠,把屬性放在默認的constructor 的參數裏。 變量賦值方式不一樣:struct是值拷貝;class是引用拷貝。 immutable變量:swift的可變內容和不可變內容用var和let來甄別,若是初始爲let的變量再去修改會發生編譯錯誤。struct遵循這一特性;class不存在這樣的問題。 mutating function: struct 和 class 的差別是 struct 的 function 要去改變 property 的值的時候要加上 mutating,而 class 不用。 繼承: struct不能夠繼承,class能夠繼承。 struct比class更輕量:struct分配在棧中,class分配在堆中。
答: class 有如下功能,struct 是沒有的: class能夠繼承,子類能夠使用父類的特性和方法 類型轉換能夠在運行時檢查和解釋一個實例對象 class能夠用 deinit來釋放資源 一個類能夠被屢次引用 struct 優點: 結構較小,適用於複製操做,相比較一個class 實例被屢次引用,struct 更安全 無需擔憂內存泄露問題
答: Swift 既是面向對象的,又是函數式的編程語言。 說 Swift 是面向對象的語言,是由於 Swift 支持類的封裝、繼承、和多態,從這點上來看與 Java 這類純面向對象的語言幾乎毫無差異。 說 Swift 是函數式編程語言,是由於 Swift 支持 map, reduce, filter, flatmap 這類去除中間狀態、數學函數式的方法,更增強調運算結果而不是中間過程。
答: 泛型(generic)能夠使咱們在程序代碼中定義一些可變的部分,在運行的時候指定。使用泛型能夠最大限度地重用代碼、保護類型的安全以及提升性能。 泛型能夠將類型參數化,提升代碼複用率,減小代碼量。 例如 optional 中的 map、flatMap 、?? (泛型加逃逸閉包的方式,作三目運算)
答: ?爲optional的語法糖 optional<T> 是一個包含了nil 和普通類型的枚舉,確保使用者在變量爲nil的狀況下處理 !爲optional 強制解包的語法糖
答: 1.在 Swift 中,可選型是爲了表達一個變量爲空的狀況,當一個變量爲空,他的值就是 nil 在類型名稱後面加個問號? 來定義一個可選型 值類型或者引用類型均可以是可選型變量 2.Optional 是一個泛型枚舉 大體定義以下: enum Optional<Wrapped> { case none case some(Wrapped) } 除了使用 let someValue: Int? = nil 以外, 還能夠使用let optional1: Optional<Int> = nil 來定義
答: 一個函數若是能夠以某一個函數做爲參數, 或者是返回值, 那麼這個函數就稱之爲高階函數, 如 map, reduce, filter
答: 轉換爲值類型, 只有類會存在引用循環, 因此若是能不用類, 是能夠解引用循環的, delegate 使用 weak 屬性. 閉包中, 對有可能發生循環引用的對象, 使用 weak 或者 unowned, 修飾
答: static 定義的方法不能夠被子類繼承, class 則能夠 class AnotherClass { static func staticMethod(){} class func classMethod(){} } class ChildOfAnotherClass: AnotherClass { override class func classMethod(){} //override static func staticMethod(){}// error }
答: Swift 有五個級別的訪問控制權限,從高到底依次爲好比 Open, Public, Internal, File-private, Private。 他們遵循的基本原則是:高級別的變量不容許被定義爲低級別變量的成員變量。好比一個 private 的 class 中不能含有 public 的 String。反之,低級別的變量卻能夠定義在高級別的變量中。好比 public 的 class 中能夠含有 private 的 Int。 Open 具有最高的訪問權限。其修飾的類和方法能夠在任意 Module 中被訪問和重寫;它是 Swift 3 中新添加的訪問權限。 Public 的權限僅次於 Open。與 Open 惟一的區別在於它修飾的對象能夠在任意 Module 中被訪問,但不能重寫。 Internal 是默認的權限。它表示只能在當前定義的 Module 中訪問和重寫,它能夠被一個 Module 中的多個文件訪問,但不能夠被其餘的 Module 中被訪問。 File-private 也是 Swift 3 新添加的權限。其被修飾的對象只能在當前文件中被使用。例如它能夠被一個文件中的 class,extension,struct 共同使用。 Private 是最低的訪問權限。它的對象只能在定義的做用域內使用。離開了這個做用域,即便是同一個文件中的其餘做用域,也沒法訪問。
答: guard let name = self.text else { return } defer的用法是,這條語句並不會立刻執行,而是被推入棧中,直到函數結束時纔再次被調用。 defer { //函數結束才調用 }
答: Swift 的內存管理機制同OC一致,都是ARC管理機制; Strong,和 Weak用法同OC同樣 Unowned(無主引用), 不會產生強引用,實例銷燬後仍然存儲着實例的內存地址(相似於OC中的unsafe_unretained), 試圖在實例銷燬後訪問無主引用,會產生運行時錯誤(野指針)
答: 值類型(好比:struct),在複製時,複製對象與原對象實際上在內存中指向同一個對象,當且僅當修改複製的對象時,纔會在內存中建立一個新的對象, 爲了提高性能,Struct, String、Array、Dictionary、Set採起了Copy On Write的技術 好比僅當有「寫」操做時,纔會真正執行拷貝操做 對於標準庫值類型的賦值操做,Swift 能確保最佳性能,全部不必爲了保證最佳性能來避免賦值
答: 屬性觀察是指在當前類型內對特性屬性進行監測,並做出響應,屬性觀察是 swift 中的特性,具備2種, willset 和 didset var title: String { willSet { print("willSet", newValue) } didSet { print("didSet", oldValue, title) } } willSet會傳遞新值,默認叫newValue didSet會傳遞舊值,默認叫oldValue 在初始化器中設置屬性值不會觸發willSet和didSet
答: 值類型和引用類型相比,最大優點能夠高效的使用內存,值類型在棧上操做,引用類型在堆上操做,棧上操做僅僅是單個指針的移動,而堆上操做牽涉到合併,位移,重連接,Swift 這樣設計減小了堆上內存分配和回收次數,使用 copy-on-write將值傳遞與複製開銷降到最低
答: 1.在協議和方法前面添加 @objc,而後在方法前面添加 optional關鍵字,改方式其實是將協議轉爲了OC的方式 @objc protocol someProtocol { @objc optional func test() } 2.使用擴展(extension),來規定可選方法,在 swift 中,協議擴展能夠定義部分方法的默認實現 protocol someProtocol { func test() } extension someProtocol{ func test() { print("test") } }
答: swift 的初始化方法,更加嚴格和準確, swift初始化方法須要保證全部的非optional的成員變量都完成初始化, 同時 swfit 新增了convenience和 required兩個修飾初始化器的關鍵字 convenience只提供一種方便的初始化器,必須經過一個指定初始化器來完成初始化 required是強制子類重寫父類中所修飾的初始化方法
答: Swift 和OC中的 protocol相同點在於: 二者均可以被用做代理; 不一樣點: Swift中的 protocol還能夠對接口進行抽象,能夠實現面向協議,從而大大提升編程效率,Swift中的protocol能夠用於值類型,結構體,枚舉;
答: 自省在OC中就是判斷某一對象是否屬於某一個類的操做,有如下2中方式 [obj iskinOfClass:[SomeClass class]] [obj isMemberOfClass:[SomeClass class]] 在 Swift 中因爲不少 class 並不是繼承自 NSObject, 故而 Swift 使用 is 來判斷是否屬於某一類型, is 不只能夠做用於class, 仍是做用於enum和struct
答: 函數重載是指: 函數名稱相同,函數的參數個數不一樣, 或者參數類型不一樣,或參數標籤不一樣, 返回值類型與函數重載無關 swift 支持函數重載
答: 1.關聯值--有時會將枚舉的成員值跟其餘類型的變量關聯存儲在一塊兒,會很是有用 // 關聯值 enum Date { case digit(year: Int, month: Int, day: Int) case string(String) } 2.原始值--枚舉成員能夠使用相同類型的默認值預先關聯,這個默認值叫作:原始值 // 原始值 enum Grade: String { case perfect = "A" case great = "B" case good = "C" case bad = "D" }
答: 1. { (參數列表) -> 返回值類型 in 函數體代碼 }
答: 2.將一個很長的閉包表達式做爲函數的最後一個實參 使用尾隨閉包能夠加強函數的可讀性 尾隨閉包是一個被書寫在函數調用括號外面(後面)的閉包表達式 // fn 就是一個尾隨閉包參數 func exec(v1: Int, v2: Int, fn: (Int, Int) -> Int) { print(fn(v1, v2)) } // 調用 exec(v1: 10, v2: 20) { $0 + $1 }
答: 3.當閉包做爲一個實際參數傳遞給一個函數或者變量的時候,咱們就說這個閉包逃逸了,能夠在形式參數前寫 @escaping 來明確閉包是容許逃逸的。 非逃逸閉包、逃逸閉包,通常都是當作參數傳遞給函數 非逃逸閉包:閉包調用發生在函數結束前,閉包調用在函數做用域內 逃逸閉包:閉包有可能在函數結束後調用,閉包調用逃離了函數的做用域,須要經過@escaping聲明 // 定義一個數組用於存儲閉包類型 var completionHandlers: [() -> Void] = [] // 在方法中將閉包當作實際參數,存儲到外部變量中 func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) { completionHandlers.append(completionHandler) }
答: 4.自動閉包是一種自動建立的用來把做爲實際參數傳遞給函數的表達式打包的閉包。它不接受任何實際參數,而且當它被調用時,它會返回內部打包的表達式的值。這個語法的好處在於經過寫普通表達式代替顯式閉包而使你省略包圍函數形式參數的括號。 func getFirstPositive(_ v1: Int, _ v2: @autoclosure () -> Int) -> Int? { return v1 > 0 ? v1 : v2() } getFirstPositive(10, 20) 爲了不與指望衝突,使用了@autoclosure的地方最好明確註釋清楚:這個值會被推遲執行 @autoclosure 會自動將 20 封裝成閉包 { 20 } @autoclosure 只支持 () -> T 格式的參數 @autoclosure 並不是只支持最後1個參數 有@autoclosure、無@autoclosure,構成了函數重載 若是你想要自動閉包容許逃逸,就同時使用 @autoclosure 和 @escaping 標誌。
答: Swift中跟實例對象相關的屬性能夠分爲2大類 存儲屬性(Stored Property) 相似於成員變量這個概念 存儲在實例對象的內存中 結構體、類能夠定義存儲屬性 枚舉不能夠定義存儲屬性 計算屬性(Computed Property) 本質就是方法(函數) 不佔用實例對象的內存 枚舉、結構體、類均可以定義計算屬性 struct Circle { // 存儲屬性 var radius: Double // 計算屬性 var diameter: Double { set { radius = newValue / 2 } get { return radius * 2 } } }
答: 使用lazy能夠定義一個延遲存儲屬性,在第一次用到屬性的時候纔會進行初始化(相似OC中的懶加載) lazy屬性必須是var,不能是let let必須在實例對象的初始化方法完成以前就擁有值 若是多條線程同時第一次訪問lazy屬性 沒法保證屬性只被初始化1次 class PhotoView { // 延遲存儲屬性 lazy var image: Image = { let url = "https://...x.png" let data = Data(url: url) return Image(data: data) }() }
答: 能夠經過類型屬性+let+private 來寫單例; 代碼以下以下: public class FileManager { public static let shared = { // .... // .... return FileManager() }() private init() { } }
答: 使用subscript能夠給任意類型(枚舉、結構體、類)增長下標功能,有些地方也翻譯爲:下標腳本 subscript的語法相似於實例方法、計算屬性,本質就是方法(函數) 使用以下: class Point { var x = 0.0, y = 0.0 subscript(index: Int) -> Double { set { if index == 0 { x = newValue } else if index == 1 { y = newValue } } get { if index == 0 { return x } else if index == 1 { return y } return 0 } } } var p = Point() // 下標賦值 p[0] = 11.1 p[1] = 22.2 // 下標訪問 print(p.x) // 11.1 print(p.y) // 22.2
答: 類、結構體、枚舉均可以定義初始化器 類有2種初始化器: 指定初始化器(designated initializer)、便捷初始化器(convenience initializer) // 指定初始化器 init(parameters) { statements } // 便捷初始化器 convenience init(parameters) { statements } 規則: 每一個類至少有一個指定初始化器,指定初始化器是類的主要初始化器 默認初始化器老是類的指定初始化器 類偏向於少許指定初始化器,一個類一般只有一個指定初始化器 初始化器的相互調用規則 指定初始化器必須從它的直系父類調用指定初始化器 便捷初始化器必須從相同的類裏調用另外一個初始化器 便捷初始化器最終必須調用一個指定初始化器
答: 可選鏈是一個調用和查詢可選屬性、方法和下標的過程,它可能爲 nil 。若是可選項包含值,屬性、方法或者下標的調用成功;若是可選項是 nil ,屬性、方法或者下標的調用會返回 nil 。多個查詢能夠連接在一塊兒,若是鏈中任何一個節點是 nil ,那麼整個鏈就會得體地失敗。 多個?能夠連接在一塊兒 若是鏈中任何一個節點是nil,那麼整個鏈就會調用失敗
答: 類、結構體、枚舉能夠爲現有的運算符提供自定義的實現,這個操做叫作:運算符重載 struct Point { var x: Int var y: Int // 重載運算符 static func + (p1: Point, p2: Point) -> Point { return Point(x: p1.x + p2.x, y: p1.y + p2.y) } } var p1 = Point(x: 10, y: 10) var p2 = Point(x: 20, y: 20) var p3 = p1 + p2
收錄:原文地址