版本記錄
| 版本號 | 時(shí)間 |
|---|---|
| V1.0 | 2019.08.01 星期四 |
前言
幾乎隨著每一版iOS新系統(tǒng)的發(fā)布,Swift都會有所改變,加入了更多的特性,下面我們就一起走進(jìn)看一下相關(guān)的變化。
開始
首先,看下主要內(nèi)容
主要內(nèi)容:Swift 5.1的新變化。
接著,看下寫作環(huán)境
Swift 5, iOS 13, Xcode 11
好消息:Swift 5.1現(xiàn)在可以在Xcode 11 beta中使用!此版本帶來了模塊穩(wěn)定性(module stability),并通過改進(jìn)了語言的重要特征。在本教程中,您將了解Swift 5.1中的新功能。您需要Xcode 11 beta才能使用Swift 5.1,因此請?jiān)陂_始之前安裝它。
Swift 5.1與Swift 5兼容。由于ABI stability,它還與Swift 5以及未來版本的Swift二進(jìn)制兼容。
Swift 5.1在Swift 5中引入的ABI stability之上增加了模塊穩(wěn)定性。雖然ABI穩(wěn)定性在運(yùn)行時(shí)負(fù)責(zé)應(yīng)用程序兼容性,但模塊穩(wěn)定性使編譯時(shí)的庫兼容性成為可能。這意味著您可以將第三方框架與任何編譯器版本一起使用,而不是僅使用它構(gòu)建的版本。
每個教程部分都包含Swift Evolution建議編號,例如[SE-0001]。您可以通過單擊每個提案的鏈接標(biāo)記來瀏覽每個更改。
我建議您通過在playground上嘗試新功能來學(xué)習(xí)本教程。啟動Xcode 11并轉(zhuǎn)到File ? New ? Playground。選擇iOS作為平臺,選擇Blank作為模板。將其命名并將其保存在您想要的位置。那么就是時(shí)候開始了!
Language Improvements
此版本中有許多語言改進(jìn),包括不透明的結(jié)果類型,函數(shù)構(gòu)建器,屬性包裝器等。
1. Opaque Result Types
您可以使用協(xié)議作為Swift 5中函數(shù)的返回類型。
打開新的Playground后,通過導(dǎo)航到View ? Navigators ? Show Project Navigator打開Project Navigator。 右鍵單擊Sources文件夾,選擇New File并將文件命名為BlogPost。 使用名為BlogPost的新協(xié)議的定義替換新文件的內(nèi)容。
public protocol BlogPost {
var title: String { get }
var author: String { get }
}
右鍵單擊頂層playground并選擇New Playground Page。 重命名新的playground頁面Opaque Tutorials并將其粘貼到其中:
// 1
struct Tutorial: BlogPost {
let title: String
let author: String
}
// 2
func createBlogPost(title: String, author: String) -> BlogPost {
guard !title.isEmpty && !author.isEmpty else {
fatalError("No title and/or author assigned!")
}
return Tutorial(title: title, author: author)
}
// 3
let swift4Tutorial = createBlogPost(title: "What's new in Swift 4.2?",
author: "Cosmin Pup?z?")
let swift5Tutorial = createBlogPost(title: "What's new in Swift 5?",
author: "Cosmin Pup?z?")
這一步一步:
- 1) 聲明
Tutorial的title和author,因?yàn)?code>Tutorial實(shí)現(xiàn)了BlogPost。 - 2) 檢查
title和author是否有效,如果測試成功,則從createBlogPost(title:author :)返回Tutorial。 - 3) 使用
createBlogPost(title:author :)創(chuàng)建swift4Tutorial和swift5Tutorial。
您可以重復(fù)使用createBlogPost(title:author :)的原型和邏輯來創(chuàng)建截屏視頻。
右鍵單擊頂層playground并選擇New Playground Page。 重命名新的playground頁面Opaque Screencasts并將其粘貼到其中:
struct Screencast: BlogPost {
let title: String
let author: String
}
func createBlogPost(title: String, author: String) -> BlogPost {
guard !title.isEmpty && !author.isEmpty else {
fatalError("No title and/or author assigned!")
}
return Screencast(title: title, author: author)
}
let swift4Screencast = createBlogPost(title: "What's new in Swift 4.2?",
author: "Josh Steele")
let swift5Screencast = createBlogPost(title: "What's new in Swift 5?",
author: "Josh Steele")
Screencast實(shí)現(xiàn)了BlogPost,因此您可以從createBlogPost(title:author :)返回Screencast,并使用createBlogPost(title:author :)來創(chuàng)建swift4Screencast和swift5Screencast。
導(dǎo)航到Sources文件夾中的BlogPost.swift,并使BlogPost符合Equatable。
public protocol BlogPost: Equatable {
var title: String { get }
var author: String { get }
}
此時(shí),您將收到一個錯誤,即BlogPost只能用作generic constraint。 這是因?yàn)?code>Equatable有一個名為Self的關(guān)聯(lián)類型。 具有關(guān)聯(lián)類型的協(xié)議不是類型,即使它們看起來像類型。 相反,它們有點(diǎn)像類型占位符,表示“這可以是符合此協(xié)議的任何具體類型”。
Swift 5.1允許您將這些協(xié)議用作具有不透明結(jié)果類型的常規(guī)類型 opaque result types [SE-0244]。
在Opaque Tutorials頁面中,將some添加到createBlogPost的返回類型中,表示它返回BlogPost的具體實(shí)現(xiàn)。
func createBlogPost(title: String, author: String) -> some BlogPost {
同樣,在Opaque Screencasts頁面中,使用some來告訴編譯器createBlogPost返回某種類型的BlogPost。
func createBlogPost(title: String, author: String) -> some BlogPost {
在這種情況下,您可以從createBlogPost返回任何實(shí)現(xiàn)BlogPost的具體類型:Tutorial或Screencast。
現(xiàn)在,您可以檢查以前創(chuàng)建的教程和截屏是否相同。 在Opaque Tutorials的底部,粘貼以下內(nèi)容以檢查swift4Tutorial和swift5Tutorial是否相同。
let sameTutorial = swift4Tutorial == swift5Tutorial
在Opaque Screencasts的底部,粘貼以下內(nèi)容以檢查swift4Screencast和swift5Screencast是否相同。
let sameScreencast = swift4Screencast == swift5Screencast
2. Implicit Returns From Single-Expression Functions
在Swift 5中使用單表達(dá)式函數(shù)中的return:
extension Sequence where Element == Int {
func addEvenNumbers() -> Int {
return reduce(0) { $1.isMultiple(of: 2) ? $0 + $1 : $0 }
}
func addOddNumbers() -> Int {
return reduce(0) { $1.isMultiple(of: 2) ? $0 : $0 + $1 }
}
}
let numbers = [10, 5, 2, 7, 4]
let evenSum = numbers.addEvenNumbers()
let oddSum = numbers.addOddNumbers()
您在addEvenNumbers()和addOddNumbers()中使用reduce(_:_ :)來確定Sequence中偶數(shù)和奇數(shù)的總和。
Swift 5.1在單表達(dá)式函數(shù)中return,因此在這種情況下它們的行為類似于單行閉包[SE-0255]:
extension Sequence where Element == Int {
func addEvenNumbers() -> Int {
reduce(0) { $1.isMultiple(of: 2) ? $0 + $1 : $0 }
}
func addOddNumbers() -> Int {
reduce(0) { $1.isMultiple(of: 2) ? $0 : $0 + $1 }
}
}
這次代碼更清晰,更容易理解。
3. Function Builders
Swift 5.1使用函數(shù)構(gòu)建器(function builders)來實(shí)現(xiàn)構(gòu)建器模式 builder pattern[SE-XXXX]:
@_functionBuilder
struct SumBuilder {
static func buildBlock(_ numbers: Int...) -> Int {
return numbers.reduce(0, +)
}
}
使用@_functionBuilder注釋SumBuilder,使其成為函數(shù)構(gòu)建器類型。 函數(shù)構(gòu)建器是特殊類型的函數(shù),其中每個表達(dá)式(文字,變量名,函數(shù)調(diào)用,if語句等)單獨(dú)處理并用于生成單個值。 例如,您可以編寫一個函數(shù),其中每個表達(dá)式將該表達(dá)式的結(jié)果添加到數(shù)組中,從而創(chuàng)建您自己的數(shù)組文字。
注意:在Xcode測試版中,函數(shù)構(gòu)建器的注釋是
@_functionBuilder,因?yàn)榇颂嶙h尚未獲得批準(zhǔn)。 一旦獲得批準(zhǔn),期望注釋成為@functionBuilder。
您可以通過實(shí)現(xiàn)具有特定名稱和類型簽名的不同靜態(tài)函數(shù)來創(chuàng)建函數(shù)構(gòu)建器。 buildBlock(_:T ...)是唯一需要的。 還有一些函數(shù)可以處理if語句,選項(xiàng)和其他可以作為表達(dá)式處理的結(jié)構(gòu)。
您可以通過使用類名注釋函數(shù)或閉包來使用函數(shù)構(gòu)建器:
func getSum(@SumBuilder builder: () -> Int) -> Int {
builder()
}
let gcd = getSum {
8
12
5
}
傳遞給getSum的閉包計(jì)算每個表達(dá)式(在本例中為三個數(shù)字),并將這些表達(dá)式的結(jié)果列表傳遞給構(gòu)建器。 函數(shù)構(gòu)建器和隱式返回是SwiftUI干凈語法的構(gòu)建塊。 它們還允許您創(chuàng)建自己的特定于域的語言。
4. Property Wrappers
在Swift 5中使用計(jì)算屬性時(shí),你會處理很多樣板代碼:
var settings = ["swift": true, "latestVersion": true]
struct Settings {
var isSwift: Bool {
get {
return settings["swift"] ?? false
}
set {
settings["swift"] = newValue
}
}
var isLatestVersion: Bool {
get {
return settings["latestVersion"] ?? false
}
set {
settings["latestVersion"] = newValue
}
}
}
var newSettings = Settings()
newSettings.isSwift
newSettings.isLatestVersion
newSettings.isSwift = false
newSettings.isLatestVersion = false
isSwift和isLatestVersion在settings中獲取并設(shè)置給定鍵的值。 Swift 5.1通過定義property wrappers[SE-0258]來刪除重復(fù)代碼:
// 1
@propertyWrapper
struct SettingsWrapper {
let key: String
let defaultValue: Bool
// 2
var wrappedValue: Bool {
get {
settings[key] ?? defaultValue
}
set {
settings[key] = newValue
}
}
}
// 3
struct Settings {
@SettingsWrapper(key: "swift", defaultValue: false) var isSwift: Bool
@SettingsWrapper(key: "latestVersion", defaultValue: false)
var isLatestVersion: Bool
}
這就是上面代碼的工作原理:
- 1) 使用
@propertyWrapper注釋SettingsWrapper,使其成為屬性包裝器類型。 - 2) 使用
wrappedValue獲取并設(shè)置settings中的key。 - 3) 標(biāo)記
isSwift和isLatestVersion為@SettingsWrapper用相應(yīng)的包裝器實(shí)現(xiàn)它們。

