前言

本期是 Swift 修正组拾掇周报的第三十五期,每个模块已开始成型。各位读者假设有好的提议,欢迎在文末留言。

欢迎投稿或举荐内容。现在计划每两周周一发布,欢迎情投意合的朋友一起参加周报拾掇。

是站在生命之巅,讪笑死神的无能?还是跪在生活边际,寻求生计的或许?Swift社区始于藐小,行至辽阔!

周报精选

新闻和社区:五天市值蒸发 2000 亿美元,苹果公司怎样了?

提案:具有编码验证的 String Initializers

Swift 论坛:Swift 分布式寻找

举荐博文:iOS ReplayKit 与 屏幕录制

论题谈论:

苹果公司正在考虑在今年秋季推出新款 iPhone Pro 时前进其高端手机的价格,那么假设到时候新款 iPhone Pro 在国内的价格逾越了一万元,你还会买吗?

上期论题成果

Swift 周报 第三十五期

从投票成果可以看出来,购买决策不再仅仅只受价格影响,用户更注重手机功能、价值、国产支撑等多个方面。你怎样看~

新闻和社区

五天市值蒸发 2000 亿美元,苹果公司怎样了?

不久前的 6 月份,苹果公司刚成为首家市值逾越 3 万亿美元的企业,但其最新一季的财报却引发了投资者对其手机与其他设备需求不振的担忧。

8 月 4 日,苹果公司发布了三季度财报。财报闪现,苹果第三财季营收 817.97 亿美元,不及上一财年同期的 829.59 亿美元,较上一财季的 948.36 亿美元大幅下滑。在看到新一季财报数据后,投资者惊奇地发现,这家巨无霸上市公司的经营收入现已连续 3 个财季下滑,且苹果在第四季展望中猜想当季体现也不大会有差别。

公司股价连续下跌

苹果公司三季报发布日恰在其新产品 iPhone15 系列新机上市前,但商场预期苹果手机这一新机型受追捧程度不如以往。在失望心情影响下,苹果公司股价在 8 月 4 日财报发布日重挫 4.8% ,创下今年以来最大单日跌幅,市值一天之内蒸发逾 1600 亿美元。然后,苹果股价并未能止住跌势,到本周一(8 月 7 日),苹果的股价现已遭受“五连跌”,股价暴降近 10% ,总市值蒸发逾越 2000 亿美元,约合人民币 1.44万 亿元。

美国银行的分析师在一份成绩陈述中标明,苹果正面对美国智能手机商场疲软的大环境。此外,估值过高或许也是苹果此次下跌的又一重要原因。关于苹果销售额的“三连降”,第一手机界研究院院长孙燕飙标明,消费电子商场持续低迷削弱了对智能手机的需求,叠加创新力缺乏难以拉动新机销量,苹果手机的销售收入连续下滑。假设苹果在第四财季的销售额持续同比下降,这将是该公司 20 年来销售额同比下降持续时间最长的一次。(来历:金融时报)

在你的 App 中协助顾客处理账单问题

正如咱们在 4 月份宣告的那样,很快,你的顾客就能直接在你的 App 中处理付款问题,以便更轻松地持续订阅你的内容、服务和高级功用。

自 2023 年 8 月 14 日起,假设主动续期订阅因账单问题而无法续订,你的 App 中会闪现一个系统供应的表单,提示顾客更新其 Apple ID 的付款方法。你可以在沙盒中先测试一下此表单,还可以运用 StoreKit 中的 messages (英文) 和 display (英文) 来推迟或制止闪现此表单。这项功用在 iOS 16.4 和 iPadOS 16.4 或更高版别中供应,无需采纳任何操作即可选用。

需求声明原因的 API 列体现已推出

