swift4.2新特性
CaseInterable
协议
在4.2之前我们想打印枚举里面所有的case只能自己通过以下方式去实现:
/// swift4.2之前,错误示例
enum Gait {
case walk
case trot
case canter
case gallop
static var allCases: [Gait] = [.walk, .trot, .canter, .gallop]
}
for gait in Gait.allCases {
print(gait)
}
这样每次新增和删除一个case都要去维护allCases这个数组,这样造成了诸多不便,在Swift 4.2
中新增了CaseIterable
协议,通过遵循这个协议,会自动生成allCases
,例如:
enum Gait: CaseIterable {
case walk
case trot
case canter
case gallop
case jog
}
for gait in Gait.allCases {
print(gait)
}
这样我们就不用去自己维护allCases
这个集合了
条件一致性
条件一致性是在Swift 4.1
引入的,例如在Swift 4.0
的时候下面代码运行会报错:
let animals = ["cat", "dog", "weasel"]
animals.contains("dog") // OK
let coins = [[1, 2], [3, 6], [4, 12]]
/// Error because the element type [Int] is not equatable
coins.contains([3, 6])
然而在Swift 4.1
之后类似这种的问题得到了解决:
extension Array: Equatable where Element: Equatable {
static func ==(lhs: Array<Element>, rhs: Array<Element>) -> Bool {
let count = lhs.count
if count != rhs.count { return false } for x in 0..<count {
if lhs[x] != rhs[x] { return false } }
return true
}
}
let coins = [[1, 2], [3, 6], [4, 12]]
coins.contains([3, 6]) // This now works!
类似的这种一致性有
Equatable
、Hashable
、Encodable
和Decodable
优化Equatable
和Hashable
例如在Swift 4.1
需要实现一下代码的功能需要这样写:
enum Either<Left, Right> {
case left(Left)
case right(Right)
}
extension Either: Equatable where Left: Equatable, Right: Equatable {
static func == (a: Either<Left, Right>, b: Either<Left, Right>) -> Bool {
switch (a, b) {
case (.left(let x), .left(let y)):
return x == y
case (.right(let x), .right(let y)):
return x == y
default:
return false
}
}
}
extension Either: Hashable where Left: Hashable, Right: Hashable {
var hashValue: Int {
switch self {
case .left(let x):
return x.hashValue
case .right(let x):
return x.hashValue
}
}
}
var mySet = Set<Either<Int, String>>()
但是在Swift 4.2
中不用写以上代码了,帮你默认实现了:
enum Either<Left, Right> {
case left(Left)
case right(Right)
}
extension Either: Equatable where Left: Equatable, Right: Equatable { }
extension Either: Hashable where Left: Hashable, Right: Hashable { }
var mySet = Set<Either<Int, String>>()
更加安全的Hashable
在Swift 4.1
我们遵循Hashable
协议时需要这样写:
struct City {
let name: String
let state: String
/// 城市不用比较人口
let population: Int
}
extension City: Equatable {
static func ==(a: City, b: City) -> Bool {
return a.name == b.name && a.state == b.state
}
}
extension City: Hashable {
var hashValue: Int {
return name.hashValue ^ state.hashValue
}
}
在Swift 4.2
引入了一个新的Hasher
结构,它提供了一个随机播种的通用散列函数:
struct City {
let name: String
let state: String
/// 城市不用比较人口
let population: Int
}
extension City: Hashable {
func hash(into hasher: inout Hasher) {
name.hash(into: &hasher)
state.hash(into: &hasher)
}
}
Hasher中的hash合并算法可以有效的平衡hash的质量和性能,还可以低于阻断式服务攻击,它使用了App启动时生成的随机预处理种子,因此在
Swift 4.2
中每次启动App时的hash值不一样了,会导致之前一些有序字典或者集合变的无序,当然我们也可以添加环境变量( SWIFT_DETERMINISTIC_HASHING=1)来关掉这个功能
随机数生成
之前的随机数用法:
#if os(iOS) || os(tvOS) || os(watchOS) || os(macOS)
return Int(arc4random())
#else
return random() // or Int(rand())
#endif
// Return random number in the range 1...6
func diceRoll() -> Int {
return 1 + (arc4random() % 6)
}
Swift 4.2
中:
let randomIntFrom0To10 = Int.random(in: 0 ..< 10)
let randomFloat = Float.random(in: 0 ..< 1)
let greetings = ["hey", "hi", "hello", "hola"]
print(greetings.randomElement()!)
let randomlyOrderedGreetings = greetings.shuffled()
print(randomlyOrderedGreetings)
还可以自定义随机生成器,遵循
RandomNumberGenerator
,具体用法在这里就不详细阐述了
检查平台条件
在之前检测平台时,代码如下:
#if os(iOS) || os(watchOS) || os(tvOS)
import UIKit
...
#else
import AppKit
...
#endif
在Swift 4.2
中:
#if canImport(UIKit)
import UIKit
...
#else
import AppKit
...
#endif
检测是否是模拟器:
#if hasTargetEnvironment(simulator)
...
#else
#warning("We need to test this better")
...
#endif
#warning
和#error
编译指令
#warning("这是一个警告")
#error("这是一个错误")
removeAll(where:)
/// removeAll(where:)
var pythons = ["John", "Michael", "Graham", "Terry", "Eric", "Terry"]
pythons.removeAll { $0.hasPrefix("Terry") }
print(pythons)
/// filter
var python2 = ["John", "Michael", "Graham", "Terry", "Eric", "Terry"]
python2 = python2.filter { !$0.hasPrefix("Terry") }
print(python2)
allSatisfy()
//判断数组的所有元素是否全部大于85
let scores = [86, 88, 95, 92]
//返回一个BOOL
let passed = scores.allSatisfy({ $0 > 85 })
print(passed)
//输出: true
toggle()
var isSwift = true
//toggle函数没有返回值
isSwift.toggle()
print(isSwift)
last(where:)和
lastIndex(where:)
//获取满足条件的数组中的第一个值
let a = [20, 30, 10, 40, 20, 30, 10, 40, 20]
print(a.first(where: { $0 > 25 }))
print(a.index(where: { $0 > 25 }))
print(a.index(of: 10))
//输出:
30
1
2
//在Swift4.1中
print((a.reversed().index(where: { $0 > 25 })?.base).map({ a.index(before: $0) }))
//输出: 7
//Swift 4.2
//获取满足条件的元素
print(a.last(where: { $0 > 25 })) //40
//获取满足条件的元素的索引
print(a.lastIndex(where: { $0 > 25 })) //7