1. 進程和線程 1.1 進程 進程:正在運行的應用程式叫進程 進程之間都是獨立的,運行在專用且受保護的記憶體空間中 兩個進程之間無法通訊 通俗的理解,手機上同時開啟了兩個App。這兩個App肯定是在不同的進程中的。所以這兩個App之間是獨立的,記憶體中的數據不能互相竄來竄去,兩個App之間也沒有辦法進 ...
1. 進程和線程
1.1 進程
- 進程:正在運行的應用程式叫進程
- 進程之間都是獨立的,運行在專用且受保護的記憶體空間中
- 兩個進程之間無法通訊
通俗的理解,手機上同時開啟了兩個App。這兩個App肯定是在不同的進程中的。所以這兩個App之間是獨立的,記憶體中的數據不能互相竄來竄去,兩個App之間也沒有辦法進行通訊。
兩個App之間沒有辦法進行通訊?我說的是正常情況下。當然還是有不正常情況啊,例如使用iOS提供的極少數的幾種進程間通訊的工具。
1.2 線程
- 線程:進程想要執行任務,必須要有線程,每個進程至少有一條線程。
- 線程就是用來幹活的。
- 程式一啟動,就會啟動進程。進程預設開啟一條線程。
幹活的線程?對啊,活太多,或者不想彼此互相等著浪費時間,當然可以找幾個人同時幹了。
例如在項目上,產品經理需求都沒有完全寫完,也不妨礙先設計一個大概的數據框架啊。例如需求沒有完全定下來,不妨礙UI童鞋提前設計啊,大不了再改嘛~ HOHO~怎麼聽上去都像是黑話。
1.3 多線程
-
單核CPU同一時間,CPU只能處理1個線程,只有1個線程在執行任務。
-
多線程的同時執行 : 其實是CPU在多條線程之間快速切換(調度任務)。
-
如果CPU調度線程的速度足夠快,就造成了多線程同時執行的假象
-
如果線程非常多,CPU會在多條線程之間不斷的調度任務,結果就是消耗了大量的CPU資源,效率下降:
- 每個線程調度的頻率會降低
- 線程的執行效率會下降
iPhone手機是幾核的?
A7 : iPhone 5S , 雙核
A8: iPhone 6、iPhone 6 Plus,雙核
A9:iPhone 6S、iPhone 6S Plus,雙核
A10:iPhone 7、iPhone 7 Plus,2+2核
1.4 iOS中的多線程
剛纔說了,iOS App一旦運行,預設就會開啟一條線程。這條線程,我們通常稱作為“主線程”
主線程的作用:
- 刷新UI
- 處理UI事件,例如點擊、滾動、拖拽。
如果主線程的操作太多、太耗時,就會造成App卡頓現象嚴重。所以,通常我們都會把耗時的操作放在子線程中進行,獲取到結果之後,回到主線程去刷新UI。
2. Operation
我們來看看基礎使用:
1 // 最基本的使用Operation 2 private func basicOperation() { 3 // 第一步:創建Operation 4 let op = Operation.init() 5 // 第二步:把要執行的代碼放入operation中 6 op.completionBlock = { 7 8 print(#function,#line,Thread.current) 9 } 10 // 第三步:創建OperationQueue 11 let opQueue = OperationQueue.init() 12 // 第四步:把Operation加入到線程中 13 opQueue.addOperation(op) 14 }
使用BlockOperation創建operatoin,並直接運行。咱們看看會在哪條線程執行。
1 //創建一個簡單的BlockOperation 2 private func CreatBasicBlockOperation() { 3 //使用BlockOperation創建operation 4 let operation = BlockOperation.init { 5 //列印,看看在哪個線程中 6 7 print(#function,#line,Thread.current) 8 } 9 10 //直接運行operation,看看運行在哪個線程中 11 operation.start() 12 }
列印一下看看運行的結果:
這就是我們說,創建完Operation如果直接運行,就會在當前線程執行。也就是說,如果實在主線程創建並且start的,那就會在主線程執行;如果是在子線程創建並且start的,那就會在子線程執行。
3. Basic Demo
在這個例子裡面,需求如下:
1,在子線程載入每個圖片的數據
2,圖片數據下載完畢之後,顯示出來
3,開始請求數據的時候,讓指示符開始轉動
4,所有圖片下載完畢後,指示符停止轉動
3. Basic Demo
在這個例子裡面,需求如下:
1,在子線程載入每個圖片的數據
2,圖片數據下載完畢之後,顯示出來
3,開始請求數據的時候,讓指示符開始轉動
4,所有圖片下載完畢後,指示符停止轉動
3.2 Swift中的do catch
這個是Swift和OC不一樣的地方。Swift中出現了可選值這麼一個東西,這個不是這次的重點。想深入瞭解的童鞋可以參看這篇:?和 !的使用
Swift 里有四種方法來處理錯誤:
- 把錯誤從函數傳遞到調用函數的代碼里
- 使用一個 do-catch 語句來處理錯誤
- 把錯誤當做一個可選值來處理
- 斷言這個錯誤不會發生
因為Demo裡面用到了do catch,那咱們就只說do catch.
在Swift的標準try中,是要配合do catch的。
下麵是do-catch語句的一般格式,如果do分句內的代碼拋出了一個錯誤,它就被catch分句捕獲,並判斷由哪個分句來處理此錯誤。
1 do { 2 try expression 3 statements 4 } catch pattern 1 { 5 statements 6 } catch pattern 2 where condition { 7 statements 8 }
3.3 優先順序
在思維導圖裡面出現了兩個優先順序。一個是屬於Operation 的,一個是屬於OperationQueue的。那咱們分看看看這兩個都是啥。
3.3.1 Operation中的優先順序
Operation裡面的這個叫做qualityOfService
1 public enum QualityOfService : Int { 2 case userInteractive 3 case userInitiated 4 case utility 5 case background 6 case `default` 7 }
1 userInteractive:最高優先順序,用於用戶交互事件 2 userInitiated :次高優先順序,用於用戶需要馬上執行的事件 3 utility:普通優先順序,用於普通任務 4 background:最低優先順序,用於不重要的任務 5 default:預設優先順序,主線程和沒有設置優先順序的線程都預設為這個優先順序
3.3.2 operationQueue 裡面的優先順序
operationQueue中表示優先順序的屬性是queuePriority
,表示操作在隊列中的優先順序。
1 public enum QueuePriority : Int { 2 case veryLow 3 case low 4 case normal 5 case high 6 case veryHigh 7 }
這些優先順序都是相對的,並不是是說必須要執行完最高的才執行次重要的。這裡面並沒有一個特別嚴格順序。只是在分配資源上有傾向性。如果隊列需要有嚴格的執行順序,還是要添加依賴關係的,這個是我們下一篇文章要分享的內容。
4. 案例實現
Operation 基本應用及優先順序小案例。
實現後效果如下:
這個Demo裡面,用了兩種方法創建Operation。
在startBasicDemo
,使用的是閉包創建Operation的方式。在startPriorityDemo
裡面使用的是自定義的構造方法創建的Operation,然後把任務數組加入到線程中。
代碼:
1 // Operation 案例 2 fileprivate func startBasicDemo() 3 { 4 let operationQueue = OperationQueue.init() 5 operationQueue.maxConcurrentOperationCount = 3 6 7 let activityIndicator = UIActivityIndicatorView() 8 activityIndicator.startAnimating() 9 10 let a = UIImageView(frame: CGRect(x: 0, y: 64, width: 414, height: 100)) 11 self.view.addSubview(a) 12 let b = UIImageView(frame: CGRect(x: 0, y: 164, width: 414, height: 100)) 13 self.view.addSubview(b) 14 let c = UIImageView(frame: CGRect(x: 0, y: 264, width: 414, height: 100)) 15 self.view.addSubview(c) 16 let d = UIImageView(frame: CGRect(x: 0, y: 364, width: 414, height: 100)) 17 self.view.addSubview(d) 18 19 20 let imageViews = [a, b, c, d] 21 for imageView in imageViews { 22 if let url = URL(string: "https://placebeard.it/355/140") 23 { 24 do { 25 let image = UIImage(data:try Data(contentsOf: url)) 26 27 DispatchQueue.main.async 28 { 29 imageView.image = image 30 } 31 }catch 32 { 33 print(error) 34 } 35 } 36 } 37 // global queue 38 DispatchQueue.global().async 39 { 40 [weak self] in 41 // 等待所有操作都完成了,回到主線程停止刷新器。 42 // wait Until All Operations are finished, then stop animation of activity indicator 43 operationQueue.waitUntilAllOperationsAreFinished() 44 DispatchQueue.main.async 45 { 46 activityIndicator.stopAnimating() 47 } 48 49 } 50 }View Code
設置了優先順序的Demo:
1 fileprivate func startPriorityDemo() { 2 operationQueue.maxConcurrentOperationCount = 2 3 activityIndicator.startAnimating() 4 5 var operations = [Operation]() 6 for (index, imageView) in (imageViews?.enumerated())! { 7 if let url = URL(string: "https://placebeard.it/355/140") { 8 // 使用構造方法創建operation 9 let operation = convenienceOperation(setImageView: imageView, withURL: url) 10 11 //根據索引設置優先順序 12 switch index { 13 case 0: 14 operation.queuePriority = .veryHigh 15 case 1: 16 operation.queuePriority = .high 17 case 2: 18 operation.queuePriority = .normal 19 case 3: 20 operation.queuePriority = .low 21 default: 22 operation.queuePriority = .veryLow 23 } 24 25 operations.append(operation) 26 } 27 } 28 29 // 把任務數組加入到線程中 30 DispatchQueue.global().async { 31 [weak self] in 32 self?.operationQueue.addOperations(operations, waitUntilFinished: true) 33 DispatchQueue.main.async { 34 self?.activityIndicator.stopAnimating() 35 } 36 } 37 38 }View Code