前言

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

欢迎投稿或推荐内容。目前计划每两周周一发布,欢迎志同道合的朋友一起加入周报整理。

渺小不可怕,可怕的是比你优秀的强者还比你更加努力。Swift社区不会辜负每一位努力的勇士,优秀终将与你不期而遇!

周报精选

新闻和社区:因iPhone销量下降 苹果利润2016年以来首次低于预期

提案:新年开始多个提案状态发生变化

Swift 论坛:讨论如何设置需要异步初始化的静态变量

新闻和社区

因 iPhone 销量下降,苹果利润 2016 年以来首次低于预期

2 月 3 日凌晨,多家美股科技巨头公布财报。苹果 2023 财年 Q1 净利润录得 299 亿美元,低于市场预期,原因是 iPhone 的供应出现问题,导致销售疲软。苹果当季销售额下降 5% ,至 1172 亿美元,全球各地的销售额均出现下滑。除服务和 ipad 以外,所有产品类别的销售额都有所下降。这是自 2016 年以来苹果首次未能达到华尔街的利润预期。不过,苹果CEO库克在最新业绩会上表示,中国市场的需求已经有非常好的复苏,去年 12 月和 11 月相比市场确实发生了很大变化。库克还表示,苹果将很快在印度开设第一批零售店。

App 和 App 内购买项目即将实行税率和价格调整

App Store 的交易和支付机制旨在帮助您在覆盖全球的 175 个国家和地区的商店中,以 45 种货币为您的产品和服务便捷地进行定价与销售。我们会根据税款和外币汇率变化,定期在相关地区的 App Store 更新定价。相关调整将根据金融数据机构提供的公开汇率信息进行,以此确保 App 和 App 内购买内容的定价在所有商店中保持平衡。

2023 年 2 月 13 日起,哥伦比亚、埃及、匈牙利、尼日利亚、挪威、南非和英国 App Store 的 App 及 App 内购买项目 (自动续期订阅除外) 的价格将上调。由于乌兹别克斯坦的增值税率从 15% 下调至 12%,该地区的价格亦将相应下调。您的收益将随之进行调整,并会根据不含税的价格来进行计算。

虽然爱尔兰、卢森堡、新加坡和津巴布韦 App Store 的价格不会改变,但您的收益将进行调整以反映以下税率调整:

爱尔兰:电子报纸和期刊的增值税率从 9% 下调至 0% 卢森堡:增值税率从 17% 下调至 16% 新加坡:商品和服务税率从 7% 上调至 8% 津巴布韦:增值税率从 14.5% 上调至 15% 此外,在柬埔寨、吉尔吉斯斯坦、印度尼西亚、新加坡、韩国、塔吉克斯坦、泰国和乌兹别克斯坦销售产品和服务的当地开发者的收益将在一月底前相应增加。

Apple 在计算抽成之前会根据您提供的税务类别信息估算并移除相关税费。《付费 App 协议》的附录 B 亦将更新以反映此调整。

以上调整生效后,在“我的 App”中“价格与销售范围”部分会随即更新。一如既往,您可以随时在 App Store Connect 中更改您的 App 和 App 内购买项目的价格 (包括自动续期订阅)。如果您有提供订阅项目,您可以选择为现有订阅者保留当前价格。

正如我们此前所宣布,从 2023 年春季起,App 和 App 内购买项目的定价功能升级将带来 700 个新增的价格点;我们还将提供针对全球不同地区更加灵活的价格设定,您将能够不受全球均衡价格的影响,自由管理外币汇率变化。

Ask Apple Q&A 和调查表

Swift 周报 第二十二期_Swift

感谢大家参与 10 月、11 月和 12 月举办的三场精彩的 Ask Apple 活动周。Ask Apple 参与者仍可以根据需要访问并查阅 Slack 中的 Q&A。

我们非常希望获得您的反馈,如果您尚未与我们分享您的 Q&A 体验,恳请完成我们的简短调查表。只需几分钟时间即可完成,并且您的回答将被匿名处理。

我们期待不久之后能再次与您沟通交流。

提案

通过审查的提案

SE-0384 导入已声明的 Objective-C 接口和协议 提案通过审查。该提案已在 二十一期周报 正在审查的提案模块做了详细介绍。

SE-0383 弃用 @UIApplicationMain 和 @NSApplicationMain 提案通过审查。该提案已在 二十一期周报 正在审查的提案模块做了详细介绍。

SE-0381 DiscardingTaskGroups 提案通过审查。该提案已在 二十期周报 正在审查的提案模块做了详细介绍。

SE-0380 if 和 switch 表达式 提案通过审查。该提案已在 十九期周报 正在审查的提案模块做了详细介绍。

SE-0378 Package 注册表认证 提案通过审查。该提案已在 十八期周报 正在审查的提案模块做了详细介绍。

SE-0377 提出了新的 borrowtake 参数修饰符 提案通过审查。该提案已在 十六期周报 正在审查的提案模块做了详细介绍。

驳回的提案

SE-0382 Expression Macros 提案被驳回。该提案已在 二十期周报 正在审查的提案模块做了详细介绍。

SE-0379 Swift 选择加入 Reflection 元数据 提案被驳回。该提案已在 十九期周报 正在审查的提案模块做了详细介绍。

正在审查的提案

SE-0387 交叉编译项目 提案正在审查。

