[译]What’s New in Swift5?

原文链接:What’s New in Swift 5?

Swift 5 最终伴随着Xcode 10.2一起到来。这次发布带来了 ABI 稳定性 并且改进了语言,一些期待已久的特性。来看看这些新东西吧!

在这篇教程,你将学习Swift 5的一些重大改变。使用 Swift 5 需要Xcode 10.2,所以在开始前请确认你安装了它。

Getting Started

Swift 5 源兼容(source compatible) Swift 4.2,但是它不二进制兼容(binary compatible)更早的Swift 发行版。不过由于 ABI 稳定性,未来发行版将与Swift 5二进制兼容。

ABI 稳定性让使用不同 Swift版本编译的应用程序和库之间的二进制兼容性。Swift 标准库和运行时嵌入在 OS 中,因此应用程序不会在任何平台上分发自己的库副本。这导致更好的 工具解耦(tool decoupling) 和 OS 集成(OS integration)。

你还需要 ABI 稳定性来分发跨多个 Swift 版本的二进制frameworks(binary frameworks )。这需要模块格式稳定性(module format stability),稳定模块包含编译器的框架公开接口表示的模块文件。

你可以在本教程的每个章节找到 Swift Evolution像 [SE-0001] 这样的提议号。你可以浏览每个提案的链接来详细了解每项新变化。

最好是在 playground 中尝试这些新特性。

启动 Xcode 10.2,选择 File ▸ New ▸ Playground,在 platform 项选择 iOS ,template 选 Blank。命名和保存位置随意,你开心就好。开始吧!

需要快速复习一下 Swift 4.2 重点,查看 Swift 4.2教程。What’s New in Swift 4.2?

Language Improvements

Swift 5有很多语言特性,如 动态可调用类型(dynamic callable types),处理未来的枚举(handling future enumeration)等等.

Testing Integer Multiples

在Swift 4.2中,你可以使用余数运算符确定数字是否是另一个的倍数:

let firstNumber = 4
let secondNumber = 2
if secondNumber != 0 && firstNumber % secondNumber == 0 {
  print("\(secondNumber) * \(firstNumber / secondNumber) = \(firstNumber)")
}

这段代码如何工作:

  1. 确认 secondNumber 不为 0.
  2. 确认 firstNumber除以secondNumber余 0.
  3. 执行除法操作。

你必须确认 secondNumber 不为 0,否则 % 操作将抛出错误。

Swift 5 通过给BinaryInteger添加了 isMultiple(of:) 方法简化了这一操作SE-0225:

if firstNumber.isMultiple(of: secondNumber) {
  print("\(secondNumber) * \(firstNumber / secondNumber) = \(firstNumber)")
}

即使你传入 0 作为参数,isMultiple(of:)依然可以工作,而且是代码更加简洁明了。

Escaping Raw Strings

Swift 4.2使用转义符来表示字符串中的反斜杠和引号:

let escape = "You use escape sequences for \"quotes\"\\\"backslashes\" in Swift 4.2."
let multiline = """
                You use escape sequences for \"\"\"quotes\"\"\"\\\"\"\"backslashes\"\"\"
                on multiple lines
                in Swift 4.2.
                """

Swift 5添加了 raw strings 。你可以在字符串的开头和结尾添加#,这样你就可以使用反斜杠和引号而不会出现问题:

let raw = #"You can create "raw"\"plain" strings in Swift 5."#  
let multiline = #"""  
                You can create """raw"""\"""plain""" strings  
                on multiple lines  
                in Swift 5.  
                """#

在原始字符串中使用字符串插值时,必须在反斜杠后使用 # 号:

let track = "Nothing Else Matters"
print(#"My favorite tune\song is \#(track)."#)

在某些情况下,你需要在字符串的开头和结尾使用多个#:

let hashtag = ##"You can use the Swift "hashtag" #swift in Swift 5."##

在上面的代码中,你在开头添加##在 hashtag结尾添加 #,这样可以在字符串中表示#。字符串开头使用的 # 数量必须与其末尾的数量相同。

在Swift 4.2中,你在正则表达式中转义反斜杠,如下所示:

// 1
let versions = "3 3.1 4 4.1 4.2 5"
let range = NSRange(versions.startIndex..., in: versions)
// 2
let regex = try! NSRegularExpression(pattern: "\\d\\.\\d")
// 3
let minorVersions = regex.matches(in: versions, range: range)
// 4
minorVersions.forEach { print(versions[Range($0.range, in:  versions)!]) }
  1. 声明 versions定义一个 range 覆盖整个字符串
  2. 定义一个匹配 versions 中所有次要Swift发行版(minor Swift releases)的正则表达式。
  3. 使用matches(in:options:range:)确定次要发行版的rangs 。
  4. 使用 rangs 从 versions中获得次要发行版。

Swift 5使用 raw strings 简化正则表达式:

let regex = try! NSRegularExpression(pattern: #"\d\.\d"#)

在上述代码中,你定义 regex用的反斜杠少了一半,因为你不需要在 raw strings 中转义反斜杠。

No extra backslashes in regular expressions!

需要了解更多的关于正则表达式如何在Swift中使用,请看这篇教程: An Introduction to Regular Expressions

Using New Character Properties

在处理characters时,Swift 4.2 需要一个解决方法来处理一个常见的需求:

let id = "ID10"
var digits = 0
id.forEach { digits += Int(String($0)) != nil ? 1 : 0 }
print("Id has \(digits) digits.")  

在此代码中,首先将每个字符转换为String,然后再转换为Int,以确定 id 有多少数字。

但是,Swift 5为Character添加了属性,使 characters 更易用SE-0221:


1  


id.forEach { digits += $0.isNumber ? 1 : 0 }  

在上述情况中,你使用 isNumber 来检查每个字符是否都是数字。查看提案来寻找其他你能使用的属性。

Using New Unicode Scalar Properties

在 Swift4.2 中,你为Unicode scalars 实现文本处理算法,如下所示:

let username = "bond007"
var letters = 0
username.unicodeScalars.forEach {
 letters += (65...90) ~= $0.value || (97...122) ~= $0.value ? 1 : 0
}
print("Username has \(letters) letters.")

在此代码中,您通过检查每个字符的 unicode scalars是代表小写字母还是大写字母来计算用户名的字母数。

Swift 5为 unicode scalars 添加了属性,简化了文本处理SE-0211:

username.unicodeScalars.forEach { letters += $0.properties.isAlphabetic ? 1 : 0 }

在此代码中,你使用isAlphabetic 检查每个字符是否为数字。链接的提案将显示你可以检查的所有属性。

Removing Subsequences

Swift 4.2 使用下列方法 从 Sequence customization points返回 SubSequence:

extension Sequence {
    func remove(_ s: String) -> SubSequence {
        guard let n = Int(s) else {
            return dropLast()
        }
        return dropLast(n)
    }
}

let sequence = [5, 2, 7, 4]
sequence.remove("2") // [5, 2]
sequence.remove("two") // [5, 2, 7]  

上述情况中,如果 s 是一个 Int那么 remove(_:)将从 sequence移除倒数的 n 个元素,否则移除最后一个元素。

Swift 5用 sequences 中的具体类型替换SubSequence

extension Sequence {
    func remove(_ s: String) -> [Element] {
        guard let n = Int(s) else {
            return dropLast()
        }
        return dropLast(n)
    }
}

在这段代码中,remove(_:) 跟随 dropLast() 和 dropLast(_:) 一样返回 [Element]类型。

Dictionary Updates

Swift 5为 Dictionary 带来了许多期待已久的改进:

Compacting Dictionaries

Swift 4.2使用 mapValues,filter和 reduce来从过滤 Dictionary 中的 nil 值:

let students = ["Oana": "10", "Nori": "ten"]
let filterStudents = students.mapValues(Int.init)
    .filter { $0.value != nil }
    .mapValues { $0! }
let reduceStudents = students.reduce(into: [:]) { $0[$1.key] = Int($1.value) }

上述代码使用 mapValues加上mapValues或者 reduce 来认定 students中成绩有效的学生。
两种方法都需要多次通过 dictionary而且使代码复杂化。

Swift 5 使用 compactMapValues(_:)来高效解决[[SE-0218]](https://github.com/apple/swift-evolution/blob/master/proposals/0218-introduce-compact-map-values.md):

let mapStudents = students.compactMapValues(Int.init)

使用更少的代码行数完成了相同的事情,整洁!

Renaming Dictionary Literals

Swift 4.2使用 DictionaryLiteral来来声明一个Dictionary:
let pets: DictionaryLiteral = ["dog": "Sclip", "cat": "Peti"]
DictionaryLiteral 不是一个 Dictionary 也不是 literal. 它是一个键值对表。

Swift 5 重命名 DictionaryLiteral 为 KeyValuePairs[[SE-0214]](https://github.com/apple/swift-evolution/blob/master/proposals/0214-DictionaryLiteral.md):
let pets: KeyValuePairs = ["dog": "Sclip", "cat": "Peti"]

Numeric Protocol Updates

Swift 4.2为向量实现了 Numeric:

// 1
struct Vector {
    let x, y: Int
    
    init(_ x: Int, _ y: Int) {
        self.x = x
        self.y = y
    }
}

// 2
extension Vector: ExpressibleByIntegerLiteral {
    init(integerLiteral value: Int) {
        x = value
        y = value
    }
}

// 3
extension Vector: Numeric {
    var magnitude: Int {
        return Int(sqrt(Double(x >md.png COPYING Config.plist CopyAsMarkdown-demo.mp4 README.md _Signature.plist html2md.sh html2text.py x + y >md.png COPYING Config.plist CopyAsMarkdown-demo.mp4 README.md _Signature.plist html2md.sh html2text.py y)))
    }
    
    init?<T>(exactly value: T) {
        x = value as! Int
        y = value as! Int
    }
    
    static func +(lhs: Vector, rhs: Vector) -> Vector {
        return Vector(lhs.x + rhs.x, lhs.y + rhs.y)
    }
    
    static func +=(lhs: inout Vector, rhs: Vector) {
        lhs = lhs + rhs
    }
    
    static func -(lhs: Vector, rhs: Vector) -> Vector {
        return Vector(lhs.x - rhs.x, lhs.y - rhs.y)
    }
    
    static func -=(lhs: inout Vector, rhs: Vector) {
        lhs = lhs - rhs
    }
    
    static func *(lhs: Vector, rhs: Vector) -> Vector {
        return Vector(lhs.x >md.png COPYING Config.plist CopyAsMarkdown-demo.mp4 README.md _Signature.plist html2md.sh html2text.py rhs.y, lhs.y >md.png COPYING Config.plist CopyAsMarkdown-demo.mp4 README.md _Signature.plist html2md.sh html2text.py rhs.x)
    }
    
    static func *=(lhs: inout Vector, rhs: Vector) {
        lhs = lhs >md.png COPYING Config.plist CopyAsMarkdown-demo.mp4 README.md _Signature.plist html2md.sh html2text.py rhs
    }
}

// 4
extension Vector: CustomStringConvertible {
    var description: String {
        return "(\(x) \(y))"
    }
}

这段代码如何工作:

  1. 为 vector 声明xy和 init(_:_:)
  2. 实现 init(integerLiteral:)方法来使 Vector 遵守 Numeric必须遵守的 ExpressibleByIntegerLiteral
  3. 定义 vector 的magnitude使其符合 Numeric,声明 init(exactly:)然后实现 +(lhs:rhs:)+=(lhs:rhs:)-(lhs:rhs:)-=(lhs:rhs:)*(lhs:rhs:)*=(lhs:rhs:)
  4. 实现 description 使 Vector 遵守 CustomStringConvertible

上面的代码使你可以轻松地使用 vector :

var first = Vector(1, 2) // (1,2)
let second = Vector(3, 4) // (3,4)
let third = first + second // (4,6)
first += second // (4,6)
let fourth = first - second // (1,2)
first -= second // (1,2)  

Swift 5为 vector 实现 AdditiveArithmetic,因为你无法定义2D向量的叉积。[[SE-0233]](https://github.com/apple/swift-evolution/blob/master/proposals/0233-additive-arithmetic-protocol.md)。它在 ExpressibleByIntegerLiteral 中不是必须的:

extension Vector: AdditiveArithmetic {
    static var zero: Vector {
        return Vector(0, 0)
    }
    
    static func +(lhs: Vector, rhs: Vector) -> Vector {
        return Vector(lhs.x + rhs.x, lhs.y + rhs.y)
    }
    
    static func +=(lhs: inout Vector, rhs: Vector) {
        lhs = lhs + rhs
    }
    
    static func -(lhs: Vector, rhs: Vector) -> Vector {
        return Vector(lhs.x - rhs.x, lhs.y - rhs.y)
    }
    
    static func -=(lhs: inout Vector, rhs: Vector) {
        lhs = lhs - rhs
    }
}

在这段代码,你通过定义 zero和实现 +(lhs:rhs:)+=(lhs:rhs:)-(lhs:rhs:)-=(lhs:rhs:)

Working with vectors is so easy in Swift 5!

想学习更多关于Swift中的操作符重载,访问操作符重载的教程Overloading Custom Operators in Swift

String Interpolation Updates

Swift 4.2 通过 interpolating segments 实现 字符串的插入:

let language = "Swift"
let languageSegment = String(stringInterpolationSegment: language)
let space = " "
let spaceSegment = String(stringInterpolationSegment: space)
let version = 4.2
let versionSegment = String(stringInterpolationSegment: version)
let string = String(stringInterpolation: languageSegment, spaceSegment, versionSegment)

在上述代码,首先包裹每个部分加入init(stringInterpolationSegment:),然后把所有的部分用 init(stringInterpolation:)包起来。

Swift 5带来了完全不同的处理方法[[SE-0228]](https://github.com/apple/swift-evolution/blob/master/proposals/0228-fix-expressiblebystringinterpolation.md):

// 1
var interpolation = DefaultStringInterpolation(
    literalCapacity: 7,
    interpolationCount: 1)
// 2
let language = "Swift"
interpolation.appendLiteral(language)
let space = " "
interpolation.appendLiteral(space)
let version = 5
interpolation.appendInterpolation(version)
// 3
let string = String(stringInterpolation: interpolation)

这段代码做了什么:

  1. 用指定容量和插入计数定义了一个 DefaultStringInterpolation实例。
  2. 调用 appendLiteral(_:)和 appendInterpolation(_:)来添加文字和插入数值到interpolation
  3. 通过调用 init(stringInterpolation:)生成最终的插值字符串。

Handling Future Enumeration Cases

Swift 4.2 不能恰当的处理新的枚举值,看下面的代码:

// 1
enum Post {
    case tutorial, article, screencast, course
}

// 2
func readPost(_ post: Post) -> String {
    switch post {
    case .tutorial:
        return "You are reading a tutorial."
    case .article:
        return "You are reading an article."
    default:
        return "You are watching a video."
    }
}

// 3
let screencast = Post.screencast
readPost(screencast) // "You are watching a video."
let course = Post.course
readPost(course) // "You are watching a video."

上面的代码发生了什么:

  1. 定义了所有的网站上的 blog posts 类型。
  2. 添加 default使 switch无遗漏。
  3. 在 default 中处理 .screencast 和.course因为他们都是视频。

以下是在Swift 4.2中处理 podcasts

enum Post {
    case tutorial, article, podcast, screencast, course
}

let podcast = Post.podcast
readPost(podcast) // "You are watching a video."

上述代码中,你在 default中处理.podcast,
即使它不是视频,Swift不会报警告因为 switch没有遗漏。

Swift 5关注到了新增枚举的情况[[SE-0192]](https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md):

func readPost(_ post: BlogPost) -> String {
    switch post {
    case .tutorial:
        return "You are reading a tutorial."
    case .article:
        return "You are reading an article."
    @unknown default:
        return "You are reading a blog post."
    }
}

readPost(screencast) // "You are reading a blog post."
readPost(course) // "You are reading a blog post."
readPost(podcast) // "You are reading a blog post."  

在这段代码中,你标记用@unknown
标记 default,Swift 将会警告你switch是不详尽的。default处理 .screencast.course.podcast
,因为他们都是 blog posts。

The future is bright for Swift 5 enumerations!

[](https://blog.devorz.com/2019/04/04/What-s-New-in-Swift5/#Adding-Result-to-the-Standard-Library)Adding Result to the Standard Library

Swift 5 加入 Result到标准库[ [SE-0235]](https://github.com/apple/swift-evolution/blob/master/proposals/0235-add-result.md):

// 1
enum ConnectionError: Error {
    case noNetwork, noDatabase
}

// 2
let networkSuccess = Result<String, ConnectionError>.success("Network connected!")
let databaseSuccess = Result<String, ConnectionError>.success("Database connected!")
let networkFailure = Result<String, ConnectionError>.failure(.noNetwork)
let databaseFailure = Result<String, ConnectionError>.failure(.noDatabase)
let sameSuccess = networkSuccess == databaseSuccess
let sameFailure = networkFailure == databaseFailure
let success: Set = [networkSuccess, databaseSuccess]
let failure: Set = [networkFailure, databaseFailure]
let successDictionary = [
    networkSuccess: try! networkSuccess.get(),
    databaseSuccess: try! databaseSuccess.get()
]
let failureDictionary = [
    networkFailure: ConnectionError.noNetwork,
    databaseFailure: ConnectionError.noDatabase
]

这段代码如何工作:

  1. 声明最常见的连接错误.
  2. 比较连接结果,将它们添加到集合中。你可以使用这些集和中的元素作为字典的 key ,因为Result实现了 Equatable和 Hashable

Conforming Never to Equatable and Hashable

Swift 5 是 Never 遵从 EquatableHashable[SE-0215]
:

let alwaysSucceeds = Result<String, Never>.success("Network connected!")
let neverFails = Result<String, Never>.success("Database connected!")
let alwaysFails = Result<Never, ConnectionError>.failure(.noNetwork)
let neverSucceeds = Result<Never, ConnectionError>.failure(.noDatabase)
let sameValue = alwaysSucceeds == neverFails
let sameError = alwaysFails == neverSucceeds
let alwaysSuccess: Set = [alwaysSucceeds, neverFails]
let alwaysFailure: Set = [alwaysFails, neverSucceeds]
let alwaysSuccessDictionary = [
    alwaysSucceeds: try! alwaysSucceeds.get(),
    neverFails: try! neverFails.get()
]
let alwaysFailureDictionary = [
    alwaysFails: ConnectionError.noNetwork,
    neverSucceeds: ConnectionError.noDatabase
]  

在此代码中,您定义连接结果的返回值或错误,比较它们,将它们添加到集合并将它们用作字典key。

Dynamically Callable Types

Swift 5定义了 dynamically callable types,使其可以与 Python 和 Ruby相互操作。

// 1
@dynamicCallable
class DynamicFeatures {
    // 2
    func dynamicallyCall(withArguments params: [Int]) -> Int? {
        guard !params.isEmpty else {
            return nil
        }
        return params.reduce(0, +)
    }
    
    func dynamicallyCall(withKeywordArguments params: KeyValuePairs<String, Int>) -> Int? {
        guard !params.isEmpty else {
            return nil
        }
        return params.reduce(0) { $1.key.isEmpty ? $0 : $0 + $1.value }
    }
}

// 3
let features = DynamicFeatures()
features() // nil
features(3, 4, 5) // 12
features(first: 3, 4, second: 5) // 8

上述代码:

  1. 用 @dynamicCallable 标记 DynamicFeatures 使其成为 dynamically callable type
  2. 使 DynamicFeatures 遵从 @dynamicCallable ,实现 dynamicallyCall(withArguments:) 和 dynamicallyCall(withKeywordArguments:)
  3. 使用平常的语法调用 features,编译器将调用dynamicallyCall(withArguments:) 或者dynamicallyCall(withKeywordArguments:) 。

[](https://blog.devorz.com/2019/04/04/What-s-New-in-Swift5/#Swift-Package-Manager-Updates)Swift Package Manager Updates

Swift 5给 Swift Package Manager添加了一些特性:

[](https://blog.devorz.com/2019/04/04/What-s-New-in-Swift5/#Platform-Deployment-Settings)Platform Deployment Settings

Swift 5允许您在 Package.swift 中定义所需的最低平台部署目标版本[[SE-0236]](https://github.com/apple/swift-evolution/blob/master/proposals/0236-package-manager-platform-deployment-settings.md):

let package = Package(name: “Package”, platforms: [
    .macOS(.v10_14),
    .iOS(.v12),
    .tvOS(.v12),
    .watchOS(.v5)
])

你可以在 SupportedPlatform中使用 macOS()iOS()tvOS()watchOS()来设置包所需的最低平台版本。

Target Build Settings

Swift 5在 Package.swift 中声明了特定于目标的构建设置。它们自定义包管理器在目标构建期间如何调用构建工具[[SE-0238]](https://github.com/apple/swift-evolution/blob/master/proposals/0238-package-manager-build-settings.md)。

Dependency Mirroring

Swift 5为Swift Package Manager带来了依赖镜像 [SE-0219].

swift package config set-mirror --package-url <package> --mirror-url <mirror>

即使原始源不可用或被删除,镜像也允许您访问依赖项。

set-mirror使用镜像更新依赖项,后者替换所有其他镜像。

使用unset-mirror从依赖项中删除镜像:

swift package config unset-mirror --package-url <package>
swift package config unset-mirror —mirror-url <mirror>
swift package config unset-mirror --all

Miscellaneous Bits and Pieces

Swift 5还增加了一些其他急需的功能和改进:

[](https://blog.devorz.com/2019/04/04/What-s-New-in-Swift5/#Making-Codable-Ranges)Making Codable Ranges

Swift 5 给 rangs 增加了 Codable 的遵从 [SE-0239]:

let temperature = 0...10
let encoder = JSONEncoder()
let data = try! encoder.encode(temperature)
let decoder = JSONDecoder()
let temperatureRange = try! decoder.decode(ClosedRange<Int>.self, from: data)  

您使用JSONEncoder对温度进行编码并使用JSONDecoder解码数据,因为默认情况下,rangs 在Swift 5中实现了 Codable 。

Flattening Nested Optionals

Swift 4.2 使用 try?创建 Nested Optionals:

extension Int {
    // 1
    enum DivisionError: Error {
        case divisionByZero
    }
    
    // 2
    func divideBy(_ number: Int) throws -> Int {
        guard number != 0 else {
            throw DivisionError.divisionByZero
        }
        return self / number
    }
}

// 3
let number: Int? = 10
let division = try? number?.divideBy(2)
if let division = division,let final = division {
    print(final)
}

上述代码:

  1. 用 DivisionError 扩展 Int 。
  2. 如果 number为 0 ,divideBy(_:) 抛出 .divisionByZero
  3. 解开 division 两次,因为它是一个 Int ?? 型。

Swift 5以不同的方式处理[SE-0230]:

if let division = division {
    print(division)
}

try? 在Swift 5中不会创建 nested optionals ,因此你需要解包一次,因为它是一个 Int?

Removing Customization Points From Collections

在Swift 4.2 你入口可以从 Collection中自定义细节(customization points):

extension Array {
    var first: Element? {
        return !isEmpty ? self[count - 1] : nil
    }
    
    var last: Element? {
        return !isEmpty ? self[0] : nil
    }
}

let names = ["Cosmin", "Oana", "Sclip", "Nori"]
names.first // "Nori"
names.last // "Cosmin"

在此代码中,first 从 names返回最后一个名字,last 返回数组的第一个元素。

两个计算属性都不能按预期工作,因此 Swift 5 会从集合中删除自定义细节 [SE-0232]

[](https://blog.devorz.com/2019/04/04/What-s-New-in-Swift5/#Identity-Key-Paths)Identity Key Paths

Swift 4.2使用.self来访问值:

class Tutorial {
    let title: String
    let author: String
    init(title: String, author: String) {
        self.title = title
        self.author = author
    }
}

var tutorial = Tutorial(title: "What's New in Swift 5.0?", author: "Cosmin Pupaza")
tutorial.self = Tutorial(title: "What's New in Swift 5?", author: "Cosmin Pupăză")

在此代码中,你使用 .self 一口气更改教程的标题和作者。

Swift 5 添加为 identity key paths 来访问值 [SE-0227];

tutorial[keyPath: \.self] = Tutorial(
    title: "What's New in Swift 5?",
    author: "Cosmin Pupăză")

在此代码中,您使用\ .self来更新 tutorial

Initializing Literals Through Coercion

在Swift 5中,如果类型符合 literal 协议,则literal initializers会将字面值强制转换为其类型:

let value = UInt64(0xFFFF_FFFF_FFFF_FFFF)

在Swift 4.2中,上面的代码行在编译时产生溢出错误。

Build Configuration Updates

Swift 4.2 条件编译时用 >=


let favoriteNumber = 10
var evenNumber = true

#if !swift(>=5)
evenNumber = favoriteNumber % 2 == 0
#else
evenNumber = favoriteNumber.isMultiple(of: 2)
#endif

#if !compiler(>=5)
evenNumber = favoriteNumber % 2 == 0
#else
evenNumber = favoriteNumber.isMultiple(of: 2)
#endif  

这些条件检查Swift版本是否大于或等于5,并在满足条件时编译这些代码。

Swift 5增加 < 用来更简洁的表达条件 [SE-0224]:

#if swift(<5)
evenNumber = favoriteNumber % 2 == 0
#else
evenNumber = favoriteNumber.isMultiple(of: 2)
#endif

#if compiler(<5)
evenNumber = favoriteNumber % 2 == 0
#else
evenNumber = favoriteNumber.isMultiple(of: 2)
#endif

Using Variadic Parameters for Enumeration Cases With Associated Values

Swift 4.2中,在有关联值时,你可以使用可变参数来枚举case:

enum BlogPost {
    case tutorial(_: String...)
    case article(_: String...)
}

您可以使用 String ... 获取 tutorials 和 articles 详细信息。这在 Swift 5 中是不行的,所以你应该使用数组:

enum BlogPost {
    case tutorial([String])
    case article([String])
}

Deprecating String Index Encoded Offsets

Swift 4.2字符串使用UTF-16编码。因此,encodedOffset将返回UTF-16字符串的偏移量:

let swiftVersion = "Swift 4.2"
let offset = swiftVersion.endIndex.encodedOffset  

在这段代码 你可以获得 swiftVersion 中 endIndex 的偏移量。这不适用于Swift 5中使用的UTF-8字符串编码,因此Swift 5用utf16Offset(in :)替换encodedOffset来处理这两种情况:

let swiftVersion = "Swift 5"
let offset = swiftVersion.endIndex.utf16Offset(in: swiftVersion)  

New Pointer Methods

Swift 5添加了 ContiguousStorageIfAvailable(_ :)到 Sequence 和 withContiguousMutableStorageIfAvailable(_ :) 到 MutableCollection,为协议扩展中的 withUnsafeBufferPointer(_ :)withUnsafeMutableBufferPointer(_ :)提供通用实现[SE-0237]。

SIMD Vector Updates

Swift 5将处理器的SIMD类型操作添加到标准库中。它们为 SIMD vectors 和矩阵提供底层支持。它们还简化了<simd/simd.h>的Objective-C,C和C实现[SE-0229].

本文链接:

https://www.devorz.com/index.php/archives/What-s-New-in-Swift5.html
1 + 4 =
快来做第一个评论的人吧~