Apple 致力于保护咱们途径上的用户隐私。咱们知道,有一小部分 API 或许会被乱用来通过信息指纹搜集用户设备的相关数据,这是咱们的 Developer Program 容许协议制止的一种做法。为了防止乱用这些 API,咱们在 WWDC23 (英文) 上宣告了开发者需求在 App 的隐私清单中声明运用这些 API 的原因。这将有助于保证 App 仅将这些 API 用于预期用途。在这个流程中,你需求选择一个或多个可以准确反映你的 App 怎样运用相应 API 的同意原因,而且你的 App 只能出于你选择的原因运用相应 API。

从 2023 年秋季开端,假设你上传到 App Store Connect 的新 App 或 App 更新运用了需求声明原因的 API (包括来自第三方 SDK 的内容),而你没有在 App 的隐私清单中供应同意的原因,那么你会收到告诉。从 2024 年春季开端,若要将新 App 或 App 更新上传到 App Store Connect,你需求在 App 的隐私清单中注明同意的原因,以准确反映你的 App 怎样运用相应 API。

假设现在同意原因的包括规模内并未包括某个需求声明原因的 API 的用例,且你深信这个用例可让你的 App 用户直接获益,请告诉咱们。

提案

通过的提案

SE-0403 软件包管理器混合言语政策支撑 提案通过查看。该提案已在 三十四期周报 正在查看的提案模块做了详细介绍。

正在查看的提案

SE-0405 具有编码验证的 String Initializers 提案正在查看。

咱们主张添加新的 String 可失利 Initializers,用于验证编码输入,并在输入包括任何无效元素时回来 nil

Swift论坛

  1. 谈论Swift 字符串比较不将连字等同于其组件

内容大约

我刚刚发现 Swift 字符串将 “office” 和 “office” 视为不持平,这让我感到惊奇,由于它将 “caa” 和 “caa” 视为持平(即,都是组合和分解方式)。关于一般用户来说,这些状况是等价的 – 它们只是以不同的方法标明相同的字形(至少在某些字体中是如此)。

我进行了一些调查,如同这是由于 Swift 许诺在 Unicode 术语中运用 “规范” 比较,而不是 “兼容” 比较。文档说到了这一点,但没有解说其含义。

我进一步查找并发现了有关 Unicode 中连字的一些争议和前史,这或许会为此供应一些启示(例如,现在 Unicode 关于连字的观念如同是不应该用于字距调整,例如 “ffi”,但它依然包括一些”不恰当” 的连字 – 再次,如 “ffi” – 这些连字是在这种心态改动之前添加的)。

NSString 也类似,除非你在运用 compare(_:options:) 时选择了 caseInsensitive 选项,这时它会将连字视为其分解方式。这很乖僻,由于这与字符大小写无关。

我猜这篇文章首要是向其他人供应信息和警告。但我很猎奇为什么 Swift 选择实行 “规范” 比较,而不是 “兼容” 比较?此外,如同在 Swift 规范库中没有方法实行 “兼容” 比较 – 有必要导入 Foundation 才华获取字符串堆叠部分,以便访问前面说到的 NSString 方法。

答复

兼容性分解是 Unicode 在需求与前期编码兼容(作为超集)的状况下所迫不得已的退让。假设这些字符直接提议给 Unicode,它们将永久不会被编码。通常状况下,即便您在运用它们,也或许是在做差错的作业,由于它们所编码的内容(例如连字)不是文本的特色,而是闪现格局的特色。

在 Unicode 的观念中,它们本身就不应该出现在原始字符串中。但是,将它们折叠到规范方式会丢掉有关格局的信息,因此不能安全地运用于实践运用了它们的传统文本。(以“ff”为例,不是每一对“f”都要在闪现中衔接;那些跨过复合词两半的“f”应该坚持分隔。不能通过简单查看上下文来康复这种差异,需求手动进行或通过字典查询来结束。)这与类似“”的规范分解根本不同,后者在规范化进程中不会丢掉信息。

