前语

本期是 Swift 编辑组整理周报的第三十六期,每个模块已开端成型。各位读者假如有好的提议,欢迎在文末留言。

欢迎投稿或引荐内容。现在计划每两周周一发布,欢迎志同道合的朋友一起参加周报整理。

一米阳光下阴雨连绵,一米阳光上晴空万里,这便是生活。Swift社区伴你一起,走过风雨,沐浴暖阳!

周报精选

新闻和社区:iPhone 15 全系配 USB-C 苹果回绝接口和安卓互通

提案:对 AsyncStream 的 Backpressure 支持

Swift 论坛:提议大局变量的严厉并发

引荐博文:WWDC23 10105 – 打造呼应更快的相机体会

话题评论:

日本核污水排海,你还会吃海鲜吗?

上期话题成果

Swift 周报 第三十六期

根据投票成果能够看出,咱们有不同的主意。小编认为家长应该根据孩子的个性特点和兴趣爱好灵活调整,重视培育他们的立异精神和独立思考才能。

新闻和社区

音讯称苹果公司和印度财政部官员商量,扩展在印度的制作产能

8 月 25 日音讯,根据印度当地媒体 Business Today 报导,苹果印度地区的高管现已和当地财政部会晤,探讨扩展 iPhone 在印度产能相关事宜。

音讯称本次探讨触及面很广,印度政府期望以苹果公司带头下,进一步推进本土智能手机制作业,并商量相关的扶持方针。

而苹果公司在沟通中也表明,印度是非常重要的生产地和消费商场,乐于扩展在印度商场的产能,但期望能获得更多的补贴,以及方针福利。

IT之家此前报导,根据商场调查机构 Counterpoint Research 发布的统计数据,2023 年第 2 季度印度商场营收表现首次超越法国和德国,成为苹果第五大 iPhone 商场。

苹果 iPhone 零售业在印度商场的快速增长的一起,苹果也加快了 iPhone 在印度制作的脚步。苹果加大了在印度商场的出资力度,期望供应链完成多元化开展。(来源:IT之家)

iPhone 15 Pro 机型新增泰坦灰

新烘托图曝光,音讯称苹果 iPhone 15 Pro 机型泰坦灰将代替金色 iPhone15Pro新增灰色。8 月 25 日音讯,根据国外科技媒体 9to5Mac 报导,苹果本年将调整 iPhone 15 Pro 和 iPhone 15 Pro Max 两款机型的色彩选项,撤销金色,新增灰色。 在最新报导称这种全新灰色官方名称为“泰坦灰”(Titan Gray),并共享了这种色彩的概念烘托图,能够看到“泰坦灰”色彩要比现有的银色 / 白色更深一些,但比深空黑要更淡一些。 该媒体还泄漏苹果本年推出的 iPhone 15 Pro 机型将会撤销暗紫色,并由深蓝色代替。 注: iPhone 14 Pro 机型共有暗紫色、金色、银色和深空黑四种色彩。 苹果预估将于 9 月 12 日发布 iPhone 15 系列,其间 iPhone 15 系列标准版将有黑色,绿色,蓝色,黄色和粉红色。(来源:IT之家)

Swift 周报 第三十六期

iPhone 15 全系配 USB-C 苹果回绝接口和安卓互通

8月19日音讯,据供应链最新音讯称,iPhone 15 全系将会装备 USB-C 接口,不过不同类型会被差异对待。

依照供应链说法,iPhone 15 标准版仅仅装备一般版别的 USB-C 接口,而 iPhone 15 Pro 系列则在速度上有明显的进步,一起这个功用只能在 MFi 认证的 USB 数据线下发挥功效。

具体来说便是,iPhone 15 标准版供给 USB 2.0 版别,传输速度最高 480 Mbps,与之前的 Lightning 接口差不多。而 iPhone 15 Pro 系列用的是 USB 3.2,传输速度能到达 20 Gbps,比标准版快 20 倍以上。

