前语

本期是 Swift 批改组拾掇周报的第三十七期,每个模块已初步成型。各位读者假设有好的提议,欢迎在文末留言。

Swift 周报在 GitHub 开源,欢迎提交 issue,投稿或举荐内容。现在计划每两周周一发布,欢迎志同道合的朋友一同参与周报拾掇。

浅尝辄止必将黯然神伤,锲而不舍终会穷途末路。Swift社区值得与之同行,一同成就出色!

周报精选

新闻和社区:苹果跌近 3% 市值两天蒸发 1898亿 美元

提案:包迭代提案正在检查

Swift 论坛:提议用户定义的元组一同性

举荐博文:Swift 中的线程安全性和运用锁的方法

论题谈论:

HUAWEI Mate 60 Pro 和 iPhone 15 你会怎样挑选?

上期论题效果

Swift 周报 第三十七期

这个效果反映了人们对核污水排放问题的担忧,以及对个人健康和环境保护的注重。

新闻和社区

苹果跌近 3% 市值两天蒸发 1898 亿 美元

苹果股价连续两天大跌,实属稀有。截至收盘,苹果报 177.56 美元,跌幅 2.92% ,最新市值 2.8万 亿美元。苹果连续两天累计跌幅 6.5% ,其市值两天蒸发 1898 亿 美元(约 13911 亿元)。

Swift 周报 第三十七期

消息面上,据我国基金报,一方面,下周发布 iPhone 15 系列手机,会跟现在卖爆的华为手组织成剧烈比赛,另一方面有报道称 iPhone 手机在某些场合已被禁用。

另据报道,欧盟发布最严数字监管名单,苹果等科技巨擘名列其间。

据上海证券报,欧盟将于周三发布第一批受《数字商场法案》(简称 DMA )监管的服务清单。这份清单将列出部分“守门人”,即处于必定独占方位的科技巨擘。现在苹果、微软、亚马逊、Alphabet、Meta 和三星等现已在名单上,这些公司将承担不得乱用商场支配方位镇压或并购比赛对手、与比赛对手树立链接等 DMA 规则的义务。

依据 DMA 的规则,“看门人”公司指在数字商场上扮演了要害的人物,具有巨大的商场影响力,因而需求遭到更严厉的监管。具体条件为:公司年营业额跨越 75亿 欧元、市值跨越 750 亿 欧元(820 亿 美元),在欧盟具有 4500万 月活用户的途径。不过,在这些原始方针之外,欧盟方面对这些规则具有必定的自在裁量权。

与此同时,欧盟委员会还启动了四项商场调查,以进一步点评微软 Bing、Edge 和微软广告以及苹果 iMessage 是否能获豁免。

苹果公司的一位发言人表示,该公司仍然“非常担忧 DMA 给我们的用户带来的隐私和数据安全危险。”“我们的重点将是怎样减轻这些影响,并持续为我们的欧洲客户供应最好的产品和服务。(来历:每日经济新闻)

iPhone 15 系列订单量下滑,苹果公司面对双重商场冲击

9 月 4 日,依据第三方组织的消息称,苹果公司估计 2023 年下半年全球智能手机商场将出现疲软态势,因而订货的 iPhone 15 数量或许会减少。

此前,苹果公司宣告 2023 年的秋季新品发布会时间为北京时间 9 月 13 日清晨一点,备受瞩目的 iPhone 15 系列智能手机也将在发布会上正式露脸。

Swift 周报 第三十七期

跟着发布会的时间临近,iPhone 15 系列的供应链备货情况也遭到工作重视。

有剖析师走漏称,苹果公司在本年 8 月份就现已向供应链下达了 iPhone 15 系列在本年下半年的订单,订单量在 8000 万部到 9000 万部之间。

但是,2022 年 8 月份 iPhone 14 行将露脸的时分,苹果公司向供应链下达的 iPhone 14 系列订单在 9000万 部到 1 亿部之间,现在 iPhone 15 的订单量,比较上一年 iPhone 14 的订单出现了大幅下滑!

8 月份的时分,苹果公司下达订单量首要考虑的是下半年的商场情况。关于订单量的下滑,苹果公司给出的原因是全球智能手机商场的疲软。

依据 Canalys 发布的研讨数据闪现,2023 年上半年,全球智能手机出货量达 5.28 亿部,同比下降 12% ,我国智能手机商场的出货量为 1.32 亿部,同比下滑 8% 。

