1掌唾、Bool.toggle
struct Layer {
var isHidden = false
}
struct View {
var layer = Layer()
}
var view = View()
// Before:
view.layer.isHidden = !view.layer.isHidden
view.layer.isHidden
// Now:
view.layer.isHidden.toggle()
2面哼、對Sequence and Collection 新增一些方法
-
新增
allSatisfy
會根據(jù)closure中的謂詞進行判斷,只有全部為true
才會返回true
let digits = 0...9
let areAllSmallerThanTen = digits.allSatisfy { $0 < 10 }
areAllSmallerThanTen // true
let areAllEven = digits.allSatisfy { $0 % 2 == 0 }
areAllEven // false
-
新增
last(where:)
從后往前開始遍歷,直到找到滿足條件的第一個元素红淡,返回改元素
let digits = 0...9
let lastEvenDigit = digits.last { $0 % 2 == 0 }
lastEvenDigit //8
-
新增
lastIndex(where:)
從后往前開始遍歷,直到找到滿足條件的第一個元素降铸,返回其Index
let text = "Vamos a la playa"
let lastWordBreak = text.lastIndex(where: { $0 == "l" })
let lastWord = lastWordBreak.map { text[text.index(after: $0)...] }
lastWord // aya
-
新增
lastIndex(of:)
從后往前遍歷在旱,直到輸入的值和數(shù)組中的值相等,返回其Index
text.lastIndex(of: "l") == lastWordBreak //true
-
移除
index(of:)
和index(where:)
推掸,分別用firstIndex(of:)
和firstIndex(where:)
代替
let text = "Vamos a la playa"
let firstWordBreak = text.firstIndex(where: { $0 == " " })
let firstWord = firstWordBreak.map { text[..<$0] }
firstWord //Vamos
-
新增
removeAll(where:)
刪除滿足條件的元素
var numbers = Array(1...10)
numbers.removeAll(where: { $0 % 2 == 0 })
numbers // 1 3 5 7 9
3桶蝎、新增協(xié)議 CaseIterable
協(xié)議大多用在enum
中,添加了一個allCases
屬性谅畅,該屬性是一個collection
3.1 簡單使用
enum Terrain: CaseIterable {
case water
case forest
case desert
case road
}
Terrain.allCases // [water,forest,desert,road]
Terrain.allCases.count // 4
3.2 這個屬性可以用在TableView Sections中
enum TableSection: Int, CaseIterable {
/// The section for the search field
case search = 0
/// Featured content
case featured = 1
/// Regular content cells
case standard = 2
}
func numberOfSections(in tableView: UITableView) -> Int {
return TableSection.allCases.count
}
override func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let section = TableSection.allCases[indexPath.section]
switch section {
case .search: ...
case .featured: ...
case .standard: ...
}
}
3.3 還可以在一個Enum
中的case引用另外一個Enum
登渣,但是必須重寫allCases
enum Intensity: CaseIterable {
case light
case medium
case hard
}
enum Workout {
case resting
case running(Intensity)
case cycling(Intensity)
}
extension Workout: CaseIterable {
static var allCases: [Workout] {
return [.resting]
+ Intensity.allCases.map(Workout.running)
+ Intensity.allCases.map(Workout.cycling)
}
}
Workout.allCases
/* .resting
.running(.light)
.running(.medium)
.running(.hard)
.cycling(.light)
.cycling(.medium)
.cycling(.hard) */
Workout.allCases.count // 7
3.4 為了防止在自定義的allCases
中漏掉新增的case
,可以在內(nèi)部新增一個方法毡泻,用于提示我們需要做一些改變
extension Workout: CaseIterable {
static var allCases: [Workout] {
/// Dummy function whose only purpose is to produce
/// an error when a new case is added to Workout. Never call!
@available(*, unavailable, message: "Only for exhaustiveness checking, don't call")
func _assertExhaustiveness(of workout: Workout, never: Never) {
switch workout {
case .resting,
.running(.light), .running(.medium), .running(.hard),
.cycling(.light), .cycling(.medium), .cycling(.hard):
break
}
}
return [.resting]
+ Intensity.allCases.map(Workout.running)
+ Intensity.allCases.map(Workout.cycling)
}
}
這樣子當我們新增了case
胜茧,就會提示我們需要進行適配了。
這個動作就像我們在做單元測試一樣仇味,所以當新增了case
呻顽,務(wù)必適配allCases
3.5 在其他的類型中使用 CaseInterable
協(xié)議,
除了普通的enum
有著默認的實現(xiàn),其他的都需要自己去重寫allCases
Bool
extension Bool: CaseIterable {
public static var allCases: [Bool] {
return [false, true]
}
}
Bool.allCases // → [false, true]
UInt8
extension UInt8: CaseIterable {
public static var allCases: ClosedRange<UInt8> {
return .min ... .max
}
}
UInt8.allCases.count // → 256
這里官方還給出了建議丹墨,就是如果生成的時候很消耗資源廊遍,請考慮使用lazy
,例如:
UInt8.allCases.lazy.count
3.6 如果allCases中有optional贩挣,那么必須定義 public typealias AllCases = [?],否則編譯器會報錯
extension Optional: CaseIterable where Wrapped: CaseIterable {
public typealias AllCases = [Wrapped?]
public static var allCases: AllCases {
return [nil] + Wrapped.allCases.map { $0 }
}
}
enum CompassDirection: CaseIterable {
case north, south, east, west
}
CompassDirection.allCases // → [north, south, east, west]
CompassDirection.allCases.count // → 4
CompassDirection?.allCases // → [nil, north, south, east, west]
CompassDirection?.allCases.count // → 5
4昧碉、統(tǒng)一隨機數(shù)的接口
4.1數(shù)字類型
Int.random(in: 1...1000)
UInt8.random(in: .min ... .max)
Double.random(in: 0..<1)
4.2 Bool
Bool.random()
4.3 collection(集合)
- 隨機取一個元素
let emotions = "??????????????????"
let randomEmotion = emotions.randomElement()!
-
打亂集合
-
let
let numbers = 1...10 let shuffled = numbers.shuffled()
-
var
var mutableNumbers = Array(numbers) // Shuffles in place mutableNumbers.shuffle()
-
4.4 重寫隨機數(shù)生成器
/// A dummy random number generator that just mimics `SystemRandomNumberGenerator`.
struct MyRandomNumberGenerator: RandomNumberGenerator {
var base = SystemRandomNumberGenerator()
mutating func next() -> UInt64 {
// 如果有特殊的需求,就這這里進行處理
return base.next()
}
}
var customRNG = MyRandomNumberGenerator()
Int.random(in: 0...100, using: &customRNG)
4.5 為enum
添加隨機函數(shù)
enum Suit: String, CaseIterable {
case diamonds = "?"
case clubs = "?"
case hearts = "?"
case spades = "?"
static func random<T: RandomNumberGenerator>(using generator: inout T) -> Suit {
// Using CaseIterable for the implementation
return allCases.randomElement(using: &generator)!
}
static func random() -> Suit {
// 如果不需要系統(tǒng)的隨機數(shù)生成揽惹,就把這個類型替換
var rng = SystemRandomNumberGenerator()
return Suit.random(using: &rng)
}
}
let randomSuit = Suit.random()
randomSuit.rawValue
5被饿、重新設(shè)計了Hashable
減少hash值碰撞
栗子:
struct Point {
var x: Int { didSet { recomputeDistance() } }
var y: Int { didSet { recomputeDistance() } }
/// Cached. Should be ignored by Equatable and Hashable.
private(set) var distanceFromOrigin: Double
init(x: Int, y: Int) {
self.x = x
self.y = y
self.distanceFromOrigin = Point.distanceFromOrigin(x: x, y: y)
}
private mutating func recomputeDistance() {
distanceFromOrigin = Point.distanceFromOrigin(x: x, y: y)
}
private static func distanceFromOrigin(x: Int, y: Int) -> Double {
return Double(x * x + y * y).squareRoot()
}
}
extension Point: Equatable {
static func ==(lhs: Point, rhs: Point) -> Bool {
// Ignore distanceFromOrigin for determining equality
return lhs.x == rhs.x && lhs.y == rhs.y
}
}
extension Point: Hashable {
func hash(into hasher: inout Hasher) {
// Ignore distanceFromOrigin for hashing
hasher.combine(x)
hasher.combine(y)
}
}
let p1 = Point(x: 3, y: 4)
p1.hashValue
let p2 = Point(x: 4, y: 3)
p2.hashValue
assert(p1.hashValue != p2.hashValue)
如果類/結(jié)構(gòu)體中的數(shù)據(jù)類型都是一種,比如Int
搪搏,在采用return x ^ y
這種算法狭握,就很容易發(fā)生碰撞,所以我們在重寫hash
的時候一定要注意這個東西疯溺,要在性能和碰撞之間做平衡论颅。
6哎垦、動態(tài)映射的修改
func isEncodable(_ value: Any) -> Bool {
return value is Encodable
}
// This would return false in Swift 4.1
let encodableArray = [1, 2, 3]
isEncodable(encodableArray)
// Verify that the dynamic check doesn't succeed when the conditional conformance criteria aren't met.
struct NonEncodable {}
let nonEncodableArray = [NonEncodable(), NonEncodable()]
isEncodable(nonEncodableArray)//false
assert(isEncodable(nonEncodableArray) == false)
7、擴展中的合成一致性
enum Either<Left, Right> {
case left(Left)
case right(Right)
}
// No code necessary
extension Either: Equatable where Left: Equatable, Right: Equatable {}
extension Either: Hashable where Left: Hashable, Right: Hashable {}
Either<Int, String>.left(42) == Either<Int, String>.left(42) //true
8恃疯、Range的修改
官方說道:CountableRange
和CountableClosedRange
還存在漏设,但是不應(yīng)該在之后的代碼中使用到他們了,這個是為了兼容之前的代碼
let integerRange: Range = 0..<5
// integer是一個collection今妄,所以可以調(diào)用map方法
let integerStrings = integerRange.map { String($0) }
integerStrings
let floatRange: Range = 0.0..<5.0
// 以為float不是一個collection郑口,所以不能調(diào)用map方法
//floatRange.map { String($0) } // error!
9、新增@dynamicMemberLookup
允許我們運行時盾鳞,動態(tài)查找屬性犬性,可以用來修飾class/struct/protocol/enum
使用@dynamicMemberLookup
需要重寫如下代碼:
subscript(dynamicMember input: String) -> XX {
get {
guard let value = getenv(name) else { return nil }
return xx
}
nonmutating set {
if let value = newValue {
setenv(name, value, /*overwrite:*/ 1)
} else {
unsetenv(name)
}
}
}
@dynamicMemberLookup
struct Uppercaser {
subscript(dynamicMember input: String) -> String {
return input.uppercased()
}
}
Uppercaser().hello // → "HELLO"
// You can type anything, as long as Swift accepts it as an identifier.
Uppercaser().k?seso?e // → "K?SESOSSE"
10、guard let self = self
喜大奔普終于不用寫
guard let `self` = self ...
11腾仅、if let self = self { … }
也不用這樣子寫啦
if let weakself = self { … }
12乒裆、支持#warning
和#error
啦
-
error
#if MYLIB_VERSION < 3 && os(macOS) #error("MyLib versions < 3 are not supported on macOS") #endif
-
warning
func doSomethingImportant() { #warning("TODO: missing implementation") } doSomethingImportant()
13、#if compiler version directive
#if compiler(>=4.2)
print("Using the Swift 4.2 compiler or greater in any compatibility mode")
print("swift編譯器大于等于4.2") //菜雞翻譯推励,如果不準鹤耍,煩請告知
#endif
#if swift(>=4.2)
print("Using the Swift 4.2 compiler or greater in Swift 4.2 or greater compatibility mode")
print("使用swift4.2編譯器編譯swift大于/等于4.2的版本") //菜雞翻譯,如果不準验辞,煩請告知
#endif
#if compiler(>=5.0)
print("Using the Swift 5.0 compiler or greater in any compatibility mode")
print("swift編譯器大于等于5.0") //菜雞翻譯稿黄,如果不準,煩請告知
#endif
14受神、MemoryLayout
中新增offset(of:)
方法
struct Point {
var x: Float
var y: Float
var z: Float
}
MemoryLayout<Point>.offset(of: \Point.x) // 0
MemoryLayout<Point>.offset(of: \Point.y) // 4
MemoryLayout<Point>.offset(of: \Point.z) // 8
官方解釋:
許多圖形和數(shù)學庫接受任意輸入格式的輸入數(shù)據(jù)抛猖,用戶在設(shè)置輸入緩沖區(qū)時必須向API描述。例如鼻听,OpenGL允許您使用一系列glVertexAttribPointer
API 調(diào)用來描述頂點緩沖區(qū)的布局财著。在C中,您可以使用標準offsetof
宏來獲取結(jié)構(gòu)中字段的偏移量撑碴,允許您使用編譯器對類型布局的了解來填充這些函數(shù)調(diào)用:
//我們的一個頂點條目的布局
struct MyVertex {
float position [ 4 ];
float 正常 [ 4 ];
uint16_t texcoord [ 2 ];
};
enum MyVertexAttribute {Position撑教,Normal,TexCoord};
glVertexAttribPointer(Position醉拓,4伟姐,GL_FLOAT,GL_FALSE亿卤,
sizeof(MyVertex)愤兵,(void *)offsetof(MyVertex,position));
glVertexAttribPointer(Normal排吴,4秆乳,GL_FLOAT,GL_FALSE,
sizeof(MyVertex)屹堰,(void *)offsetof(MyVertex肛冶,normal));
glVertexAttribPointer(TexCoord,2扯键,GL_UNSIGNED_BYTE睦袖,GL_TRUE,
sizeof(MyVertex)荣刑,(void *)offsetof(MyVertex馅笙,texcoord));
目前offsetof
在Swift中沒有相同的功能,因此這些API的用戶必須在C中編寫代碼的這些部分嘶摊,或者在頭腦中執(zhí)行Swift內(nèi)存布局延蟹,如果他們更改了數(shù)據(jù)布局或Swift评矩,則容易出錯叶堆。編譯器實現(xiàn)更改其布局算法(它保留權(quán)利)。
15斥杜、新增兩個修飾符@inlinable
和 @usableFromInline
-
@inlinable
: 開發(fā)者可以將一些公共功能注釋為@inlinable
虱颗。這給編譯器提供了優(yōu)化跨模塊邊界的泛型代碼的選項
@inlinable public func allEqual<T>(_ seq: T) -> Bool
where T : Sequence, T.Element : Equatable {
var iter = seq.makeIterator()
guard let first = iter.next() else { return true }
func rec(_ iter: inout T.Iterator) -> Bool {
guard let next = iter.next() else { return true }
return next == first && rec(&iter)
}
return rec(&iter)
}
-
usableFromInline
: 使用@usableFromInline
在你的“ABI-public”庫中進行某些內(nèi)部聲明,允許它們在可鏈接函數(shù)中使用蔗喂。public class C { @usableFromInline internal class D { @usableFromInline internal func f() {} @inlinable internal func g() {} } }
16忘渔、withUnsafePointer(to::) 和 withUnsafeBytes(of::)
withUnsafePointer
和withUnsafeBytes
通過指針提供對變量和屬性的內(nèi)存表示的臨時范圍訪問。它們當前只接受inout
參數(shù)缰儿,這使得處理不可變值的內(nèi)存表示比它應(yīng)該做的更尷尬和更低效畦粮,需要復(fù)制:
let x = 1 + 6
var x2 = x
let value = withUnsafeBytes(of: &x2) {
ptr in
return (ptr[0] + ptr[1])
}
value // 7
其內(nèi)部實現(xiàn)如下:
public func withUnsafePointer<T, Result>(
to value: /*borrowed*/ T,
_ body: (UnsafePointer<T>) throws -> Result
) rethrows -> Result
public func withUnsafeBytes<T, Result>(
of value: /*borrowed*/ T,
_ body: (UnsafeRawBufferPointer) throws -> Result
) re