##概述

Swift 3.1 和 Swift 3.0 是源码兼容的,所以如果已经使用 Edit\Convert\To Current Swift Syntax… 将项目迁移到了 Swift 3.0 的话,新功能将不会破坏我们的代码。不过,苹果在 Xcode 8.3 中已经抛弃了对 Swift 2.3 的支持。所以如果还没有从 Swift 2.3 迁移过来,现在要抓紧做了!

1. 可失败数值转换初始化方法

Swift 3.1 为所有数字类型 (Int, Int8, Int16, Int32, Int64, UInt, UInt8, UInt16, UInt32, UInt64, Float, Float80, Double) 实现了可失败初始化方法,要么完全成功、不损失精度,要么返回 nil 。

例如以下处理JSON的代码

class Student {let name: Stringlet grade: Intinit?(json: [String: Any]) {guard let name = json["name"] as? String,let gradeString = json["grade"] as? String,let gradeDouble = Double(gradeString),let grade = Int(exactly: gradeDouble)  // <-- 这里是 3.1 的功能else {return nil}self.name = nameself.grade = grade}
}func makeStudents(with data: Data) -> [Student] {guard let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments),let jsonArray = json as? [[String: Any]] else {return []}return jsonArray.flatMap(Student.init)
}let rawStudents = "[{\"name\":\"Ray\", \"grade\":\"5.0\"}, {\"name\":\"Matt\", \"grade\":\"6\"},{\"name\":\"Chris\", \"grade\":\"6.33\"}, {\"name\":\"Cosmin\", \"grade\":\"7\"}, {\"name\":\"Steven\", \"grade\":\"7.5\"}]"
let data = rawStudents.data(using: .utf8)!
let students = makeStudents(with: data)
dump(students) // [(name: "Ray", grade: 5), (name: "Matt", grade: 6), (name: "Cosmin", grade: 7)]
复制代码

Student 类的指定可失败初始化方法中用可失败构造器将 grade 属性从 Double 转换为 Int,就像这样:

let grade = Int(exactly: gradeDouble)
复制代码

如果 gradeDouble 是小数,例如 6.33,就会失败。如果可以用 Int 来表示,例如 6.0,就会成功。

2. 新的序列函数

Swift 3.1 为标准库的 Sequence 协议增加了两个新函数,用于数据过滤:prefix(while:)drop(while:)

Swift 3.1 允许我们使用 prefix(while:) 和 drop(while:) 来获取位于序列两个给定值之间所有的元素,像这样:

// Swift 3.1
let interval = fibonacci.prefix(while: {$0 < 1000}).drop(while: {$0 < 100})
for element in interval {print(element) // 144 233 377 610 987
}
复制代码

prefix(while:)返回满足某 predicate 的最长子序列。从序列的开头开始,并且在第一个从给定闭包中返回 false 的元素处停下。

drop(while:)做相反的操作:从第一个在闭包中返回 false 的元素开始,直到序列的结束,返回此子序列。

3. Concrete Constrained Extensions

Swift 3.1 允许我们扩展具有 concrete type constraint 的泛型。之前不能扩展这样的类型,因为约束必须是一个协议。 例如,Ruby On Rails 提供了一个非常实用的方法 isBlank 用于检查用户输入。在 Swift 3.0 中我们会将其实现为 String 扩展中的计算属性:

// Swift 3.0
extension String {var isBlank: Bool {return trimmingCharacters(in: .whitespaces).isEmpty}
}let abc = " "
let def = "x"abc.isBlank // true
def.isBlank // false
如果想要 string 可选值 也能用 isBlank 计算属性,在 Swift 3.0 中要这么做:// Swift 3.0
protocol StringProvider {var string: String {get}
}extension String: StringProvider {var string: String {return self}
}extension Optional where Wrapped: StringProvider {var isBlank: Bool {return self?.string.isBlank ?? true}
}let foo: String? = nil
let bar: String? = "  "
let baz: String? = "x"foo.isBlank // true
bar.isBlank // true
baz.isBlank // false
复制代码

我们创建了一个 StringProvider 协议供 String 采用。当拆包类型是StringProvider的时候使用它扩展 Optional,添加 isBlank方法。

Swift 3.1 可以用这样的协议来扩展 concrete type:

// Swift 3.1
extension Optional where Wrapped == String {var isBlank: Bool {return self?.isBlank ?? true}
}
复制代码

4. 泛型嵌套