关于消费者来说,这将是多年来 iPhone 系列手机最大的改进之一。装备该端口后,iPhone 用户在旅行时不再需求为手机和其他移动设备带着两根不同的充电线,不过主意是好的,但苹果却不会这么干。

依照供应链配件商的说法,苹果不会让 iPhone 15 的 USB-C 接口与安卓通用,即便是有违法的行为,但依然会如此做,毕竟 MFi 认证背面一年是几十亿美元的盈利。

此外,从苹果的备货来看,Pro 系列占比超越 60%,他们也是想从这些细节的当地卡位用户,让咱们主动去买高价版别。

Swift 周报 第三十六期

提案

正在查看的提案

SE-0407 成员 Macro 一致性 提案正在查看。

SE-0402中从一致性宏到扩展宏的转变包含扩展宏能够了解类型现已遵从了哪些协议(例如,由于遵从了超类或在某处声明晰显式一致性),这样宏就能够避免增加不需求的声明和一致性。这也意味着增加的任何新声明都是扩展的一部分——而不是原始类型定义的一部分——这一般是有利的,由于这意味着(例如)新的初始化器不会按捺成员初始化器。将协议一致性拆分为各自的扩展一般也被认为是一种很好的办法。

可是,有时用于一致性的成员确实需求成为原始类型定义的一部分。例如:

  • 非 final 类中的初始化项有必要是必需的初始化项,以满足协议要求。
  • 非 final 类的可重写成员。
  • 存储的特点或大小写只能在主类型定义中。

关于这些状况,成员宏能够生成声明。可是,成员宏并没有供给任何关于应该为哪种协议一致性供给成员的信息,因而宏或许会过错地尝试将一致性成员增加到现已符合协议的类型中(例如,经过超类)。这或许使某些宏(例如完成 EncodableDecodable 协议的宏)无法完成。

SE-0406 对 AsyncStream 的 Backpressure 支持 提案正在查看。

SE-0314引进了新的 Async[Throwing]Stream 类型,作为根异步序列。这两种类型答应从同步回调(如托付)桥接到异步序列。该提案增加了一种构建异步流的新办法,意图是将 Backpressure 系统桥接成异步序列。此外,该提案旨在弄清消费使命撤销和生产方表明停止时的撤销行为。

Swift论坛

  1. 提议宏文字协议

现在仅答应在顶层运用宏。 可是,在某些状况下,嵌套宏会很有好处。

例如,咱们能够增加具有宏要求的新文字协议:

public protocol ExpressibleByMacroIntegerLiteral {
  associatedtype IntegerLiteralType: _ExpressibleByBuiltinIntegerLiteral
  @freestanding(expression)
  macro Init(integerLiteral: IntegerLiteralType) -> Self
}

然后用编译器的魔法,酱子:

let x: Decimal = 5.3

能够变成酱子:

let x = #Decimal.Init(integerLiteral: 5.3)

然后将扩展

我知道宏的设计方针之一是避免这种不可见的宏运用,可是现已有很多编译器魔法能够经过 _ 文字协议来表达,这将使它们愈加通用。

例如,当时假如类型是 ExpressibleByStringLiteral 但只要某些字符串文字有效,则仅有的挑选是在运转时遇到无效字符串文字时捕获。 这违反了文字的编译时性质,而文字应该答应查看文字。 在基金会提出将 URL 改为 ExpressibleByStringLiteral 时,这个问题在某种程度上被掩盖了,但现已完全处理了。

这个句子:

downloadFile(at: "https://apple.com")

看起来比这个好很多:

downloadFile(at: #URL("https://apple.com"))
  1. 提议嵌套 if let 和 guard let

介绍

在 Swift 中,if let 句子一般用于可选的解包。 它经过处理可选值帮助开发人员编写更干净、更安全的代码。

现在,if let 句子解包单个可选值。 可是,在某些状况下,咱们期望以更简洁的办法解开嵌套方针的可选特点。

该提案建议扩展 if let 和 Guard let 句子以支持嵌套可选展开。

1. if let 嵌套

嵌套 if let 的拟议语法将答应开发人员有条件地解包嵌套方针的可选特点。 如下:

if let myOptionalObject?.optionalValue {
    // 'optionalValue' is now safely unwrapped and ready to use // *1
} else {
    // Handle the case where 'optionalValue' is nil
}

2. 嵌套的 guard let

类似地,所提议的嵌套 Guard Let 语法将答应开发人员有条件地解开嵌套方针的可选特点。 如下:

guard let myOptionalObject?.optionalValue else {
    // Handle the case where 'myOptionalObject' or 'optionalValue' is nil
    // This could include returning from the current function, loop, or throwing an error
}
// 'optionalValue' is now safely unwrapped and ready to use // *1
  1. 提议大局变量的严厉并发

介绍

该提案定义了无数据竞赛的大局变量的运用选项。 在此提案中,大局变量包含静态持续时间的任何存储:在大局范围内声明或作为静态成员变量声明的 let 和存储变量。

动机

大局状况在并发性中提出了应战,由于它是能够从任何程序上下文拜访的内存。 大局变量在数据阻隔查看中受到特别关注,由于它们违反了其他强制阻隔的尝试。

本地且未捕获的变量只能从本地上下文拜访,这隐式地阻隔了它们。 值类型的存储特点现现已过排他性规则阻隔。

能够经过运用可发送性强制或运用参与者束缚来阻隔引证类型的包含方针,然后阻隔引证类型的存储特点。 但大局变量能够从任何当地拜访,所以这些东西不起作用。

建议的处理计划

在严厉的并发查看下,要求每个大局变量要么与大局参与者阻隔,要么两者都阻隔:

  • 不可变的(immutable)
  • 可发送类型(Sendable)

immutable 而且 Sendable 的大局变量能够从任何上下文安全地拜访,否则需求阻隔。

具体设计

这些要求能够在声明时在类型查看器中强制执行。

源兼容性

由于增加了束缚,因而在运用严厉的并发查看时或许需求更改某些类型声明。 可是,此类源代码更改依然向后兼容任何具有并发功用的 Swift 版别。

ABI兼容性

该提案本身不会增加或影响 ABI(Application Binary Interface),可是它或许对选用的项目引发的类型声明更改或许会影响该项意图 ABI。

对选用的影响

在选用严厉并发查看的项目中,或许需求修正某些大局变量类型。

考虑的代替计划

为了阻隔,咱们能够隐式锁定变量的拜访,而不需求大局参与者。 在供给内存安全的一起,这或许会给线程安全带来问题,由于开发人员能够轻松编写 non-atomic 的形式:

// value of global may concurrently change between
// the read for the multiplication expression
// and the write for the assignment
global = global * 2

虽然假如咱们需求在旧言语形式中做一些源兼容的事情,咱们能够考虑隐式锁定,但一般咱们的办法仅仅说旧言语形式是并发不安全的。

它也不适用于非可发送类型,除非咱们强制该值在拜访它时坚持阻隔。咱们或许能够经过提议的跨阻隔域安全发送不可发送值功用来完成这一方针,但这或许是一个过于先进的功用,无法作为此类基本问题的处理计划来推进。

咱们能够将一切需求阻隔的大局变量默认为 @MainActor。 能够说,让开发人员考虑挑选会更好(例如,也许它应该仅仅一个 let 常量)。

拜访控制在理论上是有用的:例如,咱们能够知道大局变量是并发安全的,由于它是文件私有的,而且该文件中的一切拜访都来自单个大局参与者上下文,或者由于它永久不会 变异了。

不过,这比咱们一般期望在编译器中进行的分析愈加大局化; 咱们有必要查看上下文中的一切内容,然后开发人员或许很难理解它为什么起作用。

未来开展方向

咱们不一定需求明确地要求阻隔全球参与者; 有空间推断正确的全球行动者。 大局人物束缚类型的大局可变变量能够被推断为束缚到该大局人物(虽然假如变量是不可变的,则没有必要,由于大局人物束缚类类型是可发送的)。

  1. 评论用 globalActor 符号的办法修正类中的特点
protocol Po {
    @MainActor
    func foo()
}
class Base: Po {
    var str = ""
    func foo() {
        str = "w"
        print("foo: \(Thread.isMainThread)") // true
    }
}
if #available(macOS 10.15, *) {
    Task {
        let b = Base()
        await b.foo()
    }
} 
RunLoop.main.run()
while true {}