无论是我国手机商场,仍是全球手机商场,都没有从手机工作的下行中走出来,出货量仍在下跌。(来历:腾讯网新行情Pro)

苹果的对手回来了

8 月 29 日正午,在没有任何预告、发布会的情况下,华为官方发布了《致华为用户的一封信》,信中称华为推出了“ HUAWEI Mate 60 Pro 前锋计划”,当天 12 时 08 分在华为商城正式上线华为 Mate 60 Pro。

Swift 周报 第三十七期

尽管毫无征兆,但是华为 Mate 60 Pro 仍然遭到了广泛重视,华为的消息一瞬间就冲上了微博热搜。

随后,在短短几个小时之内,华为商城第一批 Mate 60 Pro 就被抢购一空,很多网友直呼华为急忙出下一批!

更令人惊喜的是,华为 Mate 60 Pro 的网速现已达到了 5G 水平,还有卫星通话功用,这预示着手机内的芯片质量现已达到了 5G 芯片水平,华为实在劫后重生,王者归来。

这一瞬间,苹果公司直接慌了神,快快当当地宣告将于 9 月 13 日发布 iPhone 15 系列手机,作为对华为发布新手机的对冲。

苹果公司和华为,能够说是手机工作的老对手了。2019 年,假设不出意外的情况下,华为当年的手机销量、商场比例将会全面跨越苹果,成为全球第一大手机厂商。

但是,在那之后一切人都看到了,华为的供应链出现了危机,不得不将荣耀子品牌脱离,甚至在手机全面进入 5G 时代的时分,只能推出 4G 的手机。

本年上半年,华为手机的销量现已彻底跌出了工作前 7 的方位,业界一度认为华为有或许会退出手机工作了。

但是,现在华为实在攻克了难关,携 Mate 60 王者归来,直接震撼了全球手机商场!

9 月 4 日,据媒体报道称,华为已将 Mate 60 系列手机的订单量提升至 1500 – 1700 万台。

业界人士预测,Mate 60 Pro 将有望成为华为 Mate 系列销量最高的手机,终究的订单量将在 1700 万台左右。(来历:腾讯网新行情Pro)

提案

通过的提案

SE-0405 具有编码验证的 String Initializers 提案通过检查。该提案已在 三十五期周报 正在检查的提案模块做了具体介绍。

正在检查的提案

SE-0408 包迭代 提案正在检查。

在依据值和类型参数包提案 SE-0393 的基础上,这个提案使答应在值参数包中对每个元素进行迭代,并运用 for-in 语法将每个值绑定到本地变量。

驳回的提案

SE-0403 软件包处理器混合言语方针支撑 提案被驳回。该提案已在 三十四期周报 正在检查的提案模块做了具体介绍。

Swift论坛

  1. 提议用户定义的元组一同性

介绍

元组无法符合当今的协议,这以明显的束缚方法表现出来,例如无法运用可哈希值的元组作为字典键。

动机

SE-0283 的动机早年处理了元组符合某些标准库协议的愿望,该动机提出了对 Equatable、Comparable 和 Hashable 元组的内置言语支撑。 独登时,Swift 并发作业添加了一个言语扩展,其间可发送值的元组自身就是可发送的。 我们建议将一切这些特别情况行为与用户定义的元组一同性统一同来,现在能够运用参数包(SE-0393)来表达。 SE-0283 和 SE-0393 都将元组一同性列为未来方向。

建议的处理计划

我们建议引入参数化扩展语法,如泛型宣言中所述。 在一种特定情况下,答应运用此语法以最通用的方法声明元组一同性:

extension <each T> (repeat each T): P where repeat each T: P { ... }

我们还将答应描述元组的通用类型别号通过条件一同性进行扩展; 我们建议将以下元组类型别号添加到标准库中以方便完结:

protocol Shape {
  func draw()
}
typealias Tuple<each Element> = (repeat each Element)
extension Tuple: Shape where repeat each Element: Shape {
  func draw() {
    repeat (each self).draw()
  }
}

回想一下,协议中的要求是由具体符合类型的见证人完结的。 在上面,我们声清楚一个元组扩展,因而draw()的见证者在元组上完结了协议要求 draw()。 实践的完结对每个元素调用 draw(),它自身符合 Shape。 请注意在 draw() 主体的重复方式中每个 self 的运用。

具体规划

任何未符号元组都能够通过“最通用”未符号元组类型的类型替换来获得。 假设每个 T 都是某种类型参数包,则这个最通用的类型是(重复每个 T); 即,由每个 T 的元素的包扩展构成的元组类型。

