一、概述
好消息是尔,Swift 4.2 在 Xcode 10 beta 版上可以使用了瞻鹏,在 Swift 4.1 的基礎(chǔ)上更新了很多語(yǔ)言特性,為 Swift 5 中 ABI 穩(wěn)定做好準(zhǔn)備并思。
這篇文章包含了 Swift 4.2 中的重大的改變。因?yàn)?Swift 4.2 需要 Xcode 10语稠,所以請(qǐng)下載安裝最新的 Xcode 測(cè)試版本宋彼。
二、準(zhǔn)備
Swift 4.2 和 Swift 4.1 源碼兼容仙畦,但是和其他發(fā)布版本的二進(jìn)制不兼容输涕。Swift 4.2 是 Swift 5 實(shí)現(xiàn) ABI 穩(wěn)定(不同的 Swift 版本編譯的應(yīng)用程序和庫(kù)之間實(shí)現(xiàn)兼容)的一個(gè)中間階段。ABI 的特性在集成進(jìn)最終的 ABI 之前會(huì)接收社區(qū)的大量反饋慨畸。
三莱坎、語(yǔ)言演進(jìn)
在這個(gè)版本中有很多新的語(yǔ)言特性。例如寸士,隨機(jī)數(shù)生成檐什,動(dòng)態(tài)成員查找等等
3.1 隨機(jī)數(shù)生成
3.1.1 隨機(jī)數(shù)生成
arc4random_uniform(_:)
返回一個(gè) 0 - 9 之間的隨機(jī)數(shù)字。這種實(shí)現(xiàn)方式有兩個(gè)問(wèn)題:
- 需要引入
Foundation
框架弱卡,在 Linux 下無(wú)法工作乃正。 - Linux 上的隨機(jī)數(shù)生成會(huì)產(chǎn)生模偏差(有取模的過(guò)程,更容易隨機(jī)到小的數(shù))婶博。
// Swift 4.1
let digit = Int(arc4random_uniform(10))
Swift 4.2 在標(biāo)準(zhǔn)庫(kù)中添加了隨機(jī)數(shù)的 API SE-0202
// Swift 4.2
/ 1
let digit = Int.random(in: 0..<10)
?
// 2
if let anotherDigit = (0..<10).randomElement() {
print(anotherDigit)
} else {
print("Empty range.")
}
?
// 3
let double = Double.random(in: 0..<1)
let float = Float.random(in: 0..<1)
let cgFloat = CGFloat.random(in: 0..<1)
let bool = Bool.random()
注:randomElement() 如果 range 是空瓮具,返回 nil
3.1.2 數(shù)組隨機(jī)
Swift 4.1 數(shù)組隨機(jī)也是采用 C 函數(shù)的形式,這種方式會(huì)存在上面提到的問(wèn)題,而且會(huì)存在 Int 和 Int32 轉(zhuǎn)換的問(wèn)題名党。
let playlist = ["Nothing Else Matters", "Stairway to Heaven", "I Want to Break Free", "Yesterday"]
let index = Int(arc4random_uniform(UInt32(playlist.count)))
let song = playlist[index]
Swift 4.2 采用了更加簡(jiǎn)單直接的方式叹阔。
if let song = playlist.randomElement() {
print(song)
} else {
print("Empty playlist.")
}
3.1.3 洗牌算法
Swift 4.1 不包含任何集合的洗牌算法,所以要采用比較曲折的方式來(lái)實(shí)現(xiàn)传睹。
// 1
let shuffledPlaylist = playlist.sorted{ _, _ in arc4random_uniform(2) == 0 }
?
// 2
var names = ["Cosmin", "Oana", "Sclip", "Nori"]
names.sort { _, _ in arc4random_uniform(2) == 0 }
Swift 4.2 提供了更加高效更加優(yōu)雅的實(shí)現(xiàn) Shuffling Algorithms
let shuffledPlaylist = playlist.shuffled()
names.shuffle()
注:使用 shuffled()
來(lái)創(chuàng)建一個(gè)洗牌后的數(shù)組耳幢。使用 shuffle)
來(lái)將數(shù)組洗牌。
3.2 動(dòng)態(tài)成員查找
Swift 4.1 使用下面的方式實(shí)現(xiàn)自定義下標(biāo)操作蒋歌。
class Person {
let name: String
let age: Int
private let details: [String: String]
init(name: String, age: Int, details: [String: String]) {
self.name = name
self.age = age
self.details = details
}
subscript(key: String) -> String {
switch key {
case "info":
return "\(name) is \(age) years old."
default:
return details[key] ?? ""
}
}
}
let details = ["title": "Author", "instrument": "Guitar"]
let me = Person(name: "Cosmin", age: 32, details: details)
me["info"] // "Cosmin is 32 years old."
me["title"] // "Author"
Swift 4.2 使用動(dòng)態(tài)成員查找來(lái)提供點(diǎn)語(yǔ)法來(lái)實(shí)現(xiàn)下標(biāo)調(diào)用 Dynamic Member Lookup
// 1
@dynamicMemberLookup
class Person {
let name: String
let age: Int
private let details: [String: String]
init(name: String, age: Int, details: [String: String]) {
self.name = name
self.age = age
self.details = details
}
// 2
subscript(dynamicMember key: String) -> String {
switch key {
case "info":
return "\(name) is \(age) years old."
default:
return details[key] ?? ""
}
}
}
// 3
me.info // "Cosmin is 32 years old."
me.title // "Author"
使用步驟:
- 標(biāo)記 Person 為 @dynamicMemberLookup 使下標(biāo)可以使用點(diǎn)語(yǔ)法
- 遵守 @dynamicMemberLookup 實(shí)現(xiàn) subscript(dynamicMember:) 方法
- 使用點(diǎn)語(yǔ)法調(diào)用之前定義的下標(biāo)
注:編譯器會(huì)在運(yùn)行時(shí)動(dòng)態(tài)評(píng)估下標(biāo)的調(diào)用帅掘,這樣就可以寫(xiě)出像 Python 或者 Ruby 等腳本語(yǔ)言一樣類(lèi)型安全的代碼。
動(dòng)態(tài)成員查找不會(huì)和類(lèi)的屬性混淆堂油。
me.name // "Cosmin"
me.age // 32
可以使用點(diǎn)語(yǔ)法而非下標(biāo)來(lái)調(diào)用 name 和 age修档。而且派生類(lèi)可以繼承基類(lèi)的動(dòng)態(tài)成員查找。
@dynamicMemberLookup
class Vehicle {
let brand: String
let year: Int
init(brand: String, year: Int) {
self.brand = brand
self.year = year
}
subscript(dynamicMember key: String) -> String {
return "\(brand) made in \(year)."
}
}
class Car: Vehicle {}
let car = Car(brand: "BMW", year: 2018)
car.info // "BMW made in 2018."
可以通過(guò)協(xié)議拓展給已有類(lèi)型添加動(dòng)態(tài)成員查找
// 1
@dynamicMemberLookup
protocol Random {}
// 2
extension Random {
subscript(dynamicMember key: String) -> Int {
return Int.random(in: 0..<10)
}
}
// 3
extension Int: Random {}
// 4
let number = 10
let randomDigit = String(number.digit)
let noRandomDigit = String(number).filter { String($0) != randomDigit }
3.3 枚舉實(shí)例集合
Swift 4.1 默認(rèn)沒(méi)有提供訪問(wèn)枚舉實(shí)例集合的方式府框,所以實(shí)現(xiàn)方式不是很優(yōu)雅吱窝。
enum Seasons: String {
case spring = "Spring", summer = "Summer", autumn = "Autumn", winter = "Winter"
}
enum SeasonType {
case equinox
case solstice
}
let seasons = [Seasons.spring, .summer, .autumn, .winter]
for (index, season) in seasons.enumerated() {
let seasonType = index % 2 == 0 ? SeasonType.equinox : .solstice
print("\(season.rawValue) \(seasonType).")
}
為了解決這個(gè)問(wèn)題,Swift 4.2 給枚舉類(lèi)型添加了實(shí)例數(shù)組迫靖。
// 1
enum Seasons: String, CaseIterable {
case spring = "Spring", summer = "Summer", autumn = "Autumn", winter = "Winter"
}
enum SeasonType {
case equinox
case solstice
}
// 2
for (index, season) in Seasons.allCases.enumerated() {
let seasonType = index % 2 == 0 ? SeasonType.equinox : .solstice
print("\(season.rawValue) \(seasonType).")
}
如果枚舉中包含 unavailable
院峡,需要將 available
的 case
手動(dòng)維護(hù)協(xié)議中的 allCases
。
enum Days: CaseIterable {
case monday, tuesday, wednesday, thursday, friday
@available(*, unavailable)
case saturday, sunday
static var allCases: [Days] {
return [.monday, .tuesday, .wednesday, .thursday, .friday]
}
}
在 allCases
中只能添加 weekdays
系宜,因?yàn)?saturday
和 sunday
被標(biāo)記為各個(gè)平臺(tái)不可用照激。
枚舉實(shí)例數(shù)組中也可以添加有關(guān)聯(lián)值的實(shí)例。
enum BlogPost: CaseIterable {
case article
case tutorial(updated: Bool)
static var allCases: [BlogPost] {
return [.article, .tutorial(updated: true), .tutorial(updated: false)]
}
}
3.4 新的序列方法
Swift 4.1 中的 Sequence
定義了查找指定元素的第一個(gè)索引位置或者滿(mǎn)足指定條件的第一個(gè)元素的方法盹牧。
let ages = ["ten", "twelve", "thirteen", "nineteen", "eighteen", "seventeen", "fourteen", "eighteen", "fifteen", "sixteen", "eleven"]
if let firstTeen = ages.first(where: { $0.hasSuffix("teen") }),
let firstIndex = ages.index(where: { $0.hasSuffix("teen") }),
let firstMajorIndex = ages.index(of: "eighteen") {
print("Teenager number \(firstIndex + 1) is \(firstTeen) years old.")
print("Teenager number \(firstMajorIndex + 1) isn't a minor anymore.")
} else {
print("No teenagers around here.")
}
Swift 4.2 為了實(shí)現(xiàn)一致性重構(gòu)了方法名
if let firstTeen = ages.first(where: { $0.hasSuffix("teen") }),
let firstIndex = ages.firstIndex(where: { $0.hasSuffix("teen") }),
let firstMajorIndex = ages.firstIndex(of: "eighteen") {
print("Teenager number \(firstIndex + 1) is \(firstTeen) years old.")
print("Teenager number \(firstMajorIndex + 1) isn't a minor anymore.")
} else {
print("No teenagers around here.")
}
Swift 4.1 也沒(méi)有定義查找指定元素的最后一個(gè)索引的位置和滿(mǎn)足指定條件的的最后一個(gè)元素等方法俩垃。在 Swift 4.1 中我們可能采用下面的方法來(lái)處理。
// 1
let reversedAges = ages.reversed()
// 2
if let lastTeen = reversedAges.first(where: { $0.hasSuffix("teen") }),
let lastIndex = reversedAges.index(where: { $0.hasSuffix("teen") })?.base,
let lastMajorIndex = reversedAges.index(of: "eighteen")?.base {
print("Teenager number \(lastIndex) is \(lastTeen) years old.")
print("Teenager number \(lastMajorIndex) isn't a minor anymore.")
} else {
print("No teenagers around here.")
}
Swift 4.2 添加了相應(yīng)的方法汰寓,使用方式如下
if let lastTeen = ages.last(where: { $0.hasSuffix("teen") }),
let lastIndex = ages.lastIndex(where: { $0.hasSuffix("teen") }),
let lastMajorIndex = ages.lastIndex(of: "eighteen") {
print("Teenager number \(lastIndex + 1) is \(lastTeen) years old.")
print("Teenager number \(lastMajorIndex + 1) isn't a minor anymore.")
} else {
print("No teenagers around here.")
}
3.5 檢測(cè)序列元素
Swift 4.1 中沒(méi)有檢查序列中所有元素是否滿(mǎn)足某個(gè)指定條件的方法口柳。不過(guò)你可以實(shí)現(xiàn)你自己的方法,例如下面檢測(cè)集合中的元素是否都是偶數(shù)有滑。
let values = [10, 8, 12, 20]
let allEven = !values.contains { $0 % 2 == 1 }
Swift 4.2 添加了新的方法跃闹,很好的簡(jiǎn)化了代碼,提升了可讀性毛好。
let allEven = values.allSatisfy { $0 % 2 == 0 }
3.6 條件遵守更新
Swift 4.2 給拓展和標(biāo)準(zhǔn)庫(kù)中添加一些條件遵守方面的改進(jìn)望艺。
3.6.1 拓展中的條件遵守
Swift 4.1 不能在拓展中自動(dòng)合成 Equatable
的協(xié)議實(shí)現(xiàn)。例子如下:
// 1
struct Tutorial : Equatable {
let title: String
let author: String
}
// 2
struct Screencast<Tutorial> {
let author: String
let tutorial: Tutorial
}
// 3
extension Screencast: Equatable where Tutorial: Equatable {
// 必須自己實(shí)現(xiàn) == 方法肌访,Swift 4.1 不會(huì)自動(dòng)合成
static func ==(lhs: Screencast, rhs: Screencast) -> Bool {
return lhs.author == rhs.author && lhs.tutorial == rhs.tutorial
}
}
// 4
let swift41Tutorial = Tutorial(title: "What's New in Swift 4.1?", author: "Cosmin Pup?z?")
let swift42Tutorial = Tutorial(title: "What's New In Swift 4.2?", author: "Cosmin Pup?z?")
let swift41Screencast = Screencast(author: "Jessy Catterwaul", tutorial: swift41Tutorial)
let swift42Screencast = Screencast(author: "Jessy Catterwaul", tutorial: swift42Tutorial)
let sameScreencast = swift41Screencast == swift42Screencast
Swift 4.2 只需要遵守協(xié)議荣茫,不需要實(shí)現(xiàn)。因?yàn)榫幾g器會(huì)添加一個(gè)默認(rèn)的Equatable
協(xié)議實(shí)現(xiàn)场靴。
extension Screencast: Equatable where Tutorial: Equatable {}
這個(gè)特性也同樣支持 Hashable
和 Codable
。
// 1
struct Tutorial: Hashable, Codable {
let title: String
let author: String
}
struct Screencast<Tutorial> {
let author: String
let tutorial: Tutorial
}
// 2
extension Screencast: Hashable where Tutorial: Hashable {}
extension Screencast: Codable where Tutorial: Codable {}
// 3
let screencastsSet: Set = [swift41Screencast, swift42Screencast]
let screencastsDictionary = [swift41Screencast: "Swift 4.1", swift42Screencast: "Swift 4.2"]
let screencasts = [swift41Screencast, swift42Screencast]
let encoder = JSONEncoder()
do {
try encoder.encode(screencasts)
} catch {
print("\(error)")
}
3.6.2 條件遵守運(yùn)行時(shí)查詢(xún)
Swift 4.2 實(shí)現(xiàn)條件遵守的動(dòng)態(tài)查詢(xún)≈及可以從下面的例子看出咧欣。
// 1
class Instrument {
let brand: String
init(brand: String = "") {
self.brand = brand
}
}
// 2
protocol Tuneable {
func tune()
}
// 3
class Keyboard: Instrument, Tuneable {
func tune() {
print("\(brand) keyboard tuning.")
}
}
// 4
extension Array: Tuneable where Element: Tuneable {
func tune() {
forEach { $0.tune() }
}
}
// 5
let instrument = Instrument()
let keyboard = Keyboard(brand: "Roland")
let instruments = [instrument, keyboard]
// 6
if let keyboards = instruments as? Tuneable {
keyboards.tune()
} else {
print("Can't tune instrument.")
}
注:上面在條件遵循的運(yùn)行時(shí)檢測(cè)中,會(huì)輸出 "Can't tune instrument."
轨帜,因?yàn)?Instrument
類(lèi)型不遵守 Tuneable
協(xié)議魄咕,如果是兩個(gè) Keyboard
類(lèi)型就可以。
更多關(guān)于 Conditional Conformance
的內(nèi)容蚌父,參考 Swift 4.1 更新指北(譯)
3.6.3 Hashable 在標(biāo)準(zhǔn)庫(kù)中條件遵守增強(qiáng)
在 Swift 4.2 中可選值哮兰、數(shù)組、字典和區(qū)間當(dāng)他們的元素是 Hashable
的話(huà)苟弛,他們也是 Hashable
喝滞。
struct Chord: Hashable {
let name: String
let description: String?
let notes: [String]
let signature: [String: [String]?]
let frequency: CountableClosedRange<Int>
}
let cMajor = Chord(name: "C", description: "C major", notes: ["C", "E", "G"],
signature: ["sharp": nil, "flat": nil], frequency: 432...446)
let aMinor = Chord(name: "Am", description: "A minor", notes: ["A", "C", "E"],
signature: ["sharp": nil, "flat": nil], frequency: 440...446)
let chords: Set = [cMajor, aMinor]
let versions = [cMajor: "major", aMinor: "minor"]
3.7 Hashable 增強(qiáng)
Swift 4.1 中一般會(huì)像下面這樣實(shí)現(xiàn)自定義哈希函數(shù):
class Country: Hashable {
let name: String
let capital: String
init(name: String, capital: String) {
self.name = name
self.capital = capital
}
static func ==(lhs: Country, rhs: Country) -> Bool {
return lhs.name == rhs.name && lhs.capital == rhs.capital
}
var hashValue: Int {
return name.hashValue ^ capital.hashValue &* 16777619
}
}
let france = Country(name: "France", capital: "Paris")
let germany = Country(name: "Germany", capital: "Berlin")
let countries: Set = [france, germany]
let countryGreetings = [france: "Bonjour", germany: "Guten Tag"]
因?yàn)?code>countries是 Hashable
,所以可以添加到集合或者字典中膏秫。但是 hashValue
的實(shí)現(xiàn)很難理解并且也不高效右遭。Swift 4.2 通過(guò)定義了一個(gè)通用的哈希函數(shù)來(lái)解決這個(gè)問(wèn)題。
class Country: Hashable {
let name: String
let capital: String
init(name: String, capital: String) {
self.name = name
self.capital = capital
}
static func ==(lhs: Country, rhs: Country) -> Bool {
return lhs.name == rhs.name && lhs.capital == rhs.capital
}
func hash(into hasher: inout Hasher) {
hasher.combine(name)
hasher.combine(capital)
}
}
在 Country
中使用 hash(into:)
來(lái)替代 hashValue
缤削。這個(gè)函數(shù)使用 combine()
將屬性注入到 hasher
中窘哈。
注:現(xiàn)在實(shí)現(xiàn)上很容易,并且性能要比之前的版本高亭敢。
3.8 集合中移除元素
在 Swift 4.1 中滚婉,想要從集合中移除一個(gè)指定的元素,通常會(huì)使用 filter(_:)
的實(shí)現(xiàn)方式帅刀,在 Swift 4.2 添加了 removeAll(_:)
让腹。
// Swift 4.1
var greetings = ["Hello", "Hi", "Goodbye", "Bye"]
greetings = greetings.filter { $0.count <= 3 }
// Swift 4.2
greetings.removeAll { $0.count > 3 }
3.9 更改布爾值
在 Swift 4.1 中,我們通常會(huì)這樣實(shí)現(xiàn)
extension Bool {
mutating func toggle() {
self = !self
}
}
var isOn = true
isOn.toggle()
Swift 4.2 給 Bool
增加了 toggle()
方法
3.10 新的編譯器指令
Swift 4.2 定義了表述代碼問(wèn)題的編譯器指令
// 1
#warning("There are shorter implementations out there.")
let numbers = [1, 2, 3, 4, 5]
var sum = 0
for number in numbers {
sum += number
}
print(sum)
// 2
#error("Please fill in your credentials.")
let username = ""
let password = ""
switch (username.filter { $0 != " " }, password.filter { $0 != " " }) {
case ("", ""):
print("Invalid username and password.")
case ("", _):
print("Invalid username.")
case (_, ""):
print("Invalid password.")
case (_, _):
print("Logged in succesfully.")
}
-
#warning
用來(lái)輸出警告信息劝篷,表示實(shí)現(xiàn)未完全完成 -
#error
強(qiáng)制其他開(kāi)發(fā)者填入username
和password
3.11 新的指針函數(shù)
withUnsafeBytes(of:_:)
和 withUnsafePointer(to:_:)
在 Swift 4.1 中只能用于變量哨鸭,所以必須拷貝一份。Swift 4.2 中該函數(shù)支持常量娇妓,不需要再保存值像鸡。
// Swift 4.1
let value = 10
var copy = value
withUnsafeBytes(of: ©) { pointer in print(pointer.count) }
withUnsafePointer(to: ©) { pointer in print(pointer.hashValue) }
// Swift 4.2
withUnsafeBytes(of: value) { pointer in print(pointer.count) }
withUnsafePointer(to: value) { pointer in print(pointer.hashValue) }
3.12 Memory Layout 更新
Swift 4.2 使用 keypath 查找存儲(chǔ)屬性的內(nèi)存布局 [SE-0210],具體做法如下:
// 1
struct Point {
var x, y: Double
}
// 2
struct Circle {
var center: Point
var radius: Double
var circumference: Double {
return 2 * .pi * radius
}
var area: Double {
return .pi * radius * radius
}
}
// 3
if let xOffset = MemoryLayout.offset(of: \Circle.center.x),
let yOffset = MemoryLayout.offset(of: \Circle.center.y),
let radiusOffset = MemoryLayout.offset(of: \Circle.radius) {
print("\(xOffset) \(yOffset) \(radiusOffset)")
} else {
print("Nil offset values.")
}
// 4
if let circumferenceOffset = MemoryLayout.offset(of: \Circle.circumference),
let areaOffset = MemoryLayout.offset(of: \Circle.area) {
print("\(circumferenceOffset) \(areaOffset)")
} else {
print("Nil offset values.")
注:可以通過(guò) keypath 返回存儲(chǔ)屬性的內(nèi)存偏移哈恰。計(jì)算屬性返回 nil只估,因?yàn)闆](méi)有存儲(chǔ)關(guān)聯(lián)。
3.13 模塊中的內(nèi)聯(lián)函數(shù)
在 Swift 4.1 中着绷,不允許在自己的模塊中定義內(nèi)聯(lián)函數(shù)蛔钙。依次選擇 View ? Navigators ? Show Project Navigator, 右鍵單擊 Sources and 選擇 New File。重命名文件為 FactorialKit.swift 并且替換為下面代碼塊中的代碼荠医。
public class CustomFactorial {
private let customDecrement: Bool
public init(_ customDecrement: Bool = false) {
self.customDecrement = customDecrement
}
private var randomDecrement: Int {
return arc4random_uniform(2) == 0 ? 2 : 3
}
public func factorial(_ n: Int) -> Int {
guard n > 1 else {
return 1
}
let decrement = customDecrement ? randomDecrement : 1
return n * factorial(n - decrement)
}
}
在 Swift 4.2 中定義為內(nèi)聯(lián)的函數(shù)會(huì)更加高效吁脱,所以將 FactorialKit.swift 的代碼替換如下桑涎。
public class CustomFactorial {
@usableFromInline let customDecrement: Bool
public init(_ customDecrement: Bool = false) {
self.customDecrement = customDecrement
}
@usableFromInline var randomDecrement: Int {
return Bool.random() ? 2 : 3
}
@inlinable public func factorial(_ n: Int) -> Int {
guard n > 1 else {
return 1
}
let decrement = customDecrement ? randomDecrement : 1
return n * factorial(n - decrement)
}
}
四、其他更新
下面是 Swift 4.2 中的一些其他改變
4.1 Swift Package Manager 更新
4.1.1 定義 Package 的 Swift 版本
Swift 4.1 在 Package.swift 中定義了swiftLanguageVersions
兼贡,所以可以在 packages 中定義主版本攻冷。
let package = Package(name: "Package", swiftLanguageVersions: [4])
Swift 4.2 中也能通過(guò)SwiftVersion
定義小版本 [SE-0209]
let package = Package(name: "Package", swiftLanguageVersions: [.v4_2])
能夠通過(guò).version(_:)
定義之后的版本
let package = Package(name: "Package", swiftLanguageVersions: [.version("5")])
4.1.2 Packages 定義本地版本
在 Swift 4.1 中,可以使用倉(cāng)庫(kù)鏈接為 Package 定義依賴(lài)遍希。如果有相互關(guān)聯(lián)的 Package等曼,就會(huì)產(chǎn)生額外的問(wèn)題,所以 Swift 4.2 中引入了本地路徑而提案[SE-0201]凿蒜。
4.1.3 給 Package 添加系統(tǒng)庫(kù) Target
4.1.4 Swift 4.1 中系統(tǒng)模塊包需要分倉(cāng)庫(kù)禁谦,這樣包管理很難用 ,所以 Swift 4.2 使用系統(tǒng)庫(kù) Target 來(lái)實(shí)現(xiàn) [SE-0208]
4.2 移除隱式解包可選值
在 Swift 4.1 中废封,你可以在嵌套類(lèi)型中使用隱式解包可選值州泊。
let favoriteNumbers: [Int!] = [10, nil, 7, nil]
let favoriteSongs: [String: [String]!] = ["Cosmin": ["Nothing Else Matters", "Stairway to Heaven"], "Oana": nil]
let credentials: (usermame: String!, password: String!) = ("Cosmin", nil)
Swift 4.2 從數(shù)組、字典和元祖中移除了隱式解包可選值 SE-0054
let favoriteNumbers: [Int?] = [10, nil, 7, nil]
let favoriteSongs: [String: [String]?] = ["Cosmin": ["Nothing Else Matters", "Stairway to Heaven"], "Oana": nil]
let credentials: (usermame: String?, password: String?) = ("Cosmin", nil)
五虱饿、未來(lái)愿景
可以從這個(gè)教程中下載最終的 Playground拥诡。Swift 4.2 在 Swift 4.1 諸多特性的基礎(chǔ)上進(jìn)一步做了改進(jìn),而且為了2019 年初 Swift 5 的 ABI 穩(wěn)定做好準(zhǔn)備氮发】嗜猓可以從 Swift CHANGELOG 或者 Swift standard library diffs 中了解更多關(guān)于這個(gè)版本的改變。也可以從 Swift Evolution 中看出 Swift 5 的改變爽冕。你可以給正在審查的提案提交反饋或者自己提交一個(gè)提案仇祭。到目前為止對(duì) Swift 4.2 有什么喜歡或者不喜歡的地方【被可以在論壇中參與討論乌奇。