前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Swift 5.1

Swift 5.1

作者头像
小刀c
发布2022-09-21 16:14:23
6160
发布2022-09-21 16:14:23
举报
文章被收录于专栏:cc logcc log

改进自动生成的struct初始化方法

swift早期版本中支持了自动生成struct的初始化方法

代码语言:javascript
复制
struct User {
    var name: String
    var loginCount: Int = 0
}

let piper = User(name: "Piper Chapman", loginCount: 0)

Swift 5.1改进了初始化方法,如果属性有了初始值,初始化的时候可以省略。

代码语言:javascript
复制
let gloria = User(name: "Gloria Mendoza", loginCount: 0)
let suzanne = User(name: "Suzanne Warren")

单行函数隐式返回

这点实际上很好理解,Swift 5.1中单行返回函数可以省略return关键词。

代码语言:javascript
复制
let doubled1 = [1, 2, 3].map { $0 * 2 }
let doubled2 = [1, 2, 3].map { return $0 * 2 }

上面两个是等价的。

实际上下面这么写也一样

代码语言:javascript
复制
func double(_ number: Int) -> Int {
    number * 2
}

更通用的Self

Swift 5.1中扩展了Self的使用,在class,struct, enmu中使用时候可以指向这个类型。这点在动态类型中很有用,特别是某些类型需要在运行时才能决定时候。

例如,下面场景中

代码语言:javascript
复制
class NetworkManager {
    class var maximumActiveRequests: Int {
        return 4
    }

    func printDebugData() {
        print("Maximum network requests: \(NetworkManager.maximumActiveRequests).")
    }
}

上面声明了静态的maximumActiveRequests属性,并且使用实例方法printDebugData来打印这个属性。现在这样工作的挺好。但是如果NetworkManager有子类,情况就不一样了

代码语言:javascript
复制
class ThrottledNetworkManager: NetworkManager {
    override class var maximumActiveRequests: Int {
        return 1
    }
}

子类改变了maximumActiveRequests,但是如果我们调用printDebugData(),它只会打印父类的属性。

代码语言:javascript
复制
let manager = ThrottledNetworkManager()
manager.printDebugData()

它理应打印1而不是4,这就是Self要解决的问题。我们改写printDebugData()Self(大写S)来指向当前的类型:

代码语言:javascript
复制
class ImprovedNetworkManager {
    class var maximumActiveRequests: Int {
        return 4
    }

    func printDebugData() {
        print("Maximum network requests: \(Self.maximumActiveRequests).")
    }
}

Self在协议中仍然像早期Swift中一样工作。

不透明返回类型(Opaque Return types)

提案SE-0244为Swift 5.1带来了不透明类型:知晓某个对象的能力但是不需要知道这个对象的具体类型。

初看之下,它很像协议protocol,但不透明返回类型走的比这更远,它可以和associated type使用。

代码语言:javascript
复制
protocol Fighter { }
struct XWing: Fighter { }

func launchFighter() -> Fighter {
    return XWing()
}

let red5 = launchFighter()

上面launchFighter返回某种Fighter,但是不知道具体那个类型,它可以是XWing,或者我们新增一个strunct YWing:Fighter {}

这样写有个问题,如果你想知道red5具体是那种类型的飞机呢?你可能想到方案是,让Fighter遵循Equatable协议,然后我们就可以使用==方法。但是实际使用的时候会发现下面的报错:

“Protocol 'Fighter' can only be used as a generic constraint because it has Self or associated type requirements.”
“Protocol 'Fighter' can only be used as a generic constraint because it has Self or associated type requirements.”

这是因为Equatable有一个Self的associated type。 有associated type的协议看起来像类型,但是它们实际上不是,它们实际上表示的是“遵循此协议的任意类型”

Swift 5.1中的不透明返回类型,可以将这种协议作做一个普通的类型来使用。只需要在协议名前增加some关键词。

代码语言:javascript
复制
func launchOpaqueFighter() -> some Fighter {
    return XWing()
}

不透明返回类型(Opaque Return types)可以带来的好处有:

  • 我们的函数决定具体的返回类型,而不是函数的调用方。
  • 我们不需要在关心Self或者associated type,因为编译器会明确知道内部具体的类型。
  • 为函数定义方将来改变实现留有余地。
  • 函数定义方不需要对外保留内部的类型。

支持Staticclass类下标(subscripts)

静态Static类型的属性和方法,可用来在类型所有实例间共享某些值。例如你可以在你的App中集中管理配置。

代码语言:javascript
复制
public enum OldSettings {
    private static var values = [String: String]()

    static func get(_ name: String) -> String? {
        return values[name]
    }

    static func set(_ name: String, to newValue: String?) {
        print("Adjusting \(name) to \(newValue ?? "nil")")
        values[name] = newValue
    }
}

OldSettings.set("Captain", to: "Gary")
OldSettings.set("Friend", to: "Mooncake")
print(OldSettings.get("Captain") ?? "Unknown")

字典包裹在类型中可以让更小心的控制它,并且使用没有caseenum,也就让你没法实例化Settings