现在,扩展的扩展类型有必要是名义类型,无论是结构、枚举、类仍是协议。 我们建议答应扩展最通用的元组类型; 这称为元组扩展。 由于扩展能够声明协议一同性,因而元组扩展能够完结最通用元组类型的协议要求。 这称为元组一同性。

这意味着元组扩展中 self 的类型是(重复每个 T),其间每个 T 是声明一同性的扩展的通用参数。 由于 SE-0399,对包扩展表达式中每个 self 的引用将扩展到元组的元素上。

与结构、枚举和类的扩展相同,元组扩展中的 Self 指的是 self 的类型,即(重复每个 T)。

一旦声清楚对某个协议 P 的元组一同性,只需元组的元素满足元组一同性的条件要求,任意元组类型都将满足 P 的一同性要求。 我们将在下面看到,条件要求有必要刚好由重复每个 T:P 的一个要求组成。当对元组类型的值调用协议要求时,由元组类型的元素构成一个包; 这成为调用协议见证中每个 T 的通用参数。

孤儿规则

在大多数情况下,元组一同性的行为就好像它们是标准库类型上的用户定义的追溯一同性。 特别是,两个模块定义两个不同的元组符合同一协议是无效的。 因而,我们制止元组符合定义模块之外的协议。

单元素元组翻开

依据参数包提案中规则的规则,单元素元组类型在替换后翻开。 这意味着元组一同性有必要与此翻开保持一同。

这对元组一同性能够采取的方法施加了一些束缚。 我们能够通过交换图的方法了解以下一切束缚。 最上面一行闪现了最通用的元组类型、相应的元组一同性以及某些相关类型 A 的见证。现在,我们对每个方针应用替换,将每个 T 的类型参数包替换为包含单个具体类型的包, 说 X。我们要求图中一切在同一方针处初步和完毕的途径都产生相同的效果:

(repeat each T) ---> [(repeat each T): P] ---> (repeat each T).A
      |                        |                        |
      |                        |                        |
      v                        v                        v
      X -------------------> [X: P] -----------------> X.A

具体而言,这些束缚如下:

  • 元组扩展有必要声明符合一个协议。

  • 此一同性的条件要求有必要准确重复每个 T: P,其间每个 T 是扩展的类型参数包,P 是一同性协议。

  • 也就是说,一个元组扩展扩展 Tuple: P ,其间重复每个 T: Q 是没有意义的,由于在单元素情况下,它会衰减到 X: P 其间 X: Q; 当 P 和 Q 或许是不相关的协议时,一般情况下该陈说是过错的。

  • P 的相关类型要求 A 有必要由其底层类型刚好为 (repeat (each T).A) 的类型别号见证; 也就是说,从每个元素投影 A 的元组类型。

也就是说,假设 X.A 是 Int,Y.A 是 String,那么我们别无挑选,只能要求 (X, Y).A 等于 (Int, String)。 请注意,由于一切这些规则,空 tuple() 将符合每个具有元组一同性的协议。

动态行为

上述规则使我们能够保证元组一同性见证永久不会被单元素包调用,在这种情况下调用将直接转发到元素一同性。 因而,元组一同性中 Self 的运行时类型有必要始终是实在的元组类型,而不是未包装的元素。

假设某个函数自身运用参数包从包中构成元组值,则对该值调用协议要求将调用元组一同性见证或单个元素的见证,具体取决于包的巨细。

符号元组和方差

元组标签不是参数包能够抽象的东西。 但是,表达式类型系统定义了符号元组和相应的未符号元组之间的子类型联络。

与类类比,假设在非终究类 C 上声清楚一同性,并且存在 D 继承自 C 的子类联络,则该一同性也被 D 继承。

为了在类继承的情况下用 D 替换 C 是有效的,我们要求 Self 仅用于协变或逆变方位,而不是不变的。 因而,我们有必要对元组施加与当时对非终究类相同的束缚。

这答应以下操作:

  • 符合 Equatable 等协议,Self 出现在参数方位。
  • 符合假定的 Clonable 协议,具有回来 Self 的 func clone() -> Self 要求。

另一方面,这是制止的:

  • 符合要求Self方位不变的协议,例如 func f() -> G<Self>

在这种情况下,选用符号元组并将 G<> 应用于相应的未符号元组类型并不彻底合理。

运用范围