假设想知道两个字符串是否在兼容性方面是等价的,则可以运用 Foundation 的 decomposedStringWithCompatibilityMapping 方法。

  1. 提议Swift 分布式寻找

动机

尽管 Logging 和 Metrics 可以用于仪器化运用程序的特定部分,但 Distributed Tracing 供应了对整个分布式系统的全体视图。与这两者一起,分布式跟踪将结束“可调查性的三大支柱”。

与 Logging 和 Metrics 相同,假设在库和结构中直接运用一个一起的 API 来结束分布式跟踪,社区将从中获益最多。最终用户应该可以自由选择适宜的后端结束,而无需更改他们正在运用的库或结构。

主张的处理计划

Swift 分布式跟踪围绕着创建跨度(span),这些跨度一起构成一种树状结构。跟踪可以由在单个服务中记载的跨度组成,也可以跨多个服务传达。Swift 分布式跟踪运用根据使命本地的 Swift Service Context 来结束通明的传达,无需手动传递上下文。

咱们提出的处理计划是一个针对三个“人物”的库:

  • 终端用户
  • 库和结构作者
  • 跟踪器后端结束

用户端

最终用户是从分布式跟踪中获益的人。他们选择适宜自己需求的跟踪后端,运用具有内置的 Swift 分布式跟踪支撑的库,并在自己的代码中进行手动仪器化。

库和结构作者

比方 HTTP 服务器/客户端、数据库库等库/结构最了解怎样仪器化其库的内部。他们运用 Swift 分布式跟踪 API 结束通用的跟踪支撑,而无需考虑特定的跟踪后端。

比方:

  • Hummingbird
  • Soto

跟踪后端结束

最后一个难题是跟踪器后端结束。它们为导出跟踪 span 供应特定于供货商的支撑。

比方

Swift OTel 公开了一个导出到 OpenTelemetry Collector 的跟踪器。这现已容许该跟踪库的选用者导出到与 OpenTelemetry 兼容的盛行后端,例如 Zipkin、Jaeger、Honeycomb 等。

到期理由

咱们提议这个软件包处于“孵化”老到度等级。 咱们信任这个包是服务器生态系统的重要构建块,就像许多服务器和客户端库选用 swift-log 和 swift-metrics 相同。

该项目现已老到逾越3年,有多个活泼的保护人员,而且在出产环境中满足了选用要求。

  1. 谈论AttributedString 索引获取导致 nil 值的内部解包

问题描绘

我有一个富文本字符串,其间一个子字符串正在被替换,但是会引发 fatalError:

var string = AttributedString("caf")
let replaceIndex = string.index(beforeCharacter: string.endIndex)
let range = replaceIndex..<string.endIndex
string.replaceSubrange(range, with: AttributedString("e"))
let next = string.index(afterCharacter: replaceIndex)
//                ^---- Unexpectedly found nil while unwrapping an Optional value
assert(next == string.endIndex)

这令人惊奇,由于我认为在更改之前,索引会坚持稳定。更乖僻的是,改动怎样创建规模不会导致失利。以下代码可以正常作业:

var string = AttributedString("caf")
let range = range(of: "")!
string.replaceSubrange(range, with: AttributedString("e"))
let next = string.index(afterCharacter: replaceIndex)
assert(next == string.endIndex)

运用 ASCII 字符而不是重音符号 ” 不会导致两种规模技能中的任何一种失利。我细心分析了开源结束,试图提醒出现 nil 可选值的源头,但我看不到任何问题,我认为这与其时发布的代码不同。

关于我哪里的逻辑出了问题,有什么主张吗?

我运用的是 macOS 13.4.1 和 Xcode 15b5。

答复

明晰一点,RangeReplaceableCollection 的变异操作或许会使现有索引失效,由于这些索引或许包括关于变异集结不再有用的信息(例如,在字符串的状况下,计算的字节偏移不再有用)。从 RangeReplaceableCollection.replaceSubrange(_:with:) 文档中可以看出:

