- 蘋果公司在 3.29 正式釋出了正式版的
和Xcode 9.3
, 讓我們看看Swift 4.1
帶來了哪些新功能和新亮點Swift 4.1
- 測試需要Xcode9.3, 請確定你的Xcode是最新的9.3版本
-
與Swift 4.1
是源代碼相容的,是以如果你已經使用Swift 4.0
中的Xcode
将你的項目遷移到Swift Migrator
,那麼新特性不會破壞你的代碼Swift 4.0
- 下面在
下建立一個Xcode9.3
工程, 測試我們的代碼Playground
條件一緻性(Conditional Conformance)
- 條件一緻性使類型參數滿足特定條件的泛型類型的協定一緻性 [ SE-0143 ]
- 在Swift 4中,如果數組、字典或者可選類型的元素類型遵循
,你是可以在數組之間、字典之間和可選類型之間進行比較的, 如下示例:Equatable
// Int類型的數組
let arr1 = [, , ]
let arr2 = [, , ]
print(arr1 == arr2)
// 比較value值為Int的字典
let dic1 = ["age": , "score": ]
let dic2 = ["age": , "score": ]
print(dic1 == dic2)
// 比較Int?
let age1 = dic1["age"]
let age2 = dic2["age"]
print(age1 == age2)
/// 以上輸出結果都是: true
複制代碼
這裡如果我們把
Int
都換成
Int?
類型, 在
Swift4.0
中是不能編譯通過的, 如下:
// Int類型的數組
let arr1: [Int?] = [, , ]
let arr2: [Int?] = [, , ]
print(arr1 == arr2)
// 比較value值為Int的字典
let dic1: [String: Int?] = ["age": , "score": ]
let dic2: [String: Int?] = ["age": , "score": ]
print(dic1 == dic2)
// 比較Int?
let age1 = dic1["age"]
let age2 = dic2["age"]
print(age1 == age2)
複制代碼
- 在這些執行個體中, 我們用
測試相等性, 在Swift4.0中,==
類型遵循Int
協定, 可以比較, 但是Equatable
類型卻沒有遵循Int?
協定Equatable
- 但是在Swift4.1中, 完美的解決了這個問題, 上述代碼可比那已認證, 且都輸出:
true
- 在
中Swift 4.0
之間可以直接對比,但是[Set<Int>]
不能。現在[[Int]]
中,Swift 4.1
也能直接對比[[Int]]
- 總的來說,
的Swift 4.1
、Array
和Dictionary
,隻要他們的元素都遵循了Optional
和Equatable
,那麼他們也遵循Hashable
和Equatable
Hashable
合成 Equatable
和 Hashable
Equatable
Hashable
- 如果對象相等,則這兩個對象的
值一定相等hash
- 如果兩個對象
值相等,這兩個對象不一定相等。hash
-
中Swift
一定是Hashable
,因為前者繼承了後者。 在Equatable
中,若遵循Swift 4
協定的時候,我們必須實作Equatable
協定的Equatable
方法,==
協定如下:Equatable
public protocol Equatable {
/// Returns a Boolean value indicating whether two values are equal.
///
/// Equality is the inverse of inequality. For any values `a` and `b`,
/// `a == b` implies that `a != b` is `false`.
///
/// - Parameters:
/// - lhs: A value to compare.
/// - rhs: Another value to compare.
public static func == (lhs: Self, rhs: Self) -> Bool
}
複制代碼
在Swift4.0中, 必須實作
Equatable
協定的方法
struct Name: Equatable {
var name1 = "name1"
var name2 = "name2"
static func == (lhs: Name, rhs: Name) -> Bool {
return lhs.name1 == rhs.name1 &&
lhs.name2 == rhs.name2
}
}
複制代碼
在
Swift 4.1
,隻需要加上
Equatable
即可, 不需要實作任何協定方法
struct Name: Equatable {
var name1 = "name1"
var name2 = "name2"
}
複制代碼
JSON
編碼時支援 Camel Case
和 Snake Case
之間的轉換
JSON
Camel Case
Snake Case
-
引入了Swift 4.0
,但是有個麻煩的問題:如果Codable
資料的JSON
命名格式是key
的話,我們必須建立自己的snake_case
來告訴蘋果怎麼轉換。在CodingKeys
中Swift 4.0
- 但是在
中,蘋果給Swift 4.1
引入了一個屬性JSONDecoder
;對應的keyDecodingStrategy
引入了一個屬性JSONEncoder
。這樣我們就不需要設定定義keyEncodingStrategy
了。隻需要在CodingKeys
的時候把decoding
設定為keyDecodingStrategy
;在.convertFromSnakeCase
的時候把encoding
設定為keyEncodingStrategy
.convertToSnakeCase
- 下面是分别針對數組/字典/集合的解析形式
struct Student: Codable, Hashable {
let firstName: String
let averageGrade: Int
}
let cosmin = Student(firstName: "Cosmin", averageGrade: )
let george = Student(firstName: "George", averageGrade: )
let encoder = JSONEncoder()
// Encode an Array of students
let students = [cosmin, george]
do {
try encoder.encode(students)
} catch {
print("Failed encoding students array: \(error)")
}
// Encode a Dictionary with student values
let studentsDictionary = ["Cosmin": cosmin, "George": george]
do {
try encoder.encode(studentsDictionary)
} catch {
print("Failed encoding students dictionary: \(error)")
}
// Encode a Set of students
let studentsSet: Set = [cosmin, george]
do {
try encoder.encode(studentsSet)
} catch {
print("Failed encoding students set: \(error)")
}
// Encode an Optional Student
let optionalStudent: Student? = cosmin
do {
try encoder.encode(optionalStudent)
} catch {
print("Failed encoding optional student: \(error)")
}
複制代碼
Hashable Index Types
(哈希化索引)
Hashable Index Types
擴充
Key-path
表達式在标準庫中的使用範圍。讓标準庫中所有的索引類型都符合
Hashable
協定,這樣,
[Int]
、
String
和所有其它标準集合使用
key-path
下标時,表現都是一樣的
let swiftString2 = "one two three"
let charact1 = \String.[swiftString2.startIndex]
print(swiftString2[keyPath: charact1])
let arr = [, , , ]
let value2 = \[Int].[]
print(arr[keyPath: value2])
//輸出結果:
o
複制代碼
compactMap
的用法
compactMap
在
Swift 4.0
中,我們經常使用
flatMap
來過濾
nil
,也可以進行降維操作, 詳情可參考Swift函數式程式設計之進階用法
let arr = [1, 2, nil, 3, 4, nil]
let arr1 = arr.flatMap({ $0 })
print(arr1)
//這樣使用會有類似的警告
'flatMap' is deprecated: Please use compactMap(_:) for the case where closure returns an optional value
Use 'compactMap(_:)' instead
//Swift4.1中的用法
let arr = [1, 2, nil, 3, 4, nil]
let arr2 = arr.compactMap({ $0 })
print(arr2)
複制代碼
主要是因為在中
Swift4.0
有很多重載, 可能會引起歧義, 是以在
flatMap
中把
Swift4.1
重命名為
flatMap
compactMap
除了協定中的 weak 和 unowned。
- 當你在
協定中定義了兩個屬性Tune
和key
,pitch
可能為pitch
, 是以你在協定中可以用nil
修飾weak
- 但是如果在協定本身中定義的話,
和weak
都沒有實際意義, 是以在unowned
中就已經去掉了這些關鍵字, 并且在協定中使用這些關鍵字将會爆出警告Swift4.1
class Key {}
class Pitch {}
// Swift 4
protocol Tune {
unowned var key: Key { get set }
weak var pitch: Pitch? { get set }
}
// Swift 4.1
protocol Tune {
var key: Key { get set }
var pitch: Pitch? { get set }
}
複制代碼
UnsafeMutableBufferPointer
的改變
UnsafeMutableBufferPointer
//Swift4.0
let buffer = UnsafeMutableBufferPointer<Int>(start: UnsafeMutablePointer<Int>.allocate(capacity: ),
count: )
let mutableBuffer = UnsafeMutableBufferPointer(start: UnsafeMutablePointer(mutating: buffer.baseAddress),
count: buffer.count)
//Swift4.1
let buffer = UnsafeMutableBufferPointer<Int>.allocate(capacity: )
let mutableBuffer = UnsafeMutableBufferPointer(mutating: UnsafeBufferPointer(buffer))
複制代碼
相對的改變,
Swift4.0
這點改變鍵值太微不足道了, 傳說中
Swift4.1
的
Swift5
會趨于穩定, 但是估計改變可能也是非常大的, 坐等
API
釋出...
Swift5
參考文檔
- What’s New in Swift 4.1?