草庐IT

Swift 周报 第二十七期

Swift社区 2024-02-13 原文

前言

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

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

再暗的黑夜也会迎来黎明,再长的坎坷也会连接平川。怀抱Swift社区,一颗永不放弃的希望之心,明天将会是温暖的阳光雨露!

周报精选

新闻和社区:因增速放缓 苹果公司将开启大规模收购

提案:Package Manager 支持自定义宏

Swift 论坛:讨论为什么 didSet 观察者在使用中会触发 Set 类型的属性

推荐博文:在 SwiftUI 中掌握 Canvas 的使用

话题讨论:

你存钱了吗?你存钱的目的是什么呢?

新闻和社区

苹果公司向“恢复基金”再投2亿美元,推进碳移除项目

据界面新闻消息,苹果公司 4 月 12 日宣布,在最初 2 亿美元的投资基础上,将向 2021 年设立的“恢复基金”(Restore Fund)再投多达 2 亿美元。该基金旨在为高质量的自然碳移除项目提供资金,激励全球投资保护和恢复“关键生态系统”。苹果公司还希望帮助无法通过现有技术避免或减少碳排放的企业,推广可行的碳移除解决方案。

加码后的基金将由汇丰资产管理部门和 Polliation 合资成立的 Climate Asset Management 管理,额外投资预计将使苹果此前提出的每年从大气中清除 100 万公吨二氧化碳目标翻倍,同时为投资者带来经济回报。

该基金期望把重点放在面向自然的农业项目以及保护和恢复关键生态系统的项目上,前者将帮助公司从可持续管理的农业实践中获得收入,后者则能从大气中移除并储存二氧化碳。苹果公司表示,“恢复基金”的投资将遵循“严格的社会和环境标准”。

因增速放缓 苹果公司将开启大规模收购

【环球网科技综合报道】4 月 7 日消息,据外媒报道称,苹果公司目前拥有超过 1650 亿美元的现金储备,鉴于苹果公司当前增速放缓,这家公司未来会开启大规模的收购。

不过,和微软、亚马逊等大手笔收购类型不同,苹果公司更倾向于收购小型初创公司。

外媒称,苹果喜欢以培养、孵化的方式开展收购,并耐心等待这些初创公司成长,来撬动新的市场。

据此前报道,今年 2 月,苹果收购了位于加州的 AI 算法公司 WaveOne 。今年 3 月,苹果公司已经收购了英国开放银行初创公司 CreditKudos 。

据了解,苹果经常收购小型企业,以加强其技术和专业知识,但显然没有或立即将其推广到产品或服务中。另一方面,许多收购确实成为苹果生态系统的关键部分。近年来,苹果已经收购了音乐识别服务 Shazam 和自动驾驶汽车公司 Drive.ai 等企业。

Swift Student Challenge 现已开放申请

我们很高兴能一如既往地为世界各地热爱编程的学生提供长期支持。欢迎使用 Swift Playgrounds 或 Xcode 编写 App Playground (主题自选) 并提交你的杰作,向我们展现你对于编程的热爱。优胜者将获得奖项和表彰,以及额外奖励。

提案

通过的提案

SE-0393 Value 和 Type 参数包 提案通过审查。该提案已在 二十六期周报 正在审查的提案模块做了详细介绍。

正在审查的提案

SE-0394 Package Manager 支持自定义宏 提案正在审查。

宏提供了一种扩展 Swift 的方法,通过对输入源代码执行任意语法转换来生成新代码。该提案涵盖了如何将自定义宏作为 Swift 软件包的一部分进行定义、构建和分发。

SE-0395 Observation 提案正在审查。

该提案定义了什么是可观察的引用,观察者需要遵守什么,以及类型与其观察者之间的联系。这种设计模式是许多语言都支持的,Swift 引入之后,无疑将更加强大、安全和高性能。

Swift论坛

  1. 提议可变泛型类型抽象包

介绍

之前的 SE-0393 引入了类型参数包和几个相关概念,允许泛型函数声明抽象出可变数量的类型。 该提案将这些想法概括为泛型类型声明。