由于上面概述的美妙的静态和动态行为,我们期望元组一同性仍然是一项高级功用。 关于许多目的,最好通过 SE-0398 声明一个特别用途的可变参数泛型结构,并使其符合协议,由于这供应了彻底的灵活性,而不会在一同性方面出现任何杂乱情况:

struct EggFactory<each Bird> {}
extension EggFactory: OmletMaker where repeat each Bird: Chicken {}

此方式还答应可变参数类型定义自定义结构函数和访问器以强制不变量等。

元组应该只符合具有明显“代数”完结的协议,该完结以归纳方法推行到元素类型的一切组合,例如上面谈论的三个标准库协议。

例如,使元组符合 IteratorProtocol 或许不是一个好主意,由于至少有两个明显的完结; 要么是紧缩,要么是串联(在这种情况下,我们还需求要求一切序列具有相同的元素类型,这是元组一同性甚至无法表达的)。

  1. 谈论dispatchPrecondition 是完结 @unchecked Sendable 类型的合理方法吗?

我正在检验提高我对何时运用 @unchecked Sendable 有意义的了解。

举个例子,运用 dispatchPrecondition 保证值只能在主线程上读取或批改:

/// A wrapper that guaruntees that its value is only read or modified on the main thread.
/// For simplicity assume `T` is a value type.
final class MainThreadWrapper<T> {
  init(_ value: T) {
    dispatchPrecondition(condition: .onQueue(.main))
    _value = value
  }
  var value: T {
    get {
      dispatchPrecondition(condition: .onQueue(.main))
      return _value
    }
    set {
      dispatchPrecondition(condition: .onQueue(.main))
      _value = newValue
    }
  }
  private var _value: T
}

为了便于谈论,我们假定包装的值是值类型(而不是引用类型),因而我们不需求考虑不通过值设置器的批改。

运用 @unchecked Sendable 一同性将该类型设置为可发送是否合理?

// Is this reasonable, given the expectations of Sendable?
extension MainThreadWrapper: @unchecked Sendable { }

运用这种类型时不或许出现数据比赛。 假设在过错的线程上运用了不正确的类型(例如,在首要参与者之外的使命中),dispatchPrecondition 将失利并阻遏不答应的运用:

struct NotSendable {
  var value: String
}
let wrapper = MainThreadWrapper(NotSendable(value: "foo"))
Task {
  // Allowed by the compiler since wrapper is Sendable, 
  // but a triggers a runtime error:
  print(wrapper.value)
  await MainActor.run {
    // Safe, prints "NotSendable(value: "foo")"
    print(wrapper.value)
  }
}

鉴于这种类型能够安全地跨并发域传递,而不会出现数据比赛,我倾向于认为这是 @unchecked Sendable 的合理用例。

人们怎样看? 我特别有兴趣听到任何潜在的争辩反驳意见。

答复

这儿的包装器的保证证了底层数据的“安全”,但假设该类型在主队伍之外运用过,它会溃散。 这仅适用于声明为 @MainActor 的类型…但是一旦你以这种方法对其进行注释,那么你就现已获得了跨并发域的保证,即你将成为首要演员。

关于“安全”对你意味着什么,@unchecked Sendable 是一个承诺,你的类型能够在任何并发域中运用,并且仍然保护其自己的状况。 我认为这样符号你的包装纸是不正确的。 它仍然只能安全地从主队伍运用。 (假设不是这种情况,它就会快速而有效地溃散。)

  1. 谈论Swift 不会运用 ReferenceWritableKeyPath 编译dictionary,除非它是一个类特点

这段代码编译能够通过:

@objcMembers final class DriversLicense1: NSObject {
    private let map: [String: ReferenceWritableKeyPath<DriversLicense1, String>] = [
        "DAA": \DriversLicense1.nameFull,
    ]
    private(set) var nameFull: String = ""
    override init() {
        super.init()
        for (key, keyPath) in map {
            self[keyPath: keyPath] = key
        }
    }
}

但是,这段代码编译不能通过 – 过错是:

cannot convert value of type 'KeyPath<DriversLicense2, String>' to expected dictionary value type 'ReferenceWritableKeyPath<DriversLicense2, String>'
fileprivate let map: [String: ReferenceWritableKeyPath<DriversLicense2, String>] = [
    "DAA": \DriversLicense2.nameFull,
]
@objcMembers final class DriversLicense2: NSObject {
    private(set) var nameFull: String = ""
    override init() {
        super.init()
        for (key, keyPath) in map {
            self[keyPath: keyPath] = key
        }
    }
}

为什么?