调用此方法或许会使任何现有索引在与此集结一起运用时失效。

而且,这个方法几乎是 RangeReplaceableCollection 上一切其他操作的基础,所以人们应该假定(除非为特定类型还有阐明)任何或许改动索引相关信息的变异操作都会使现有索引失效。

  1. 提议导入语句的访问等级

这是一个关于在 Swift 中更好地控制依托和导入的提案。通过这个特性,可以将导入标记为公共的(其时的常规导入方法),关于模块的结束细节,可以标记为内部,关于源文件的结束细节,可以标记为私有或文件私有。

别的,更新后的包访问等级容许将依托标记为仅对同一包中的模块可见。这会像源文件中的常规访问等级相同进行强制实行。将作为内部导入的声明只能从内部声明或更低的访问等级中引用,而在公共或包声明中运用则会报错。

下面是一个典型的用例,其间依托项是咱们不希望在模块 API 中露出给客户端的结束细节,以及预期的确诊信息:

internal import DatabaseAdapter
internal func internalFunc() -> DatabaseAdapter.Entry { ... } // Ok
public func publicFunc(entry: DatabaseAdapter.Entry) { ... }
// error: function cannot be declared public because its parameter uses an internal type
public func useInBody() {
    DatabaseAdapter.foo() // Ok
}
@inlinable
public func useInInlinableBody() {
    DatabaseAdapter.foo()
    // error: global function 'foo()' is internal and cannot be referenced from an '@inlinable' function
}

该提案还界说了一组条件,其间可以从客户端躲藏依托项。这供应了一种强壮的方法来完全躲藏结束细节,并可以加快客户端的构建时间。

这个提案旨在供应一个正式且更明晰的替代计划,来替代 @_implementationOnly。与此相反,此版别供应了了解的确诊信息,更多等级的控制,以及与非弹性模块和 @testable 客户端更好的兼容性。

根据社区对主张的 Swift 6 行为的反响,咱们可以将其归入该提案。

  1. 谈论序列化文件访问的 Actor

问题描绘

我想知道运用 Actor 是否是保护资源免受并发访问的好选择,例如一个文件目录。在曩昔,我曾运用 dispatch queues 结束这种状况。运用 Actor 作为堵塞文件访问 API 的通道点的优缺点是什么?

答复

仅仅是在文件系统中进行典型的CRUD操作

在这儿,Actor并不能协助你。即便在 Actor 可重入性的考虑之外,从 Actor 外部调用的 Actor 方法的实行次第也无法保证。

CRUD 操作现已是线程安全的(假设它们不是,那将是一个适当令人失望的文件系统)。由于 Actor 不以实行方法的调用次第“串行化”任何内容,因此不需求 Actor。

或许需求的是一个 FIFO 队列,这便是(串行的)DispatchQueue 处理计划为此供应的优点。

现在,假设议论的是将一系列操作有用地“原子化”(例如,在枚举目录时不容许同时对其进行变异),那么需求保护的是一些可变状态,Actor 可以保护它。在我看来,这是比 CRUD 更高层次的抽象。在这方面,我认为 @tera 的问题在这儿比幻想的更相关。

  1. 谈论L-shaped 枚举

问题描绘

用于短少更好的术语,我有许多“L-shaped”枚举,它们具有一些不同的有用载荷类型和一些一起的有用载荷类型。

以下是一个示例:

extension ServerDelegate
{
    enum Request:Sendable
    {
        case get    (Get, EventLoopPromise<ServerResponse>)
        case post   (Post, EventLoopPromise<ServerResponse>)
        case delete (Delete, EventLoopPromise<ServerResponse>)
    }
}
extension ServerDelegate.Request
{
    enum Get { ... }
    enum Post { ... }
    enum Delete { ... }
}

这种布局存在问题:

很难访问一起的字段(EventLoopPromise<ServerResponse>),除非在枚举上进行 switch 操作。