动机

当试图在集合上概括通用算法时,自然会出现对可变数量的类型进行抽象的通用类型声明。 例如,惰性 ZipSequence 可能在两个序列上是通用的。 可以声明一个 ZipSequence 类型,它将固定序列列表的元素表示为元组序列:

struct ZipSequence<each S: Sequence>: Sequence {
  typealias Element = (repeat each S.Element)

  let seq: (repeat each S)

  func makeIterator() -> Iterator {
    return Iterator(iter: (repeat (each seq).makeIterator()))
  }

  struct Iterator: IteratorProtocol {
    typealias Element = (repeat each S.Element)

    var iter: (repeat each S.Iterator)

    mutating func next() -> Element? {
      return ...
    }
  }
}

建议的解决方案

在泛型类型的泛型参数列表中,each 关键字声明了一个泛型参数包,就像它在泛型函数的泛型参数列表中所做的那样。 存储属性的类型可以包含包扩展类型,如上面的 let seq 和 var iter。

  1. 讨论点前缀被认为是丑陋的

虽然我们已经习惯了,但在静态成员和枚举常量前加上点会引入视觉噪音,看起来太聪明了,总是让我的其他语言背景的同事感到惊讶:

func foo(_ v: Color) {...}
object.foo(.red) // 🤔

在声明中缺少点前缀之间也存在这种令人不安的不对称性:

enum Color {
    case red
    case green
    static var blue = ...
}

并在其他地方使用这些前缀:

switch color {
    case .red: break
    case .green: break
}
foo(.red)
foo(.blue)

有趣的是,我已经可以在某些上下文中使用“object.foo(red)”(例如,在 Color 的静态方法中),但不能在其他上下文中使用。

我很欣赏这将是一个突破性的变化,我们不可能在现阶段迅速适应这一变化。 暂时忘记这一点,你认为 Swift 通过以下更改会变得更好还是更糟?

func foo(_ v: Color) {...}
...
object.foo(Color.red) // ok
object.foo(.red)      // 🛑 prohibited
object.foo(red)       // ✅

switch color {
    case .red: break  // 🛑 prohibited
    case red: break   // ✅
}
dispatchPrecondition(condition: .onQueue(.main)) // 🛑
dispatchPrecondition(condition: onQueue(main))   // ✅
bar(.init()) // 🛑
bar(init())  // ✅

// While choosing what "red" to use – follow these new resolution rules:
// - use local variable if exists
// - or use instance variable if exists (in which case self should be captured strongly explicitly or implicitly)
// - or use static variable if exists (in case of enum could be an enumeration constant)
// - or use global variable if exists
// - otherwise emit an error
  1. 讨论非 Sendable 类型可以在 Tasks 中捕获吗?

现在,我猜想下面的代码应该会出现任何错误。

class SomeClass {
    var count: Int
    init(count: Int) {
        self.count = count
    }
}

let someClass = SomeClass(count: 0)

//public init(priority: TaskPriority? = nil, operation: @escaping @Sendable () async -> Success)
Task {
    someClass.count += 1
}

//public init(priority: TaskPriority? = nil, operation: @escaping @Sendable () async -> Success)
Task {
    someClass.count += 1
}

但是,在 Swift(5.8 版)中,此代码片段可以编译。 在 Swift6 中,这段代码有没有出现错误?

回答:

在 Swift v.Future 中,全局 someClass 必须与全局 actor 隔离,因此行 someClass.count += 1 将需要:

整个 Task 闭包被隔离到同一个global actor,或者您为该操作切换到适当的global actor
(例如:await MainActor.run { someClass.count += 1 })很难准确地说出在 Swift 6 中什么会/不会是错误。您可以使用一些编译器标志来尝试一些事情,但它们是不一致的。

  1. 讨论为什么 didSet 观察者在使用集合中已有的值调用插入后会触发 Set 类型的属性?

Xcode Playground 中的以下代码片段:

import UIKit