5. Synthesizing Default Values for Initializers in Structures
默認(rèn)情況下,Swift 5不會為結(jié)構(gòu)中的屬性設(shè)置初始值,因此您可以為它們定義自定義初始值設(shè)定項(xiàng):
struct Author {
let name: String
var tutorialCount: Int
init(name: String, tutorialCount: Int = 0) {
self.name = name
self.tutorialCount = tutorialCount
}
}
let author = Author(name: "George")
如果author已經(jīng)通過了他的試用并加入了網(wǎng)站上的教程團(tuán)隊(duì),那么你將這里設(shè)置tutorialCount為0。
Swift 5.1允許您直接為結(jié)構(gòu)屬性設(shè)置默認(rèn)值,因此不再需要自定義初始值設(shè)定項(xiàng)[SE-0242]:
struct Author {
let name: String
var tutorialCount = 0
}
這次代碼更簡潔,更簡單。
6. Self for Static Members
您不能使用Self在Swift 5中引用數(shù)據(jù)類型的靜態(tài)成員,因此您必須使用類型名稱:
struct Editor {
static func reviewGuidelines() {
print("Review editing guidelines.")
}
func edit() {
Editor.reviewGuidelines()
print("Ready for editing!")
}
}
let editor = Editor()
editor.edit()
網(wǎng)站上的編輯在編輯教程之前會查看編輯指南,因?yàn)樗鼈兛偸菚l(fā)生變化。
你可以在Swift 5.1中使用Self重寫整個東西[SE-0068]:
struct Editor {
static func reviewGuidelines() {
print("Review editing guidelines.")
}
func edit() {
Self.reviewGuidelines()
print("Ready for editing!")
}
}
你這次使用Self來調(diào)用reviewGuidelines()。
7. Creating Uninitialized Arrays
您可以在Swift 5.1中創(chuàng)建未初始化的數(shù)組[SE-0245]:
// 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
}
逐步完成上面的代碼:
- 1) 使用
init(unsafeUninitializedCapacity:initializingWith :)創(chuàng)建具有特定初始容量的randomSwitches。 - 2) 循環(huán)遍歷
randomSwitches并使用random()設(shè)置每個開關(guān)狀態(tài)。 - 3) 設(shè)置
randomSwitches的初始化元素?cái)?shù)。
8. Diffing Ordered Collections
Swift 5.1使您能夠確定有序集合之間的差異[SE-0240]。
假設(shè)您有兩個數(shù)組:
let operatingSystems = ["Yosemite",
"El Capitan",
"Sierra",
"High Sierra",
"Mojave",
"Catalina"]
var answers = ["Mojave",
"High Sierra",
"Sierra",
"El Capitan",
"Yosemite",
"Mavericks"]
operatingSystems包含自Swift 1從最舊到最新排列的所有macOS版本。 answers在添加和刪除其中一些時(shí)以相反的順序列出它們。
差異集合需要您使用#if swift(> =)檢查最新的Swift版本,因?yàn)樗?code>diffing方法僅標(biāo)記為@available,僅適用于Swift 5.1:
#if swift(>=5.1)
let differences = operatingSystems.difference(from: answers)
let sameAnswers = answers.applying(differences) ?? []
// ["Yosemite", "El Capitan", "Sierra", "High Sierra", "Mojave", "Catalina"]
通過difference(from:)獲取operatingSystems和answers之間的differences,并使用applying(_:)將它們應(yīng)用于answers。
或者,您可以手動執(zhí)行此操作:
// 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
這是代碼的作用:
- 1) 使用
inferringMoves()來確定differences中的移動并遍歷它們。 - 2) 如果
change為.insert(offset:element:associatedWith :),則將offset處的element添加到answers中,如果associatedWith不為nil,則將插入視為removal。 - 3) 如果
change為.remove(offset:element:associatedWith :),則刪除answers處offset答案的element,如果associatedWith不為nil,則考慮刪除removal。

