博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Swift5.0新特性更新
阅读量:7064 次
发布时间:2019-06-28

本文共 6614 字,大约阅读时间需要 22 分钟。

  • 原文博客地址:
  • 期待已久的Swift 5.0终于来啦, Swift 5.0Swift中最备受关注的一个版本, 传说中ABI稳定的版本
  • 随着Xcode Bate 10.2的发布, Swift 5.0也发布了测试版, 相信也带来了很多优化和改进
  • 下面运行环境都是在Xcode Bate 10.2环境中进行的

新特性

dynamicCallable

  • @dynamicCallableSwift添加了一个新属性, 允许使用一个简单的语法糖调用函数一样调用命名类型
  • 如果需要添加@dynamicCallable属性, 就必须要实现以下方法中的一个或者两个
func dynamicallyCall(withArguments args: [Int]) -> Doublefunc dynamicallyCall(withKeywordArguments args: KeyValuePairs
) -> Double复制代码
  • 注意点:
  • 除了接受各种输入外,您还可以为各种输出提供多个重载, 自定义返回值, 可以是String, Int等等......
  • KeyValuePairs的使用和介绍, 没有使用过的

下面看一个例子, RandomNumberGenerator生成一个随机数

Swift 5.0之前的定义和调用方式

// 定义方式struct RandomNumberGenerator {    func generate(numberOfZeroes: Int) -> Double {        let maximum = pow(10, Double(numberOfZeroes))        return Double.random(in: 0...maximum)    }}// 调用方式let random = RandomNumberGenerator()let num = random.generate(numberOfZeroes: 2)print(num)复制代码

Swift 5.0使用@dynamicCallable属性

// 定义方式@dynamicCallablestruct RandomNumberGenerator {    func dynamicallyCall(withArguments args: [Int]) -> Double {        let numberOfZeroes = Double(args.first ?? 0)        let maximum = pow(10, numberOfZeroes)        return Double.random(in: 0...maximum)    }}// 调用方式let random = RandomNumberGenerator()let num = random(2)// random(2)等同于random.dynamicallyCall(withArguments: [2])print(num)复制代码
  • @dynamicCallable使用注意事项
  • 可以将它应用于结构,枚举,类和协议。
  • 如果你实现withKeywordArguments:并且没有实现withArguments:,你仍然可以在没有参数标签的情况下调用
  • 如果你的实现withKeywordArguments:withArguments:时标记为throw,则调用该类型也将被抛出throw
  • 扩展名无法添加@dynamicCallable,只能添加到主要类型上
  • 仍然可以为你定义的类型添加其他方法和属性,并且能够正常使用

  • 添加引用标识键路径的功能,该路径指的是应用它的整个输入值
  • Swift中的每个值都有一个特殊的伪属性.self,它指的是整个值
let id = \Int.self  var x = 1print(id)   Swift.WritableKeyPath
x.self = 2print(x) //2print(x.self) //2print(x[keyPath: id]) //2x[keyPath: id] = 3print(x[keyPath: id]) //3复制代码

可选参数

Swift 5之前,可以编写一个带有可变参数的枚举, 但是在Swift 5开始, 调用时会报错, 如下

enum X {    // 此处定义切没有调用时不会报错    case foo(bar: Int...) }func baz() -> X {    // 此处调用时会报错    return .foo(bar: 0, 1, 2, 3) } 复制代码

Swift 5之后, 上述定义改成数组参数, 而不是可变参数, 如下

enum X {    case foo(bar: [Int]) } func baz() -> X {    return .foo(bar: [0, 1, 2, 3]) } 复制代码

Raw Strings

\处理

  • 增加了创建原始字符串的功能,其中反斜杠和引号被解释为文字符号,而不是转义字符或字符串终止符
  • 单行字符串文字可以用反斜杠填充, 以保证原字符串, 否则会报错
// 文字引用类型// 错误写法let quote = "Alice: "How long is forever?" White Rabbit: "Sometimes, just one second.""// 正确写法let quote1 = "Alice: \"How long is forever?\" White Rabbit: \"Sometimes, just one second.\""// 正则表法式类型// 错误写法let ucCaseCheck = "enum\s+.+\{.*case\s+[:upper:]"// 正确写法let ucCaseCheck = "enum\\s+.+\\{.*case\\s+[:upper:]"复制代码

#处理

