隨着iPhone X的來到,iOS11的發佈,Swift語言也更新到了第4個版本。在Swift4中,不管是代碼風格仍是編程理念都更進一步的融合了許多現代編程的思想。對於熟悉傳統語言的開發者來講(尤爲是Objective-C、Java和C++),可能會感受這些特性並無多大的價值反而很是不習慣,可是咱們依然能夠茶餘飯後(沒事幹的時候),一窺Swift4語言的玩法,體驗一下Swift語言的設計思想和編碼風格。編程
獨佔訪問權限是Swift4中引入的一大新特性。然而大部分人都將這一特性誤解了,若是你在百度上搜索 swift4 exclusive access to memory相關關鍵字,大部分博客或總結都會說這是一種編譯器的編譯時特性,能夠在例如數組越界時、對遍歷中的數組進行刪添元素時產生編譯異常。其實並不是如此,獨佔內存訪問權限特性是一種編譯時和運行時的安全特性,其和數組也沒有任何關係,當兩個變量訪問同一塊內存時,會產生獨佔內存訪問限制。swift
首先,在Swift中對內存的訪問有讀訪問與寫訪問兩種,例如:數組
//讀訪問 var name = "jaki" //寫訪問 print(name)
在Swift4之前,程序對內存的讀寫訪問並無嚴格的控制,若是你在讀內存時有寫內存操做,或者寫內存時有讀操做並不會產生什麼異常(固然,你本身要清楚讀寫後變量的值,以避免產生邏輯歧義)。Swift4中則引入了獨佔內存訪問權限的特性,若是複合以下3個條件,則程序會產生讀寫權限衝突:安全
1.至少有一個變量在使用寫權限。閉包
2.變量訪問的是同一個內存地址。app
3.持續時間有重疊。編程語言
在開發中,可能會產生讀寫權限衝突的狀況有3種:函數
var stepSize = 1 func increment(_ number: inout Int) { number += stepSize//crash } increment(&stepSize)
上面的代碼在Swift3中沒有任何問題,在Swift4環境中運行則會直接crash。在函數中,inout參數從聲明開始到函數的結束,這個變量始終開啓着寫權限,對應上面代碼,number參數開啓這寫權限,stepSize則進行了讀訪問,如此則知足上面的權限衝突規則,會產生讀寫衝突。一樣,若是對兩個inout參數訪問同一個內存地址,也會產生讀寫權限衝突,例如:學習
var stepSize = 1 func increment(_ number: inout Int,_ number2: inout Int) { var a = number+number2 } increment(&stepSize,&stepSize)
Swift語言中的結構體也是一種值類型,所以其也存在讀寫衝突的場景,例如以下代碼:優化
struct Player { var name: String var health: Int var energy: Int let maxHealth = 10 mutating func shareHealth(_ player:inout Player) { health = player.health } } var play = Player(name: "jaki", health: 10, energy: 10) play.shareHealth(&play)//產生錯誤
上面shareHealth函數中使用到的health是對self自身的讀訪問,而inout參數是寫訪問,會產生讀寫權限衝突。
在Siwft語言中,像結構體,枚舉和元組中都有屬性的概念。因爲其都是值類型,在對不一樣的屬性進行訪問時也會產生衝突,例如:
class Demo { var playerInformation = (health: 10, energy: 20) func balance(_ p1 :inout Int,_ p2 :inout Int) { } func test() { self.balance(&playerInformation.health, &playerInformation.energy)//crash } } let demo = Demo() demo.test()
看到這裏你必定以爲這太嚴格了,對不一樣屬性的訪問也會產生讀寫衝突。實際上,在開發中大部分的這種訪問都會被認爲是安全的,你須要知足下面3個條件:
1.你訪問的是存儲屬性而不是計算屬性。
2.你訪問的是結構體局部變量(函數中的變量)而不是全局變量。
3.你的結構體不被閉包捕獲,或者只是被非逃逸的閉包捕獲。
將上面的playerInformation變量修改爲局部的,程序就能夠正常運行了:
class Demo { func balance(_ p1 :inout Int,_ p2 :inout Int) { } func test() { var playerInformation = (health: 10, energy: 20) self.balance(&playerInformation.health, &playerInformation.energy) } } let demo = Demo() demo.test()
其實,Swfit4中的獨佔內存訪問權限特性通常狀況下咱們都不會使用到,可是瞭解一下仍是頗有必要,Swift是一種安全性極高的語言,也是其設計的核心思想與方向,例如類構造方法的安全性檢查特性,變量類型的安全限制特性等等都是將開發者編寫代碼的安全交給語言特性來負責,而不是開發者的經驗。這讓初學者能夠更少的出錯,語言運行時的不可控因素更少。
associatedtype是Swift協議中一個頗有用的關鍵字,其也是Swift泛型編程思想的一種實現。在Swift3中,associatedtype從語法上是不能追加where子句的,Swift4加強了associatedtype的功能,其可使用where子句進行更加精準的約束,看下面的代碼:
//容器協議 protocol Container { //約束item 泛型爲 Int類型 associatedtype Item where Item == Int func append(_ item: Item) var count: Int { get } subscript(i: Int) -> Item { get } } class MyIntArray: Container { //這個地方必須指定爲Int不然會報錯 typealias Item = Int func append(_ item: Int) { self.innerArray.append(item) } var count: Int{ get{ return self.innerArray.count } } subscript(i: Int) -> Int { return self.innerArray[i] } var innerArray = [Int]() }
在Swift4之前,字符串只能建立單行的,Swift4中引入了字面量建立多行文本的語法,例如:
var multiLineString = """ abcd jaki 24 """ print(multiLineString)
這種方式能夠大大減小在建立字符串時人爲添加換行符。
關於String操做的相關API,在Swift4中也有許多優化,例如字符串的下標操做與字符操做一直是Swift語言的硬傷,使用起來十分麻煩,在Swift4中都進行了優化。取字符串的子串的方式也更加規範。
Swift語言中的區間運算符使用起來十分方便,例如在Swift3中,咱們若要遍歷數組的範圍,可使用以下的代碼:
//Swift3代碼 let array = ["1","2","3"] for item in array[0..<array.count]{ print(item) }
Swift3中的...運算符只是做爲閉區間運算符使用,在Swift4中,能夠用它來取集合類型的邊界,如字符串,數組等,看以下代碼:
let array = ["1","2","3"] for item in array[0...]{ print(item) }
subscript方法能夠爲Swift中的類添加下標訪問的支持,在Swift4中,subscript方法更增強大,其不僅能夠支持泛型,並且能夠支持where子句進行協議中關聯類型的約束,示例以下:
//下標協議 protocol Sub { associatedtype T func getIndex()->T } //實現下標協議的一種下標類 class Index:Sub { init(_ index:Int) { self.index = index } var index:Int func getIndex() -> Int { return self.index } } class MyArray { var array = Array<Int>() func push(item:Int) { self.array.append(item) } //泛型 並進行約束 subscript<T:Sub>(i:T)->Int where T.T == Int { return self.array[i.getIndex()] } } var a = MyArray() a.push(item: 1) print(a[Index(0)])
Swift在對變量類型進行界定時,是支持使用協議的,例如,在Swift3中,咱們能夠編寫以下的代碼:
//swift3 protocol People { var name:String{set get} var age:Int{set get} } protocol Teach { func teachSwift() } class Teacher: People,Teach { var name: String = "jaki" var age: Int = 25 func teachSwift() { print("teaching...") } } func printTeacher(p:Teacher) { print(p.name,p.age) p.teachSwift() }
上面的代碼中,printTeacher方法裏使用Teacher類對參數進行的界定,實際上這種作法並很差,Teacher類知識Teach協議與People協議的一種混合實現,在定義方法參數時,應該使用協議來進行參數的界定,但是Teacher類同時實現了兩個協議,這在Swift3版本中是沒法解決的問題,在Swift4中你則能夠這樣寫:
protocol People { var name:String{set get} var age:Int{set get} } protocol Teach { func teachSwift() } class Teacher: People,Teach { var name: String = "jaki" var age: Int = 25 func teachSwift() { print("teaching...") } } func printTeacher(p:Teach&People) { print(p.name,p.age) p.teachSwift() }
&複合能夠對協議進行混合,更加貼近面向協議的編程方式。
從Swift語言第1個版本發佈到Swift3和Swift3.2進行了語言內容和風格的大改,Swift4中進行的改動實際並不大並且大可能是你開發中可能並用不到的特性。隨着Swift語言的成長,這種語言的設計風格是與其餘傳統語言有着本質的區別,我我的感悟,Swift語言以下的特色確實值得咱們學習與思考:
所謂安全性,實際上就是語言是否容易出錯,再通俗一些,便是一種編程語言是依賴其自身特性防止其出錯仍是依賴開發者經驗防止其出錯。我記得在初學JavaScript時感受十分苦惱,由於JavaScript是變量弱類型的,而且其隱式轉換十分危險(雖然代碼編寫起來暢快無比)。在Swift中,則基本不會出現類型不匹配,類型被隱式轉換了等問題。固然,換句話說,這也使得編程者必須遵照更多的規則(或者說寫更多的代碼),雖然各有利弊,但對初學者來講,Swift明顯要友好不少。
Swift語言安全性極高表如今以下幾點:
1.用let和var來分別聲明常量和變量,let聲明的量值不可改,從邏輯上保證變量安全。
2.變量類型必須明確(不少時候你沒指定是由於編譯器的推斷功能),從類型上保證安全。
3.閉包分爲逃逸和非逃逸,從邏輯上保證閉包使用的安全。
4.溢出運算符與算術運算符分開,從代碼上保證安全。
5.類的初始化檢查策略,從類的定義上保證安全。
6.刪除++與--運算符,刪除常規for循環,從習慣上保證安全。
Swift語言的靈活性很是有現代編程語言的特色,有其是其對泛型的支持,是的面向協議的編程方式在Swift語言上能夠暢行無阻。靈活性表如今以下幾點:
1.強大的泛型編程方式,協議關聯類型等。
2.where子句能夠精準的進行泛型約束。
3.Optioal類型和可失敗構造方法的支持。
4.Any與AntObject類型的支持。
5.強大的枚舉和結構體。
6.遞歸枚舉的支持。
7.支持重載與自定義運算符。
編碼體驗這點並不徹底依賴與Swift語法,也多有編譯器的功勞。
1.支持字符串內嵌變量來構建字符串。
2.支持後置閉包的寫法。
3.元組類型的支持。
4.支持默認隱式拆包類型。
5.支持區間運算符。
6.函數份內外兩種參數名(外參數名能夠省略)。
7.語法上支持便利構造方法。
8.語法層面支持的懶加載。
上面只是列出了一些特性,Swift語言中有意思的地方多的舉不勝舉,若是你有意更深刻的瞭解它,你能夠搜索清華大學出版社的《Swift從入門到精通》一書,其中是我對Swift3進行的全面講解,也包含iOS開發的部分知識和實戰,你也能夠直接經過QQ316045346聯繫我本人進行交流與互相學習。最後,一語以總結Swift語言:一門十分強大而且十分易入門的現代編程語言,只要你掌握了全部語法規則,想出錯很難!