9. Static and Class Subscripts
Swift 5.1允許您在[SE-0254]中聲明static和class subscripts:
// 1
@dynamicMemberLookup
class File {
let name: String
init(name: String) {
self.name = name
}
// 2
static subscript(key: String) -> String {
switch key {
case "path":
return "custom path"
default:
return "default path"
}
}
// 3
class subscript(dynamicMember key: String) -> String {
switch key {
case "path":
return "custom path"
default:
return "default path"
}
}
}
// 4
File["path"]
File["PATH"]
File.path
File.PATH
這就是它的工作原理:
- 1) 將
File標(biāo)記為@dynamicMemberLookup以啟用custom subscripts的點(diǎn)語法。 - 2) 創(chuàng)建一個靜態(tài)
subscript,返回File的默認(rèn)路徑或自定義路徑。 - 3) 使用動態(tài)成員查找定義上一個
subscript的類版本。 - 4) 使用相應(yīng)的語法調(diào)用兩個
subscript。
注意:想要了解有關(guān)Swift中下標(biāo)的更多信息? 查看下標(biāo)教程:Swift中的自定義下標(biāo)。
10. Dynamic Member Lookup for Keypaths
Swift 5.1實(shí)現(xiàn)了關(guān)鍵路徑的動態(tài)成員查找[SE-0252]:
// 1
struct Point {
let x, y: Int
}
// 2
@dynamicMemberLookup
struct Circle<T> {
let center: T
let radius: Int
// 3
subscript<U>(dynamicMember keyPath: KeyPath<T, U>) -> U {
center[keyPath: keyPath]
}
}
// 4
let center = Point(x: 1, y: 2)
let circle = Circle(center: center, radius: 1)
circle.x
circle.y
逐步完成所有這些步驟:
- 1) 為
Point聲明x和y。 - 2) 使用
@dynamicMemberLookup注釋Circle以為其subscripts啟用點(diǎn)語法。 - 3) 創(chuàng)建一個通用
subscripts,使用鍵路徑從Circle訪問center屬性。 - 4) 使用動態(tài)成員查找而不是鍵路徑調(diào)用
circle上的調(diào)用center屬性。
11. Keypaths for Tuples
您可以在Swift 5.1中使用元組的路徑:
// 1
struct Instrument {
let brand: String
let year: Int
let details: (type: String, pitch: String)
}
// 2
let instrument = Instrument(brand: "Roland",
year: 2019,
details: (type: "acoustic", pitch: "C"))
let type = instrument[keyPath: \Instrument.details.type]
let pitch = instrument[keyPath: \Instrument.details.pitch]
下面就是要做的事:
- 1) 聲明
Instrument的rand, year, details。 - 2) 使用關(guān)鍵路徑從
instrument中的details中獲取type, pitch。
12. Equatable and Hashable Conformance for Weak and Unowned Properties
Swift 5.1自動為具有weak和unowned存儲屬性的結(jié)構(gòu)合成Equatable和Hashable 的 conformance。
假設(shè)你有兩個類:
class Key {
let note: String
init(note: String) {
self.note = note
}
}
extension Key: Hashable {
static func == (lhs: Key, rhs: Key) -> Bool {
lhs.note == rhs.note
}
func hash(into hasher: inout Hasher) {
hasher.combine(note)
}
}
class Chord {
let note: String
init(note: String) {
self.note = note
}
}
extension Chord: Hashable {
static func == (lhs: Chord, rhs: Chord) -> Bool {
lhs.note == rhs.note
}
func hash(into hasher: inout Hasher) {
hasher.combine(note)
}
}
通過實(shí)現(xiàn)==(lhs:rhs :)和hash(into :),Key和Chord都符合Equatable和Hashable。
如果在結(jié)構(gòu)中使用這些類,Swift 5.1將能夠合成Hashable conformance:
struct Tune: Hashable {
unowned let key: Key
weak var chord: Chord?
}
let key = Key(note: "C")
let chord = Chord(note: "C")
let tune = Tune(key: key, chord: chord)
let chordlessTune = Tune(key: key, chord: nil)
let sameTune = tune == chordlessTune
let tuneSet: Set = [tune, chordlessTune]
let tuneDictionary = [tune: [tune.key.note, tune.chord?.note],
chordlessTune: [chordlessTune.key.note,
chordlessTune.chord?.note]]
Tune是Equatable和Hashable,因?yàn)?code>key和chord是Equatable和Hashable。
因?yàn)樗?code>Hashable,你可以將tune與chordlessTune進(jìn)行比較,將它們添加到tuneSet并將它們用作tuneDictionary的鍵。
13. Ambiguous Enumeration Cases
Swift 5.1為不明確的枚舉cases生成警告:
// 1
enum TutorialStyle {
case cookbook, stepByStep, none
}
// 2
let style: TutorialStyle? = .none
下面就是工作原理:
- 1) 為
TutorialStyle定義不同的樣式。 - 2)
Swift會發(fā)出警告,因?yàn)榫幾g器不清楚.none在case: Optional.none和TutorialStyle.none的含義是什么。
14. Matching Optional Enumerations Against Non-optionals
在Swift 5中,您可以使用optional pattern將non-optionals與的可選枚舉optional enumerations進(jìn)行匹配:
// 1
enum TutorialStatus {
case written, edited, published
}
// 2
let status: TutorialStatus? = .published
switch status {
case .written?:
print("Ready for editing!")
case .edited?:
print("Ready to publish!")
case .published?:
print("Live!")
case .none:
break
}
上面的代碼執(zhí)行以下操作:
- 1) 聲明
TutorialStatus的所有可能狀態(tài)。 - 2) 使用可選模式打開
status,因?yàn)槟鷮⑵涠x為可選模式。
在這種情況下,Swift 5.1刪除了可選的模式(optional pattern):
switch status {
case .written:
print("Ready for editing!")
case .edited:
print("Ready to publish!")
case .published:
print("Live!")
case .none:
break
}
這段代碼更清晰,更容易理解。
15. New Features for Strings
Swift 5.1為字符串添加了一些急需的功能[SE-0248]:
UTF8.width("S")
UTF8.isASCII(83)
在這里,您確定Unicode標(biāo)量值的UTF-8編碼寬度,并檢查給定的代碼單元是否表示ASCII標(biāo)量。 查看您可以使用的其他API的proposal。
16. Contiguous Strings
Swift 5.1對連續(xù)字符串(contiguous strings)[SE-0247]實(shí)現(xiàn)重要更改:
var string = "Swift 5.1"
if !string.isContiguousUTF8 {
string.makeContiguousUTF8()
}
您檢查UTF-8編碼的字符串是否與isContiguousUTF8連續(xù),并使用makeContiguousUTF8()來實(shí)現(xiàn),如果不是。 看一下提案(proposal),看看你可以用連續(xù)的字符串做些什么。
Miscellaneous Bits and Pieces
您應(yīng)該了解Swift 5.1中的一些其他功能:
1. Converting Tuple Types
Swift 5.1改進(jìn)了元組類型的轉(zhuǎn)換:
let temperatures: (Int, Int) = (25, 30)
let convertedTemperatures: (Int?, Any) = temperatures
您可以為convertedTemperatures賦值為temperatures,因?yàn)樵谶@種情況下您可以將(Int,Int)轉(zhuǎn)換為(Int?,Any)。
2. Tuples with Duplicate Labels
您可以在Swift 5中聲明帶有重復(fù)標(biāo)簽的元組:
let point = (coordinate: 1, coordinate: 2)
point.coordinate
在這種情況下,不清楚coordinate是否從point返回第一個或第二個元素,因此Swift 5.1刪除了元組的重復(fù)標(biāo)簽。
3. Overloading Functions With Any Parameters
Swift 5更喜歡Any參數(shù)而不是泛型參數(shù),只有一個參數(shù)的函數(shù)重載:
func showInfo(_: Any) -> String {
return "Any value"
}
func showInfo<T>(_: T) -> String {
return "Generic value"
}
showInfo("Swift 5")
在這種case下,showInfo()返回“Any value”。Swift 5.1以相反的方式工作:
func showInfo(_: Any) -> String {
"Any value"
}
func showInfo<T>(_: T) -> String {
"Generic value"
}
showInfo("Swift 5.1")
showInfo()這次返回“Generic value”。
4. Type Aliases for Autoclosure Parameters
你不能在Swift 5中為@autoclosure參數(shù)聲明類型別名(type aliases):
struct Closure<T> {
func apply(closure: @autoclosure () -> T) {
closure()
}
}
apply(closure :)在這種情況下使用autoclosure簽名進(jìn)行closure。 您可以在Swift 5.1中的apply(closure :)原型中使用類型別名:
struct Closure<T> {
typealias ClosureType = () -> T
func apply(closure: @autoclosure ClosureType) {
closure()
}
}
apply(closure :)這次使用ClosureType進(jìn)行閉包closure。
5. Returning Self From Objective-C methods
如果你的類包含一個在Swift 5中返回Self的@objc方法,你必須從NSObject繼承:
class Clone: NSObject {
@objc func clone() -> Self {
return self
}
}
Clone擴(kuò)展了NSObject,因?yàn)?code>clone()返回Self。 在Swift 5.1中不再是這種情況:
class Clone {
@objc func clone() -> Self {
self
}
}
Clone這次不必繼承任何東西。
6. Stable ABI Libraries
您可以在Swift 5.1中使用-enable-library-evolution來更改庫類型而不會破壞其ABI。 標(biāo)記為@frozen的結(jié)構(gòu)和枚舉不能添加,刪除或重新排序存儲的屬性和cases [SE-0260]。
Swift 5.1為Swift 5中已經(jīng)引入的功能添加了許多不錯的功能。它還為語言帶來了模塊穩(wěn)定性(module stability),并實(shí)現(xiàn)了WWDC中引入的新框架(如SwiftUI和Combine)所使用的復(fù)雜范例。
您可以在官方 Swift CHANGELOG 或 Swift standard library differences上閱讀有關(guān)此Swift版本更改的更多信息。
后記
本篇主要講述了Swift 5.1新變化,感興趣的給個贊或者關(guān)注~~~
