首发: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愈来愈好用。😄