Swift 3.1 让我们可以混合使用泛型和类型嵌套。练习一下,看看这个(不是很难的)例子。如果某个 raywenderlich.com 的团队领导想要在博客上发一篇文章,他会找专门的开发者团队来处理这个问题,以保证文章的质量:

class Team<T> {enum TeamType {case swiftcase iOScase macOS}class BlogPost<T> {enum BlogPostType {case tutorialcase article}let title: Tlet type: BlogPostTypelet category: TeamTypelet publishDate: Dateinit(title: T, type: BlogPostType, category: TeamType, publishDate: Date) {self.title = titleself.type = typeself.category = categoryself.publishDate = publishDate}}let type: TeamTypelet author: Tlet teamLead: Tlet blogPost: BlogPost<T>init(type: TeamType, author: T, teamLead: T, blogPost: BlogPost<T>) {self.type = typeself.author = authorself.teamLead = teamLeadself.blogPost = blogPost}
}
复制代码

我们把内部类 BlogPost嵌套在对应的外部类Team中,这两个类都是泛型。目前团队在寻找已发布的教程和文章时需要这样做:

Team(type: .swift, author: "Cosmin Pupăză", teamLead: "Ray Fix", blogPost: Team.BlogPost(title: "Pattern Matching", type: .tutorial, category: .swift, publishDate: Date()))Team(type: .swift, author: "Cosmin Pupăză", teamLead: "Ray Fix", blogPost: Team.BlogPost(title: "What's New in Swift 3.1?", type: .article, category: .swift, publishDate: Date()))
复制代码

但实际上可以简化这里的代码。如果嵌套的内部类型用了外部的泛型,它就默认继承了父类的类型。因此我们不需要声明,只要这样写就可以了:

class Team<T> {// 本来的代码class BlogPost {// 本来的代码}  // 本来的代码let blogPost: BlogPostinit(type: TeamType, author: T, teamLead: T, blogPost: BlogPost) {// 本来的代码   }
}
复制代码

注意:如果想学习 Swift 中的泛型,读一读这篇最近更新的教程 getting started with Swift generics 。

5. Swift 版本可用性

我们可以使用 Swift 版本的#if swift(>= N)  静态构造器,像这样:

// Swift 3.0
#if swift(>=3.1)func intVersion(number: Double) -> Int? {return Int(exactly: number)}
#elseif swift(>=3.0)func intVersion(number: Double) -> Int {return Int(number)}
#endif
复制代码

然而在使用 Swift 标准库这样的东西时,这种方法有一个很大的缺点。它需要为每个旧语言版本编译标准库。因为如果要使用 Swift 3.0 的行为,则需要使用针对该版本编译的标准库。如果使用 3.1 版本的标准库,就根本没有正确的代码。 所以,Swift 3.1 扩展了 @available属性

// Swift 3.1@available(swift 3.1)
func intVersion(number: Double) -> Int? {return Int(exactly: number)
}@available(swift, introduced: 3.0, obsoleted: 3.1)
func intVersion(number: Double) -> Int {return Int(number)
}
复制代码

这个新功能与 intVersion 方法相同。但是,它只允许像标准库这样的库被编译一次。编译器随后只要选择与对应版本兼容的功能即可。

**注意:**如果想学习 Swift 的 availability attributes,看看这篇教程 availability attributes in Swift。

6. Swift 包管理器的更新

  • Editable Packages Swift 3.1 在 Swift 包管理器 中新增了 Editable Packages 概念 swift package edit命令可以将现有包转换为可编辑的。可编辑的包将会替换 dependency graph 中的规范包。使用 —end-edit  命令将包管理器还原回规范解析的包
  • Version Pinning Swift 3.1 在特定版本的 Swift 包管理器 中新增了 version pinning 概念。 pin命令会像这样固定一个或多个依赖:
$ swift package pin --all      // pin 所有依赖
$ swift package pin Foo        // 把 Foo pin 在当前解析版本
$ swift package pin Foo --version 1.2.3  // 把 Foo pin 在 1.2.3
复制代码

使用 unpin  命令恢复到以前的包版本:

$ swift package unpin —all$ swift package unpin Foo
复制代码

包管理器在 Package.pins 中存储每个包的活跃版本 pin 信息。如果文件不存在,包管理器则会按照包 manifest 中指定的要求自动创建该文件,这是 automatic pinning 过程的一部分。

  • 其它 swift package reset命令将包重置为干净状态,不会检出当前的依赖关系或 build artifact。还有,使用 swift test --parallel命令并行执行测试。