我不明白为什么我能够直接在标有MainActor的办法中修正特点?

由于这对我来说似乎是过错的。 我相信 Base 及其特点不在 MainActor 上运转。

答复

您在顶层创立 Task,这隐式地使其在 main actor 上运转。 由于 Base 仅仅一个类(而不是 actor),因而它的办法在其调用者所在的任何上下文中运转,在本例中这是 main actor。 特点和办法能够独自与特定参与者相关联,包含作为协议要求的一部分。 在这种状况下 foo 隐式是 @MainActor,由于 Po 协议如此声明它。

这或许有点太奇特了 – foo 也是隐式异步的,虽然它从未真正被符号为异步,即便在原始协议声明中也是如此。

为了进一步测验这一点,假如您增加到 Base 例如:

func bar() {
    foo()
}

将收到编译器过错 Call to main actor-isolated instance method 'foo()' in a synchronous nonisolated context,表明编译器将 foo 视为 @MainActor(但 Base 的其余部分不是)。

  1. 评论[在 “super.init” 调用之前运用的 “self” 与 “在 super.init 调用时未初始化特点” 冲突](forums.swift.org/t/self-used… “在 “super.init” 调用之前运用的 “self” 与 “在 super.init 调用时未初始化特点” 冲突”)

我需求在 init 中创立一个捕获 self 的闭包来初始化特点,但我无法运用 self,由于 super.init 尚未被调用。 可是,我无法调用 super.init,由于该特点尚未初始化!

import Foundation
class Base {
}
class Sub: Base {
    let timer: Timer
    var value = 0
    // option 1 - try to initialize the property
    override init() {
        // ERROR: 'self' used before 'super.init' call
        timer = .scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in
            self!.value += 1
        }
        super.init()
    }
    // option 2 - try to initialize super first
    override init() {
        super.init()  // ERROR: Property 'self.timer' not initialized at super.init call
        timer = .scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in
            self!.value += 1
        }
    }
}

除了使特点既可选又可变(在 super.init 期间初始化为 nil,然后在之后更改它)之外,还有什么办法能够处理这个问题吗?

我有点明白为什么编译器不能承受这种状况,可是有必要使特点可选且可变,这很烦人,而一旦类完全初始化,它实际上既不应该为零,也不应该变。

答复

需求在函数内有一个本地变量:

init() {
    var futureSelf: Sub? = nil
    timer = .scheduledTimer(withTimeInterval: 1, repeats: true) { [weak futureSelf] _ in
            futureSelf?.value += 1
        }
    super.init()
    futureSelf = self
}

值得注意的是,编译器无法知道选用闭包捕获 self 的方针是否不会立即被调用,而且它试图避免运用半初始化的 self 实例调用闭包。

  1. 评论显式运用引证类型后是否应该调用 deinit?

我想经过运用 _ = Consumer 方针显式完毕演员/类的生命周期,以避免引进具有独自作用域的另一级嵌套。 可是,在显式消费之后不会调用该方针的 deinit。 相反,它是在作用域结尾调用的。 这是预期行为还是编译器过错? 关于不可复制的结构,它能够按预期作业。

class Object {
    deinit { print("deinit object") }
}
struct Noncopyable: ~Copyable {
    deinit { print("deinit noncopyable") }
}
func testDeinitAfterConsume() {
    do {
        let object = Object()
        print("before consume")
        _ = consume object
        print("after consume")
    }
    print()
    do {
        let noncopyable = Noncopyable()
        print("before consume")
        _ = consume noncopyable
        print("after consume")
    }
}

打印成果:

before consume
after consume
deinit object
before consume
deinit noncopyable
after consume