答复 这必定感觉像是一个确诊或许更有协助的当地 – 假设你检验直接在同一方位运用设置器,你会得到更好的消息:

无法分配给特点:“nameFull”设置器无法访问

好像我们能够检查检验 KeyPath -> (Reference)WritableKeyPath 转换的情况,并供应特别的确诊,假设我们能够在 setter 在当时范围内可见的情况下构成恰当的可写密钥途径。

  1. 谈论无法从 Objective C 类调用 swift 扩展方法

我为 ViewController 类创建了 swift 扩展,并在其间定义了一种方法。 当我检验从同一个 Obj-c ViewController 调用相同的方法时,它给出了以下过错:

ViewController 没有可见的 @interface 声明挑选器 testMe

我的代码如下:

Objective-C类

#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self testMe]; // No visible @interface for 'ViewController' declares the selector 'testMe'
}
@end

Swift extension: // ViewController+extnesion.swift

import UIKit
@objc public extension ViewController {
    func testMe() {
        print("Vish")
    }
}

答复

你的 .m 文件需求导入 Swift 编译器宣布的兼容性标头。

  1. 谈论运用类型包的通用结构无法在特点中运用相同类型包存储闭包
struct Foo<each T> {
    let foo: (repeat each T) -> Void
    init(
        fn: @escaping (repeat each T) -> Void
    ) {
        self.foo = fn
    }
}

编译器运用 Xcode 15.0 beta 8 (15A5229m) 和 swift-DEVELOPMENT-SNAPSHOT-2023-09-04-a 工具链响应以下消息

error: type of expression is ambiguous without a type annotation
        self.foo = fn
        ~~~~~~~~~^~~~

举荐博文

SwiftDataKit:让你在 SwiftData 中运用 Core Data 的高级功用

摘要: SwiftDataKit 旨在协助开发者在 SwiftData 中运用 Core Data的高级功用。由于 SwiftData 是 Core Data 的继任者,它在多个方面都对 Core Data 进行了改进和扩展。但是,当时版本的 SwiftData 还不能彻底完结 Core Data 的一切高级功用,这对一些开发者而言或许是一个困扰。

为了处理这个问题,作者创建了 SwiftDataKit 库,通过提取 SwiftData 中底层的 Core Data 方针,使开发者能够在 SwiftData 中运用 Core Data 的高级功用

Swift 中的线程安全性和运用锁的方法

摘要: 这篇文章谈论了 Swift 中的线程安全性和运用锁的方法。首要介绍了线程安全性的重要性,并提到了在代码库中发现的相关问题。接着通过一个简单的示例代码演示了状况处理的概念,并说清楚这种代码或许导致数据比赛和比赛条件的情况。

为了处理这个问题,作者介绍了运用锁机制来控制对同享变量的并发访问。为了完结线程安全,博客展现了怎样在 Swift 中运用 OSAllocatedUnfairLockNSRecursiveLock 两种类型的锁。最后,博客总结了保证类的线程安全性的重要性,并鼓舞在开发过程中前期就投入时间来构建类型安全的代码。

Swift 言语底层原理剖析 – Array 系列-高阶函数

摘要: 文章介绍了Swift的数组中的 filter, forEach, map , compactMap, flatMap, reduce 等函数内部源码,剖析完结逻辑。Array系列的高阶函数其实是 Collection 的高阶函数,相同适宜与 Dictionary , Set 等其他集结类型。整体的规划也比较奇妙,用到了许多 Swift 特有的 Protocol 特性,对我们日后规划 Swift代 码也会有一些启发。

论题谈论

近期华为推出了“ HUAWEI Mate 60 Pro 前锋计划”,实在劫后重生,王者归来。而苹果公司将于 9 月 13 日发布 iPhone 15 系列手机,实在的王者磕碰初步了,那么假设你近期考虑换手机的话,你会怎样挑选呢?

1.果粉无需挑选,犹豫一秒都是对苹果的不尊重。 2.决断选华为呀,超高的性价比,必定理性的挑选。 3.我觉得一两千块钱的小米就挺好的,我再买两斤排骨不香吗?

欢迎在文末留言参与谈论。

关于我们

Swift社区是由 Swift 爱好者一同保护的公益组织,我们在国内以微信大众号的运营为主,我们会共享以 Swift实战SwiftUlSwift基础为中心的技能内容,也拾掇收集优异的学习材料。

特别感谢 Swift社区 批改部的每一位批改,感谢大家的辛苦付出,为 Swift社区 供应优质内容,为 Swift 言语的展开奉献自己的力量。