var collection = Set<String>() {
    didSet {
        print("didSet")
    }
}

collection.insert("Test1")
collection.insert("Test2")
collection.insert("Test1")
collection.insert("Test3")

print("Done")

为什么是输出:

didSet
didSet
didSet
didSet
Done

而不是:

didSet
didSet
didSet
Done

为什么当集合未更改时它会触发,因为该值已经在集合中?

回答:

每个mutating函数都会像这样。
没有特殊的机制可以让属性知道 Set 没有在内部被修改。

  1. 讨论可变参数泛型的同时简单但可能致命复杂的使用

我很好奇即将到来的可变参数泛型特性是否能让我们实现像 transform(:😃 这样的函数,你可以在下面看到它的使用:

extension String {
    var hasPrimeNumberOfCharacters: Bool {
        transform(
            self,
            { $0.count },
            { $0.isPrime }
        )
    }
}

该函数采用一个强制性的第一个参数,即要转换的值,然后是一个可变的转换闭包列表,每个闭包都对它之前的闭包的输出类型进行操作,第一个对初始值进行操作。 在上面的例子中,参数是:String, (String)->Int, (Int)->Bool。

我已经阅读了大量的可变参数泛型文档,如果我现在必须给出我最好的猜测,我会说我的 transform(:😃 函数在可变参数泛型的第一次迭代中是不可能的。

下面是一个非常粗略的草图,它是我能想象到的最接近如何编写这样一个函数签名的草图。 我发现有必要发明许多新的语法,这支持了我的猜测,即这是不可能的,至少在最初是不可能的。

func transform
    <InitialValue,
     each (T, U)>
    (_ initialValue: InitialValue,
     _ transform: repeat each (T)->U)
-> last U or InitialValue
where first T == InitialValue {
    // How would one even implement this if the above syntax were valid?
}
  1. 讨论为 Debian/Ubuntu 构建发行版?

现在我希望在 Jetson Nano(它有一个 ARM Cortex-A57 CPU)上用 Swift 做一个机器人项目,它只能使用 Ubuntu 18.04。 18.04 没有预构建的 5.8 .deb 包,这有点痛苦,因为这意味着我必须从源代码构建,并且一些构建依赖项(例如 cmake)必须从源代码构建才能获得最新的 足够的版本。 我以前构建过工具链,现在我正在 Jetson Nano 上构建它,但它花费了很长时间,尽管构建在连接的 SSD 上(操作系统运行在 SD 卡上)。

我想知道在我的 M1 Max MacBook Pro 上的 Ubuntu 18.04 Docker 容器(或者可能是 Parallels VM)中构建工具链是否有意义,然后构建将正确安装在任何 18.04 ARM 机器上的工具链的 .deb。

你认为那会建造得更快吗?

是否存在对构建 .deb 包的支持? 20.04 和 22.04 包是如何构建的?

回答:

另一种选择是构建 MacOS -> 18.04 交叉编译工具链。 不久前,我将 x-compiler 配置移到了 focus,但要翻转回 bionic 配置应该很容易。

  1. 发布Swift 5.8 发布!

链接: https://www.swift.org/blog/swift-5.8-released/

您可能已经看到,Swift 5.8 现已正式发布! 🎉 此版本包括对语言和标准库的主要补充,包括支持逐步采用即将推出的功能的 hasFeature、改进的开发人员体验、改进 Swift 生态系统中的工具,包括 Swift-DocC、Swift Package Manager 和 SwiftSyntax,经过改进 Windows 支持等。

推荐博文

在 SwiftUI 中掌握 Canvas 的使用

摘要: 文章介绍了如何使用 Canvas 视图在 SwiftUI 中绘制 2D 图形,而无需使用 Shape API 。在 Canvas 视图中,我们可以使用 GraphicsContext 实例进行绘图,调整透明度、缩放和混合模式等参数,并添加不同的滤镜。 Canvas 还提供了 stroke、 fill 和 clip 函数,允许我们绘制任何我们需要的路径,同时也提供了draw函数,允许我们绘制文本和图像。我们可以使用 Canvas 类型绘制任何 SwiftUI 视图,但需要在创建 Canvas 时使用 symbols 闭包中注册它们。虽然 Canvas 视图不支持动画,但可以通过将其嵌入到带有动画调度程序的 TimelineView 中来实现动画效果。 Canvas 视图没有辅助功能树,但可以附加一组辅助视图修饰符,以使每个人都可以访问其内容。

监听 SwiftUI ScrollView 的内容偏移量

摘要: 文章介绍了如何监听 SwiftUI ScrollView 的内容偏移量。在构建可滚动的 UI 时,通常需要观察当前滚动位置以便进行操作,但目前(在撰写本文时)SwiftUI 的 ScrollView 没有内置的方式来执行此类滚动观察。作者提供了一种利用 GeometryReader 解析器并使用 PreferenceKey 类型来实现的方法,使我们能够观察当前的内容偏移。最终作者实现了一个名为 OffsetObservingScrollView 的自定义滚动视图,可以实现监听当前内容偏移量的功能。

Swift 中如何将不透明返回类型与主要关联类型相结合

摘要: 文章介绍了 Swift 5.7 引入的主关联类型和不透明返回类型相结合的使用方式。通过声明主关联类型,我们可以在使用 some 关键字时避免类型擦除,并使代码更加类型安全。该功能不仅适用于 Combine 框架,还可以在处理自己的泛型协议时使用。

话题讨论

4月11日,央行公布了2023年一季度的金融数据,居民超额存款三年10.8万亿:北京人均存款已接近27万,上海人均超21万。你存钱了吗?你存钱的目的是什么呢?

  1. 有安全感:为了应对失业、突发疾病等,避免因意外事件而出现经济困难。
  2. 实现个人目标:买房、买车、旅行等,通过积累资金来实现自己的愿望。
  3. 投资理财:通过投资股票、基金、房地产等资产来增加财富,实现长期的财务目标。
  4. 应对退休生活:通过积累养老金和退休金来保障自己的生活质量和经济安全。
  5. 没有存款:支出基本等于收入,实在是存不了钱。

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

关于我们

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

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

有关Swift 周报 第二十七期的更多相关文章

  1. ruby - 如何跳过 CSV 文件的第一行并将第二行作为标题 - 2

    有没有办法跳过CSV文件的第一行,让第二行作为标题?我有一个CSV文件,第一行是日期,第二行是标题,所以我需要能够在遍历它时跳过第一行。我尝试使用slice但它会将CSV转换为数组,我真的很想将其读取为CSV,以便我可以利用header。 最佳答案 根据您的数据,您可以使用另一种方法和skip_lines-option此示例跳过所有以#开头的行require'csv'CSV.parse(DATA.read,:col_sep=>';',:headers=>true,:skip_lines=>/^#/#Markcomments!)do|

  2. ruby - `respond_to_missing?` 的第二个参数有什么用吗? - 2

    使用method_missing时在Ruby中,它是almostalwaysagoodidea定义respond_to_missing?respond_to_missing?接受两个参数;我们正在检查的方法的名称(symbol),以及一个指示我们是否应该在检查中包含私有(private)方法的bool值(include_all)。现在我感到困惑的是:method_missing不接受任何可能指示它是否应该调用私有(private)方法的参数,如respond_to_missing?做。此外,method_missing无论原始方法调用是在公共(public)上下文还是私有(privat

  3. ruby - stub 实例方法在使用 minitest 的第二次调用时返回值不同 - 2

    我正在对用户的提要进行分页,并想模拟我正在使用的API的响应。API可以返回奇怪的结果,所以我想确保如果API返回我已经看到的项目,请停止分页。我使用minitest在第一次调用方法get_next_page时stub,但我想在第二次和第三次用不同的值调用它时stub。我应该只使用rSpec吗?ruby新手...这是片段test"crawlerdoesnotpaginateifnonewitemsinnextpage"do#1:A,B#2:B,D=>D#3:A=>stopcrawler=CrawlJob.newfirst_page=[{"id"=>"item-A"},{"id"=>"i

  4. ruby-on-rails - Ruby:给定日期找到下一个第二或第四个星期二 - 2

    我似乎找不到一种优雅的方式来做到这一点......给定一个日期,我如何找到下一个星期二,即日历月的第2个或第4个星期二?例如:给定2012-10-19然后返回2012-10-23或给定2012-10-31然后返回2012-11-13OctoberNovemberSuMoTuWeThFrSaSuMoTuWeThFrSa12345612378910111213456789101415161718192011121314151617212223242526271819202122232428293031252627282930 最佳答案

  5. ruby - 为什么触发器运算符包含第二个条件? - 2

    以下代码使用了触发器运算符。(1..10).each{|x|print"#{x},"ifx==3..x==5}为什么结果是3,4,5?我觉得应该是3,4。如教程中所述,此表达式在x==3时为真,并一直为真,直到x==5。如果“5”的计算结果为false,如何打印它?谁能为我澄清一下? 最佳答案 来自“TheRubyProgrammingLanguage”的重要链接是:4.6.9.1Booleanflip-flopsWhenthe..and...operatorsareusedinaconditional,suchasanifstat

  6. ruby array,从第二个到最后一个获取所有元素 - 2

    这个问题在这里已经有了答案:HowtoreturnapartofanarrayinRuby?(6个答案)关闭8年前。我的方法:defscroll_imagesimages_all[1..images_all.length]end我不喜欢调用images_all两次,只是想知道是否有一个好的技巧来调用self或类似的东西来使它更干净一些。

  7. ruby - 如何使用每个元素从第二个元素开始在数组中循环? - ruby - 2

    假设我有一个这样的数组:["auburn","http://auburn.craigslist.org/web/","http://auburn.craigslist.org/cpg/","http://auburn.craigslist.org/eng/","http://auburn.craigslist.org/sof/","http://auburn.craigslist.org/sad/"]我想做的是只处理这个数组中的URL——它总是从element[1]开始并向上。我该怎么做? 最佳答案 这里只显示从1(第二个元素)开始

  8. ruby-on-rails - Ruby DateTime 格式 : How can I get 1st, 第二、第三、第四? - 2

    首先,DateTime格式变量似乎没有在任何地方记录,因此对可以在rubydocs中向我展示此内容的任何人+1。其次,在查看Date.strftime函数代码时,我没有看到任何可以让我执行以下操作的内容:2010年9月9日,星期四有人知道这是否可行吗? 最佳答案 您可能想要takealookhere.总结time=DateTime.nowtime.strftime("%A,%B#{time.day.ordinalize}%Y")请注意,您在纯Ruby(2.0)中运行,您需要调用:require'active_support/core

  9. ruby - 从第二次出现的字符拆分字符串 - 2

    如何从第二次出现的字符拆分字符串str="20050451100_9253629709-2-2"Ineedtheoutput["20110504151100_9253629709-2","2"] 最佳答案 没有什么比得上单线了:)str.reverse.split('-',2).collect(&:reverse).reverse它将反转字符串,用“-”分割一次,从而返回2个元素(第一个“-”前面的内容和它后面的所有内容),然后反转两个元素,然后反转数组本身。编辑*before,after=str.split('-')puts[be

  10. ruby - || 是否即使第一个参数为真,运算符也会评估第二个参数? - 2

    我正在尝试计算表达式(a=10)||(rr=20)未定义rr变量因此在评估前一个表达式返回之前在ruby​​控制台中键入rrrrNameError:undefinedlocalvariableormethod`rr'formain:Objectfrom(irb):1from:0当我编写表达式(a=10)||(rr=20)它返回10,然后当我写rr时它说nil(a=10)||(rr=20)rr#=>nil那么,为什么会这样呢?仅当||的第二个参数时,不应定义rr运算符被评估,这不应该基于文档? 最佳答案 发生这种情况是因为ruby​​

随机推荐