在Swift 5.1中你可以使用static subscript

代码语言:javascript
复制
public enum NewSettings {
    private static var values = [String: String]()

    public static subscript(_ name: String) -> String? {
        get {
            return values[name]
        }
        set {
            print("Adjusting \(name) to \(newValue ?? "nil")")
            values[name] = newValue
        }
    }
}

NewSettings["Captain"] = "Gary"
NewSettings["Friend"] = "Mooncake"
print(NewSettings["Captain"] ?? "Unknown")
  • 类型实例之前就可以自定义下标
  • swift 5.1中类型也可以定制static或者class的下标了。

static或者class都是静态的前缀,区别是,class容许子类型覆盖

swift中static或者class方法的区别
swift中static或者class方法的区别

告警有歧义的none

Swift的可选(optional)是现实是通过有两个值somenone的enum来实现的。这样就和我们自己代码中有nonecase的enum包裹在optional时候产生混淆。

代码语言:javascript
复制
enum BorderStyle {
    case none
    case solid(thickness: Int)
}

如果在非可选值中使用

代码语言:javascript
复制
let border1: BorderStyle = .none
print(border1)

上面会打印none。 但是如果我们在使用在可选值中,我们不知道什么边框时候,Swift 5.1之前的版本会有问题。

代码语言:javascript
复制
let border2: BorderStyle? = .none
print(border2)

会打印nil, 因为swfit会默认将.none推导为可选是空值,而不是BorderStyle.none

Swift 5.1中会对此做出警告:“Assuming you mean 'Optional.none'; did you mean 'BorderStyle.none' instead?”,提示你作修复。

匹配可选(optional)和非可选的(non-optional)的enmu

Swift一直能够在switch case聪明的处理可选(optional)和非可选的(non-optional)的string,和integer。到了Swift 5.1 也支持enum了。

代码语言:javascript
复制
enum BuildStatus {
    case starting
    case inProgress
    case complete
}

let status: BuildStatus? = .inProgress

switch status {
case .inProgress:
    print("Build is starting…")
case .complete:
    print("Build is complete!")
default:
    print("Some other build status")
}

现在能够正常的打印,”Build is starting…“了。

可排序集合的diff

Swift 5.1 为可排序集合(内含Equatable元素)提供了一个difference(from:)方法来计算两个集合,那个元素被移除了,新增了哪个……

此方法被标注为,swift 5.1才@available,因此使用需要if swift(>=5.1)来判断

代码语言:javascript
复制
let operatingSystems = ["Yosemite",
                        "El Capitan",
                        "Sierra",
                        "High Sierra",
                        "Mojave",
                        "Catalina"]
var answers = ["Mojave",
               "High Sierra",
               "Sierra",
               "El Capitan",
               "Yosemite",
               "Mavericks"]


#if swift(>=5.1)
let differences = operatingSystems.difference(from: answers)
let sameAnswers = answers.applying(differences) ?? []
// 1
for change in differences.inferringMoves() {
  switch change {
    // 2
    case .insert(let offset, let element, let associatedWith):
      answers.insert(element, at: offset)
      guard let associatedWith = associatedWith else {
        print("\(element) inserted at position \(offset + 1).")
        break
      }
      print("""
            \(element) moved from position \(associatedWith + 1) to position
            \(offset + 1).
            """)
    // 3
    case .remove(let offset, let element, let associatedWith):
      answers.remove(at: offset)
      guard let associatedWith = associatedWith else {
        print("\(element) removed from position \(offset + 1).")
        break
      }
      print("""
            \(element) removed from position \(offset + 1) because it should be
              at position \(associatedWith + 1).
            """)
  }
}
#endif
  • 使用inferringMoves()得到diff中所欲改变
  • 通过associatedWith不为nil.insert(offset:element:associatedWith:)来判断是插入的操作
  • 通过associatedWith不为nil.remove(offset:element:associatedWith:)来判断是删除的操作

这个功能确实非常的pro哈~~

创建没有初始值的数组(uninitialized arrays)

可以在Swfift 5.1的版本中创建一个没有初始值的数组。

代码语言:javascript
复制
// 1
let randomSwitches = Array<String>(unsafeUninitializedCapacity: 5) {
  buffer, count in
  // 2
  for i in 0..<5 {
    buffer[i] = Bool.random() ? "on" : "off"
  }
  // 3
  count = 5
}
  1. 使用init(unsafeUninitializedCapacity:initializingWith:)来创建一个初始大小的数组
  2. 循环该数组(randomSwitches), 给每个值设值。
  3. 第二个inout参数可以让你重新为数组设置长度。

总结

这些就是swift 5.1的更新了,不算难懂,确实让swift越来越好用。😄

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 改进自动生成的struct初始化方法
  • 单行函数隐式返回
  • 更通用的Self
  • 不透明返回类型(Opaque Return types)
  • 支持Static和class类下标(subscripts)
  • 告警有歧义的none
  • 匹配可选(optional)和非可选的(non-optional)的enmu
  • 可排序集合的diff
  • 创建没有初始值的数组(uninitialized arrays)
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档