很难在实践的变体有用载荷上进行 switch,由于您有必要运用 _ 疏忽一起字段。

这儿有一个明显的重构方法,即将变体有用载荷提升到另一个嵌套类型:

extension ServerDelegate
{
    struct Request:Sendable
    {
        let operation:Operation
        let promise:EventLoopPromise<ServerResponse>
    }
}
extension ServerDelegate.Request
{
    enum Operation:Sendable
    {
        case get    (Get)
        case post   (Post)
        case delete (Delete)
    }
}
extension ServerDelegate.Request.Operation
{
    enum Get { ... }
    enum Post { ... }
    enum Delete { ... }
}

但这感觉像是过多的嵌套和(过多?)的类型结构,与我测验建模的复杂性成正比。而且 ServerDelegate.Request.Operation.GetServerDelegate.Request.Operation.Post 等枚举本身或许还有更多的嵌套结构。

咱们有哪些替代计划呢?”

答复

命名空间中的点是嵌套的成果,这与这儿的类型结构并不是真实的基本关系。供应便当的 API 来处理一些 .init 繁琐的状况如同也是合理的,例如:

extension Request {
  static func get(url: URL, params: [String: String], mintPromise: () -> EventLoopPromise) -> Self { ... }
}

举荐博文

iOS ReplayKit 与 屏幕录制

摘要: 这篇文章首要介绍了运用 Apple 的 ReplayKit 结构来结束屏幕录制功用,包括运用内录制和系统级录制。 ReplayKit 从 iOS 9中第一次供应,现已展开并增强了许多特性。文章对创建和接入 ReplayKit Extension ,系统级录制流程,以及在 LOOK 直播中的实践比方等进行了详细介绍。但是,屏幕录制开发面对着一些挑战,如内存束缚、开发和调试困难、内存控制等。文章强调在开发进程中要小心应对这些问题,坚持内存运用远离 50MB 的束缚阈值,以及充分利用日志来处理问题,使可以高雅地结束屏幕录制功用。

TheRouter-iOS 轻量化路由中间件

摘要: TheRouter 是一款由货拉拉打造的轻量级路由中间件,旨在支撑 Android 和 iOS 途径。该中间件在 iOS 端吸取了其他言语的特性,添加了注解功用,强化了路由在 iOS 端的运用体验。 TheRouter 摒弃了传统 iOS 的 target-action 或 protocol 理念,对齐了更广泛的后台或 Android 运用。首要功用包括依托注入、硬编码消除、动态化才能和页面导航跳转才能。文章详细解说了 TheRouter 的结束原理,如注解式依托注入,途径硬编码处理等,并供应了详细的运用介绍和示例。

iOS App Store 上架被拒 case

摘要: 这篇文章首要记载了 App Store 上架进程中遇到的一些被回绝的事例,以及对应的原因分析和处理战略。事例包括了从功用完整性、信息需求、隐私承认,到软件需求和上传被拒等不同阶段的问题。文章还详细阐述了各种问题的发生原因,如 APP 功用不全、集成未运用的库、隐私信息填写不全等,并提出相应的处理计划。通过这些事例的同享,开发者可以理解和学习怎样避免类似的差错,更顺利地结束 App Store 的上架进程。

论题谈论

报导称曾红极一时的少儿编程训练,如今现爆雷隐患。你认为儿童是否有必要提早触摸编程课?

  1. 有必要:编程课可以激起儿童创造力,培育处理问题的才能。
  2. 没必要:短少基础和老到度,编程需求数学和逻辑思维才能,导致理解困难和挫败感。
  3. 因人而异:有些儿童适宜提早触摸,有天赋和热情,发挥潜力,其他儿童可以在稍后阶段考虑。

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

关于咱们

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

特别感谢 Swift社区 修正部的每一位修正,感谢咱们的辛苦付出,为 Swift社区 供应优质内容,为 Swift 言语的展开贡献自己的力气。