Cross-compilation 是一个常见的开发用例。该提案的作者知道已建立的“构建/主机/目标平台”命名惯例,但认为“目标”在构建系统命名中已经具有不同的含义。此外,“平台”本身的定义相当松散。为了避免可能的混淆,我们在这个建议中使用“构建时三元组”和“运行时三元组”术语。

SE-0386 新的访问修饰符:package 提案正在审查。

该提案引入了 package 作为一个新的访问修饰符。目前,要访问另一个模块中的符号,该符号需要声明为 public。但是,public 符号允许从任何模块访问它,无论是在包内还是从包外,有时候这样做不能满足需求。需要一个新的访问修饰符来更好地控制此类符号的可见范围。

SE-0385 自定义反射元数据 提案正在审查。

该提案引入了使用自定义属性将库定义的反射元数据附加到声明中的功能,然后库可以查询这些元数据,以便于将客户端代码选择到库功能中。

Swift论坛

  1. 讨论如何设置需要异步初始化的静态变量
@globalActor public actor ImageDatabase{

    public static var shared: ImageDatabase = ImageDatabase()
    // 'async' call cannot occur in a global variable initializer

    private var transport : ImageTransportLayer

    private init() async {
           self.transport = await ImageTransportLayer()
    }
}

@ImageDatabase class ImageTransportLayer { } // CRUD

解决方法: 可以稍后在应用程序启动序列中手动初始化 ImageTransportLayer

@globalActor public actor ImageDatabase {
    private init() {}
    public static var shared: ImageDatabase = ImageDatabase()

    private var transport: ImageTransportLayer?
    public func initTransport() async {
        transport = await ImageTransportLayer()
    }
}

@ImageDatabase class ImageTransportLayer {} // CRUD

Task {
    await ImageDatabase.shared.initTransport()

    // Continue using ImageDatabase.shared
}
  1. 讨论 macOS Catalina 上的 Swift 5.7 和适用于 macOS 的工具链
  2. 发布 VSCode Swift v1.0.0

Swift Visual Studio Code 扩展的 1.0 版已经发布。 它不再处于预览状态。 此版本对 v0.10.0 进行了一些小的添加,并修复了一些错误。 更新日志链接:marketplace.visualstudio.com/items/sswg.…

  1. 讨论 AsyncSequences 和 cooperative 任务取消
  2. 讨论函数签名的属性包装器
  3. 提问将函数集成到结构中

目标是有一个接受字符串的字段,它下面的文本将打印一条消息,其中包含输入的单词和它包含的字母数。

import SwiftUI

struct Test1: View {

  @State private var newWord = ""

  var body: some View {
      VStack {
          TextField("Enter a word", text: $newWord)
              .frame(height: 50)
              .cornerRadius(10)
              .background(.gray.opacity(0.1))
              .padding(.horizontal, 20)

          //Text(countLetters(myWord: newWord))
          Text(myMessage)
      }
  }
}

func countLetters(myWord: String) -> (String, Int) {
  var myCounter = 0
  var characters = ""
  for letter in myWord {
      characters += "\(letter)"
      myCounter += 1
  }
  return (characters, myCounter)
}
var myWordCount = countLetters(myWord: "Gregory")
var myMessage = "There are \(myWordCount) letters in the"

解决: 字符串有一个 .count 属性,可以直接使用:

struct ContentView: View {

  @State var text = ""

  var body: some View {
      VStack {
          TextField("Enter a word", text: $text)
          Text("There are \(text.count) letters in your word")
      }
  }
}
  1. 发布 AsyncObjects 2.0
  2. 提议添加 KeyPaths Boolean 自定义运算符

内容大概:

在SE-0249 引入了在允许 (Root) -> Value 函数的任何地方使用关键路径表达式 \Root.value 的能力。

现在在各个项目中得到了广泛的使用。 在这里试图提议的是为关键路径添加一些新的运算符,以便在尝试对其应用任何逻辑时更容易使用它。

这里有几个例子:

假设我们想过滤字典并获取所有为真的值。 我们现在可以通过以下方式使用关键路径轻松完成此操作:

let dict = ["a": true, "b": true, "c": false]
let filtered = dict.filter(\.value) // returns ["a": true, "b": true]

但是如果我们想过滤字典中的错误值怎么办?那么现在我们不能使用关键路径,我们需要依赖闭包:

let filtered = dict.filter { !$0.value } // returns ["c": false]

这里的建议是添加以下运算符:

prefix func !<V>(keyPath: KeyPath<V, Bool>) -> (V) -> Bool {
    { !$0[keyPath: keyPath]}
}

func ==<T, V: Equatable>(lhs: KeyPath<T, V>, rhs: V) -> (T) -> Bool {
    return { $0[keyPath: lhs] == rhs }
}

func !=<T, V: Equatable>(lhs: KeyPath<T, V>, rhs: V) -> (T) -> Bool {
    return { $0[keyPath: lhs] != rhs }
}

这将使我们能够按如下方式使用关键路径:

let dict = ["a": true, "b": true, "c": false]

let filtered = dict.filter(!\.value)

let filtered2 = dict.filter(\.value == false)

关于我们

Swift社区是由 Swift 爱好者共同维护的公益组织,我们会分享以 Swift实战SwiftUlSwift基础为核心的技术内容,也整理收集优秀的学习资料。

特别感谢 Swift社区 编辑部的每一位编辑,感谢大家的辛苦付出,为 Swift社区 提供优质内容,为 Swift 语言的发展贡献自己的力量。