答复

这是能够理解的。 一般来说,每逢方针丢掉最终一个引证时,类析构器就会运转,而不考虑变量范围。

在某种程度上不鼓励在类去初始化中依靠共享可变状况,而且强烈不鼓励依靠与惯例代码中的副作用相关的顺序。 即便没有优化,它一般也会很棘手而且容易出错。

对方针生命周期的显式控制是 Swift 中依靠类撤销初始化顺序的官方办法:

withExtendedLifetime(object) {
    // Modify shared mutable state without accessing object.
}

关于局部变量(包含参数),编译器(5.7 后)遵从一些保守的生命周期规则,以便大多数“看起来正常”的编程形式无需显式生命周期管理即可作业。 事实上,假如咱们依照字面意思理解这个示例,则 deinit 将不会发生,而且咱们永久不会看到以下输出:

deinit object
before consume
after consume

额定的安全规则是:

假如不安全指针或弱引证或许依靠于局部变量的生命周期,则编译器会主动扩展该变量持有的任何引证。

假如惯例代码在 Swift 外部调用(包含一切 I/O)或跨使命同步(调用异步函数),则类析构器将不会跨这些鸿沟从头排序。 这也意味着程序员能够经过增加同步代码来控制方针的生命周期,而无需 withExtendedLifetime。 在此示例中,调用 “print” 被视为同步点,然后阻止优化。

这里有更具体的描述:gist.github.com/atrick/cc03… 在这方面,耗费参数与 “let”、“var” 和非 “耗费” 参数不同,由于它们的生命周期能够在隐式耗费时提前完毕:

func bar(_ object: consuming Object) {}
func foo(object: consuming Object) {
    bar(object)
    print("after consume")
}

总是得到成果:

deinit object
after consume

这为那些关心 ARC 开支和 CoW 行为的人供给了抱负的编程模型。 很快,我期望一切局部变量都具有“耗费”的作用。

引荐博文

把握 StoreKit2

摘要: 本文介绍了 Swift 中的 StoreKit2,这是一个用于构建运用内购买和订阅的结构。文章从配置项目和创立 StoreKit 配置文件开端,介绍了如何运用 Store 类型处理运用内购买逻辑。经过示例代码和说明,文章展现了如何运用 Store 类型来获取和显示运用内购买产品列表,并发动购买流程。还介绍了产品类型和其 purchase 函数,在成功购买时处理买卖和验证进程。文章还触及了处理挂起状况和监视买卖更新的办法。此外,提到了 StoreKit2 供给的 currentEntitlements 特点,用于获取活动订阅和已购买产品列表。最终,文章给出了一个基本的 App 结构示例,其间包含了 Store 方针,并在运用程序发动时获取活动买卖。

iOS 防 dump 可行性调研陈述

摘要: 文章介绍了如何避免 iOS App 被 dump ,包含代码混淆、加密、完整性查看等多层防护策略,以及服务器端验证、动态加载、API 安全性和多要素认证等计划。此外,监控与告警、定时安全审计和安全培训等后置计划也能够进步 App 的安全性。最终,还介绍了禁止越狱设备的实施计划,以及 DeviceCheck 和 App Attest API 等新技术计划。

WWDC23 10105 – 打造呼应更快的相机体会

摘要: 文章介绍了 iOS17 供给了一些新的特性,经过推迟图片处理、快门零推迟、呼应捕获等新特性,以及状况监听等措施,能大幅进步相机呼应速度,发明更流通的拍照体会。

话题评论

日本核污水排海,你还会吃海鲜吗?

  1. 不会

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

关于咱们

Swift社区是由 Swift 爱好者共同维护的公益安排,咱们在国内以微信大众号的运营为主,咱们会共享以 Swift实战SwiftUlSwift基础为核心的技术内容,也整理搜集优秀的学习材料。

特别感谢 Swift社区 编辑部的每一位编辑,感谢咱们的辛苦付出,为 Swift社区 供给优质内容,为 Swift 言语的开展奉献自己的力量。