  • 要使用原始字符串, 可使用#将字符串包裹起来
  • #字符串开头和结尾的符号成为字符串分隔符的一部分,因此如下Swift理解“rain”“Spain”周围的独立引号应该被视为文字引号而不是结束字符串
  • 原始字符串也允许使用反斜杠, 但是将反斜杠视为字符串中的文字字符,而不是转义字符
let rain = #"The "rain" in "Spain" falls mainly on the Spaniards."#let keypaths = #"Swift keypaths such as \Person.name hold uninvoked references to properties."#let answer = 42let dontpanic = #"The answer to life, the universe, and everything is \#(answer)."#复制代码

注意: 上面使用\#(answer)引用变量而不是\(answer), 因为在用#包裹的字符串中反斜杠将会被失败别为文字字符而不是转义字符, 所以必须额外的添加#

##处理

  • 在字符串的开头和结尾使用#处理, 在字符串中可以使用反斜杠等特殊字符, 那如果字符串中需要使用#, 又该如何处理??
  • 使用#包裹字符串, 默认会以#为字符串的结束符号, #后面的文字将不再处理, 在这种情况下, 我们会使用##处理
  • 注意: 字符串的开头和结尾的标识必须一样
let str = ##"My dog said "woof"#gooddog"##复制代码

多行字符串

原始字符串与Swift的多行字符串系统完全兼容 - 只需用于#"""启动,然后"""#结束

let multiline = #"""    The answer to life,    the universe,    and everything is \#(answer).    """#复制代码

try?嵌套

先看下面代码

struct User {    var id: Int    init?(id: Int) {        if id < 1 {            return nil        }        self.id = id    }    func getMessages() throws -> String {        // complicated code here        return "No messages"    }}复制代码

Swift4.2及其之前的版本中

let user = User(id: 1)// 这里得到的message的类型是: let messages: String??let messages = try? user?.getMessages()// 如果我们想得到非可选值就需要print((messages ?? "") ?? "")// 或者多次强解, 当然不建议强解写法print(messages!!)复制代码
  • Swift4.2及其之前的版本中, 上面返回的是一个2层嵌套的可选值, 如果有多层嵌套处理起来也是相当更麻烦的
  • Swift 5中就完美的解决了这个问题, 如果当前值是可选的, 那么try?将不会将值包装在可选值中, 因此最终结果只是一个String?
  • 因此在Swift 5中无论有多少可嵌套的可选最后, 返回值永远只是一个可选值
  • 同样,如果你使用了可选的链接as?,你仍然只有一个级别的可选性
let user = User(id: 1)// 类型: let messages: String?let messages = try? user?.getMessages()print(messages ?? "")复制代码

isMultiple

  • 为整数类型添加了一个方法isMultiple
  • 该方法可以检查一个证书是否为另一个整数的倍数
let rowNumber = 4if rowNumber.isMultiple(of: 2) {    print("Even")} else {    print("Odd")}// 该方法等效于if rowNumber % 2 == 0 {}复制代码

count

  • Swift之前的版本中, 有一个函数filter可以过滤出数组中符合条件的的元素, 组成一个新的数组, 详细使用可参考
  • Swift 5中新增了一个函数count(where:), 可以获取数组中符合条件的元素的个数
let arr = [1, 2, 34, 5, 6, 7, 8, 12, 45, 6, 9]let filter = arr.filter({ $0 > 10 })print(filter)  //[34, 12, 45]let count = arr.count(where: { $0 > 10 })print(count)  // 3复制代码

compactMapValues