==

参考文献 英文原版:What’s New in Swift 3.1? 一篇文章帮你彻底了解 Swift 3.1 的新内容 感谢翻译?

Swift 3.1新改动相关推荐

  1. Python3.0的新改动

    这篇文章主要介绍了相比于python2.6,python3.0的新特性. 更详细的介绍请参见python3.0的文档. Common Stumbling Blocks 本段简单的列出容易使人出错的变动 ...

  2. A Swift Tour, 苹果新推出的开发语言

    苹果近日召开了全球开发者大会(WWDC),推出了一种新的开发语言 Swift,有人说是用来替代Objective-C的,以下是苹果官方文档,第一时间整理了一下,觉得还是很有前景的,有些英文看不懂的就直 ...

  3. swift php 类型判断,Swift 5.1 新特性:透明类型关键字 some

    相信大家都对刚发布的 SwiftUI 印象深刻,在看示例代码的时候发现 View 前面有一个关键字  some.我开始以为是 SwiftUI 自带的属性,后来经网友提醒发现是 Swift 5.1 的新 ...

  4. [译] Swift 5.0 新特性

    原文地址:What's new in Swift 5.0 原文作者:Paul Hudson 译文出自:掘金翻译计划 本文永久链接:github.com/xitu/gold-m- 译者:iWeslie ...

  5. iOS16 第4个测试版发布,带来6个新改动,还修复了上百个bug

    距离上个测试版16天之后,苹果终于在今日推送了 iOS16.0 Beta 4 ,也就是  iOS16 的第4个测试版 iOS 16.0 Beta4 的版本号为 20A5238h ,更新包大小在 1.6 ...

  6. iOS14 正式发布!上百项新改动,超级好用!一文带你看懂

    晚上好,这里是捷径手机宝典,我是阿轲. 苹果召开了 2020 WWDC 大会,本次大会可以说诚意满满,发布了包括iOS14系统,iPadOS14系统,macOS Big Sur(大瑟尔)系统,watc ...

  7. 简版 Swift 5.7 新特性一览

  8. Git的使用:本地有新改动如何提交到远程服务器,仅做参考!

    步骤如下: 提交到本地仓库 切换到自己的分支,没有的话新建一个 git branch -b Raylay/XXXX git status git add [需要提交的文件] git commit -s ...

  9. Swift 3 新特性

    原文:What's New in Swift 3? ,作者:Ben Morrow,译者:kmyhy Swift 3将于今年下半年推出,为Swift开发者们带来了很多核心代码的改变.如果你没有关注过 S ...

最新文章

  1. MySQL的索引优化
  2. java 0xf0_java 中类似js encodeURIComponent 函数的实现案例
  3. SpringBoot 核心原理分析
  4. Windows常用运行库合集--官网(VC++、DirectX、.NET)
  5. 软件开发项目各阶段交付物列表
  6. 怎样在线制作gif表情包?教你快速制作gif表情包
  7. k8s iptable升级到ipvs
  8. Github项目(克隆,上传)简单git命令流程使用记录
  9. android 各类demo链接
  10. Python 医学知识图谱问答系统(一),建立医学知识图谱,基于neo4j知识图谱的医学问答体系
  11. 基于live555的视频直播
  12. find() 和 find_all()区别
  13. 找素数,分解质因数(python)
  14. 联通系统升级服务器地址,联通iptv升级服务器地址
  15. 实验室信息化管理行业方案
  16. 对抗熵增 耗散结构 个人成长
  17. Agora 教程 | 在 Android 端实现实时视频的美颜
  18. 商品历史价格查询API
  19. 太赛博朋克!华为天才少年自制B站百大Up奖杯,网友:技术难度不高,侮辱性极强...
  20. LeetCode刷题(python版)——Topic10盛最多水的容器

热门文章

  1. 2005国际通信展将于10月18-22日举行
  2. fedora16配制
  3. Julia程序设计3 数组1 创建、初始化、属性与访问
  4. Linuc C 编程实例1
  5. C语言结构体和结构体数组示例 - Win32窗口程序演示
  6. CSS弹出二级多列菜单和DIV布局实例 - 仿IBM官网首页
  7. 技术开发中一些名词解释
  8. 参数化查询(简单举例)
  9. 关于变量作用域的一点整理
  10. 初探Git git基本用法