首發:cc loggit
又是一篇遲來的文章。主要是譯自: What’s new in Swift 5.1。github
閱讀以前能夠查看我以前總結的Swift 3 到Swift 5的新特性。swift
Swift5.1支持了SwiftUI, 能夠看出本次的更新更多了是爲了更好的「聲明」UI。api
struct
初始化方法swift早期版本中支持了自動生成struct
的初始化方法數組
struct User {
var name: String
var loginCount: Int = 0
}
let piper = User(name: "Piper Chapman", loginCount: 0)
複製代碼
Swift 5.1改進了初始化方法,若是屬性有了初始值,初始化的時候能夠省略。app
let gloria = User(name: "Gloria Mendoza", loginCount: 0)
let suzanne = User(name: "Suzanne Warren")
複製代碼
這點實際上很好理解,Swift 5.1中單行返回函數能夠省略return
關鍵詞。dom
let doubled1 = [1, 2, 3].map { $0 * 2 }
let doubled2 = [1, 2, 3].map { return $0 * 2 }
複製代碼
上面兩個是等價的。ide
實際上下面這麼寫也同樣函數
func double(_ number: Int) -> Int {
number * 2
}
複製代碼
Self
Swift 5.1中擴展了Self
的使用,在class
,struct
, enmu
中使用時候能夠指向這個類型。這點在動態類型中頗有用,特別是某些類型須要在運行時才能決定時候。ui
例如,下面場景中
class NetworkManager {
class var maximumActiveRequests: Int {
return 4
}
func printDebugData() {
print("Maximum network requests: \(NetworkManager.maximumActiveRequests).")
}
}
複製代碼
上面聲明瞭靜態的maximumActiveRequests
屬性,而且使用實例方法printDebugData
來打印這個屬性。如今這樣工做的挺好。可是若是NetworkManager
有子類,狀況就不同了
class ThrottledNetworkManager: NetworkManager {
override class var maximumActiveRequests: Int {
return 1
}
}
複製代碼
子類改變了maximumActiveRequests
,可是若是咱們調用printDebugData()
,它只會打印父類的屬性。
let manager = ThrottledNetworkManager()
manager.printDebugData()
複製代碼
它理應打印1而不是4,這就是Self
要解決的問題。咱們改寫printDebugData()
用Self
(大寫S)來指向當前的類型:
class ImprovedNetworkManager {
class var maximumActiveRequests: Int {
return 4
}
func printDebugData() {
print("Maximum network requests: \(Self.maximumActiveRequests).")
}
}
複製代碼
Self
在協議中仍然像早期Swift中同樣工做。
提案SE-0244爲Swift 5.1帶來了不透明類型:知曉某個對象的能力可是不須要知道這個對象的具體類型。
初看之下,它很像協議protocol,但不透明返回類型走的比這更遠,它能夠和associated type使用。
protocol Fighter { }
struct XWing: Fighter { }
func launchFighter() -> Fighter {
return XWing()
}
let red5 = launchFighter()
複製代碼
上面launchFighter
返回某種Fighter,可是不知道具體那個類型,它能夠是XWing,或者咱們新增一個strunct YWing:Fighter {}
。
這樣寫有個問題,若是你想知道red5
具體是那種類型的飛機呢?你可能想到方案是,讓Fighter
遵循Equatable
協議,而後咱們就可使用==
方法。可是實際使用的時候會發現下面的報錯:
這是由於Equatable
有一個Self
的associated type。 有associated type的協議看起來像類型,可是它們實際上不是,它們實際上表示的是「遵循此協議的任意類型」
Swift 5.1中的不透明返回類型,能夠將這種協議做作一個普通的類型來使用。只須要在協議名前增長some
關鍵詞。
func launchOpaqueFighter() -> some Fighter {
return XWing()
}
複製代碼
不透明返回類型(Opaque Return types)能夠帶來的好處有:
Self
或者associated type
,由於編譯器會明確知道內部具體的類型。Static
和class
類下標(subscripts)靜態Static
類型的屬性和方法,可用來在類型全部實例間共享某些值。例如你能夠在你的App中集中管理配置。
public enum OldSettings {
private static var values = [String: String]()
static func get(_ name: String) -> String? {
return values[name]
}
static func set(_ name: String, to newValue: String?) {
print("Adjusting \(name) to \(newValue ?? "nil")")
values[name] = newValue
}
}
OldSettings.set("Captain", to: "Gary")
OldSettings.set("Friend", to: "Mooncake")
print(OldSettings.get("Captain") ?? "Unknown")
複製代碼
字典包裹在類型中可讓更當心的控制它,而且使用沒有case
的enum
,也就讓你無法實例化Settings
。
在Swift 5.1中你可使用static subscript
。
public enum NewSettings {
private static var values = [String: String]()
public static subscript(_ name: String) -> String? {
get {
return values[name]
}
set {
print("Adjusting \(name) to \(newValue ?? "nil")")
values[name] = newValue
}
}
}
NewSettings["Captain"] = "Gary"
NewSettings["Friend"] = "Mooncake"
print(NewSettings["Captain"] ?? "Unknown")
複製代碼
static
或者class
的下標了。static
或者class
都是靜態的前綴,區別是,class允許子類型覆蓋
none
Swift的可選(optional)是現實是經過有兩個值some
和none
的enum來實現的。這樣就和咱們本身代碼中有none
case的enum包裹在optional時候產生混淆。
enum BorderStyle {
case none
case solid(thickness: Int)
}
複製代碼
若是在非可選值中使用
let border1: BorderStyle = .none
print(border1)
複製代碼
上面會打印none
。 可是若是咱們在使用在可選值中,咱們不知道什麼邊框時候,Swift 5.1以前的版本會有問題。
let border2: BorderStyle? = .none
print(border2)
複製代碼
會打印nil
, 由於swfit會默認將.none
推導爲可選是空值,而不是BorderStyle.none
。
Swift 5.1中會對此作出警告:「Assuming you mean 'Optional.none'; did you mean 'BorderStyle.none' instead?」,提示你做修復。
Swift一直可以在switch case聰明的處理可選(optional)和非可選的(non-optional)的string,和integer。到了Swift 5.1 也支持enum了。
enum BuildStatus {
case starting
case inProgress
case complete
}
let status: BuildStatus? = .inProgress
switch status {
case .inProgress:
print("Build is starting…")
case .complete:
print("Build is complete!")
default:
print("Some other build status")
}
複製代碼
如今可以正常的打印,」Build is starting…「了。
Swift 5.1 爲可排序集合(內含Equatable
元素)提供了一個difference(from:)
方法來計算兩個集合,那個元素被移除了,新增了哪一個……
此方法被標註爲,swift 5.1才@available
,所以使用須要if swift(>=5.1)
來判斷。
let operatingSystems = ["Yosemite",
"El Capitan",
"Sierra",
"High Sierra",
"Mojave",
"Catalina"]
var answers = ["Mojave",
"High Sierra",
"Sierra",
"El Capitan",
"Yosemite",
"Mavericks"]
#if swift(>=5.1)
let differences = operatingSystems.difference(from: answers)
let sameAnswers = answers.applying(differences) ?? []
// 1
for change in differences.inferringMoves() {
switch change {
// 2
case .insert(let offset, let element, let associatedWith):
answers.insert(element, at: offset)
guard let associatedWith = associatedWith else {
print("\(element) inserted at position \(offset + 1).")
break
}
print("""
\(element) moved from position \(associatedWith + 1) to position
\(offset + 1).
""")
// 3
case .remove(let offset, let element, let associatedWith):
answers.remove(at: offset)
guard let associatedWith = associatedWith else {
print("\(element) removed from position \(offset + 1).")
break
}
print("""
\(element) removed from position \(offset + 1) because it should be
at position \(associatedWith + 1).
""")
}
}
#endif
複製代碼
inferringMoves()
獲得diff中所欲改變associatedWith
不爲nil
的.insert(offset:element:associatedWith:)
來判斷是插入的操做associatedWith
不爲nil
的.remove(offset:element:associatedWith:)
來判斷是刪除的操做這個功能確實很是的pro哈~~
能夠在Swfift 5.1的版本中建立一個沒有初始值的數組。
// 1
let randomSwitches = Array<String>(unsafeUninitializedCapacity: 5) {
buffer, count in
// 2
for i in 0..<5 {
buffer[i] = Bool.random() ? "on" : "off"
}
// 3
count = 5
}
複製代碼
init(unsafeUninitializedCapacity:initializingWith:)
來建立一個初始大小的數組inout
參數可讓你從新爲數組設置長度。這些就是swift 5.1的更新了,不算難懂,確實讓swift愈來愈好用。😄