  • Swift4.x的版本有两个函数compactMapmapValues
  • compactMap: 返回一个操作后得到的新的数组, 类似flatMap
  • mapValues: 字典中的函数, 对字典的value值执行操作, 返回改变value后的新的字典
let times = [    "first": 2,    "second": 43,    "three": 12,    "four": 3]let compact = times.compactMap({ $0.value > 10 })print(compact)// [true, false, true, false]let mapValues = times.mapValues({ $0 + 2 })print(mapValues)// ["second": 45, "first": 4, "three": 14, "four": 5]复制代码
  • Swift 5中新增了一个函数compactMapValues
  • compactMapValues是将上述两个方法的功能合并在一起, 返回一个对value操作后的新字典, 并且自动过滤不符合条件的键值对
let times1 = [    "Hudson": "38",    "Clarke": "42",    "Robinson": "35",    "Hartis": "DNF"]let comMap2 = times1.compactMapValues({ Int($0) })print(comMap2)// ["Clarke": 42, "Robinson": 35, "Hudson": 38]复制代码

SubSequence

  • 协议不再具有SubSequence关联类型。先前返回SubSequenceSequence方法现在会返回具体类型
  • 使用SubSequenceSequence扩展应该修改为类似地使用具体类型,或者修改为的扩展,在中SubSequence仍然可用
// swift 5不在支持extension Sequence {    func dropTwo() -> SubSequence {        return self.dropFirst(2)    }}// 建议改为extension Sequence {    func dropTwo() -> DropFirstSequence
{ return self.dropFirst(2) }}// 或者extension Collection { func dropTwo() -> SubSequence { return self.dropFirst(2) }}复制代码

其他相关更新

DictionaryLiteral类型重命名为KeyValuePairs

  • 在使用Swift 5软件包管理器时,Targets可以声明一些常用的针对特定目标的build settings设置
  • 新设置也可以基于平台和构建配置进行条件化处理。包含的构建设置支持SwiftC语言定义,C语言头文件搜索路径,链接库和链接框架

  • 在使用Swift 5时, 可以自定义所支持的最低版本号, 如果该项目的依赖包所支持的最低版本大于项目的最低版本号, 则项目会报错

Swift 5中不再支持返回Self的类方法

// 不在支持class Base {     class func factory() -> Self { /*...*/ }} 复制代码

不同文件中的扩展名无法相互识别

class FirstClass { }extension FirstClass {    class SecondClass { }}// 这里将会报错: "SecondClass is not a member type of FirstClass"extension FirstClass.SecondClass {     class ThirdClass { }}复制代码

Swift 5中, 在所声明的类里面, 所声明的变量名不能和类名一样

struct S {}extension S {  static var i: Int { return 0 }  struct i {} // error: “i”的声明无效}// 下面的方式是没有问题的struct S1
{}extension S1 { static var i: Int { return 0 } struct i {} // This is fine!}复制代码

参考文献


转载地址:http://xkill.baihongyu.com/

你可能感兴趣的文章
MacOS下SVN迁移Git踩坑记
查看>>
14 -Flask构建弹幕微电影网站-后台逻辑(六)
查看>>
思考 | 云计算 + 区块链 = ?
查看>>
Java 学习(02)--数据类型/类型转换/键盘录入
查看>>
Maven之no dependency information available解决
查看>>
Flask使用Flask-SQLAlchemy操作MySQL数据库
查看>>
从客户端的角度来谈谈移动端IM的消息可靠性和送达机制
查看>>
菜鸟入门【ASP.NET Core】2:部署到IIS
查看>>
Flask入门的第一个项目进阶版
查看>>
laravel队列-让守护进程处理耗时任务
查看>>
初探MongoDB:暴力美学
查看>>
Reverse Nodes in k-Group@LeetCode
查看>>
查看 SELinux状态及关闭SELinux
查看>>
XDOC Office Server 开源了,Office文档完美转换为PDF
查看>>
数据库原理
查看>>
非常有用的并发控制-循环栅栏CyclicBarrier
查看>>
数据库备份相关
查看>>
深度学习优化入门:Momentum、RMSProp 和 Adam
查看>>
电子阅读器
查看>>
知识碎片
查看>>