第一天

本年是 WWDC 的第39个年头了。本年的 WWDC.playground 活动()是 SwiftGG、T 沙龙和老司机技能一同会和社区开发者们一同聊聊这次 WWDC。WWDC.playground 活动在节日期间每天都会有直播,我会和 61、13 他们参与 6月11日晚上8点那场直播。现在那场直播的录播现已放了出来,地址是 WWDC22.playground – Day 5:回顾 WWDC22

下面我收拾了一份本年 WWDC 的攻略,也算供给个便利的进口吧。

  1. WWDC22 直播地址、微博直播、WWDC22 YouTube 地址
  2. Apple WWDC22 页面
  3. Apple WWDC22 攻略
  4. Apple Developer app 观看 Session 的 Apple 出的 App。
  5. Session 网页版
  6. Digital Lounge 注册感兴趣的主题,到时候就能够和 Apple 工程师在 Slack 上一同看 Session,交流。
  7. Labs 能够获得和 Apple 专家1对1辅导。6号 keynote 完后就能够开端预约。
  8. Beyond WWDC22 和上一年相同,这儿是 Apple 制作的世界各地的社区活动。
  9. weak self Discord WWDC22 Keynote Watch Party 全球最多听众的 iOS 中文 Podcast 之一 weak self 的活动。
  10. Swiftly Rush WWDC22
  11. iOS Feeds 的 WWDC 2022 新闻聚合
  12. WWWDC.io App 社区的看 Session 的 App。
  13. Keynote 后的 Platforms State of the Union 这个主题是对后面一周 Session 的总结,开发者能够要害重视下。
  14. WWDC Notes 汇聚了咱们的 Session 笔记,能够快速看到各个 Session 的要害。
  15. Technologies 这儿是 Apple 结构 API 分类地址,看完 Session 能够直接在这儿找对应 API 的更新。还有个网站 Apple Platform SDK API Differences 会列出新 SDK 里有哪些结构更新了。
  16. Apple Design Awards 提名著作

Apple Design Awards 提名著作,我先列几个我喜爱的:

  1. procreate
  2. Wylde Flowers
  3. 笼中窥梦
  4. Gibbon: Beyond the Trees
  5. Vectornator: Design Software
  6. Wylde Flowers
  7. Behind the Frame
  8. MD Clock – Live in the present
  9. 专心面条
  10. Townscaper

第二天

01.png

今日最让我形象深入是 M2、Lock screen widgets、Stage manager、Swift Charts、WeatherKit、SwiftUI Navigation API、只需一个 1024×1024 App Icon、Sticky headers on Xcode scrolling、Xcode View Debugger 能够用于 SwiftUI 了,还有 iOS 16 原生的支撑 Nintendo Switch Pro 手柄了。

后面我将更多内容运用点对点的分发,能够用 Planet 重视,我的 IPNS 是:k51qzi5uqu5dlorvgrleqaphsd1suegn8w40xwhxl0bgsyxw3zerivt59xbk74

Keynote 要害:

  • iOS 16
    • new lock screen
    • live activities
    • extend focus to lock screen
    • forcus filter for apps
    • dictation improvements
    • live text in video
    • visual lookup
    • maps
      • multistop routing
      • transit(add card to wallet)
      • new details
      • lookaround api
    • iCloud shared photo library
    • persanalized spatial audio
    • quick notes on iPhone
    • fitness app without watch
    • messages
      • edit messages
      • delete messages
      • mark as unread
      • share play
    • pay
      • tap to pay on iPhone
      • order tracking
    • carplay
      • widgets
      • more personalization
      • multi-screen
    • safety check
      • quickly remove access for others
    • home
      • introduce matter as new standard
      • redesign of app
  • M2
    • 15.8 trillion operations per seconds
    • 10-core GPU
    • macbook air and macbook pro 13”
    • better and faster
    • silent design
    • fast charge
    • new colors
    • magsafe
    • audio jack
  • macOS Ventura
    • improved spotlight
    • undo send and more
    • shared tab groups
    • passkeys
    • desk view
    • stage manager
    • continuity for facetime
    • use iPhone as camera on macbook
  • iPadOS 16
    • weather app
    • WeatherKit
    • collaborations api
    • freeform board
    • stage manager
  • WatchOS 9
    • four new watch faces
    • new ShareKit api
    • improved metrics for running
    • heart rate zones
    • create custom workouts

重要的几个信息:

  • Platforms State of the Union 汇总 WWDC22 技能的 Session,必看。
  • iOS 16 新 API 和功用 Apple 的收拾。
  • New Technologies WWDC22 Apple 收拾的 WWDC22 上的新技能。
  • WWDC22 Sample Code
  • iOS and iPadOS 16 release notes 体系接口更新阐明,包含 SwiftUI 更新了啥。
  • 下载 Xcode 14 beta 直接在开发者官方下载当地下。7个G,这次做了裁剪,手表和电视都做成了可选。
  • Webkit 许多更新

大赞的库:

  • SwiftUI 更新介绍
  • Swift Charts 本年 WWDC 的惊喜。Swifty Rush 的文章介绍 Swift Charts with SwiftUI。
  • Navigation API 又一个惊喜。从曾经的 Navigation 搬迁到新 API 的文档阐明 Migrating to New Navigation Types。能够看 NavigationStack 、NavigationSplitView。相关 Session 是 The SwiftUI cookbook for navigation。Natalia Panferova 的文章的介绍 Overview of the New SwiftUI Navigation APIs
  • macOS Window 支撑,等到了。参看这个示例 Bringing multiple windows to your SwiftUI app。
  • RegexBuilder 构建正则表达式的 DSL
  • Live Text API
  • Weatherkit 攻略 每月在 500k 次调用内是免费。
  • RoomPlan 接口文档 用摄像头扫描物理环境,创立房间的 3D 模型。Introducing RoomPlan 介绍 RoomPlan。
  • Spatial 轻量 3D 数学库。
  • Passkey (FIDO) 原理和 Web3 钱包核心逻辑差不多。
  • DriverKit 安全的 USB 和 PCI 硬件设备连接到 iPad 的库。

好用的功用和组件:

  • UICalendarView 日历视图
  • BADownloadManager 下载队列办理器。
  • backgroundTask(_:action:)
  • ImageRenderer 将 View 生成图片。
  • presentationDetents 优秀。示例 Using Presentation Detents in SwiftUI
  • String Index 晋级

一些便利上手的比方:

  • Configuring a multiplatform app 单代码,多渠道 in Xcode 14。
  • Food Truck: Building a SwiftUI multiplatform app 示例了 NavigationSplitView、Layout、Chart 和 WeatherKit 的运用。

一些感兴趣的 Session:

  • Session 按主题分类
  • What’s new in Swift
  • Swift Session、Lab 和 Digital Lounges 合集 Apple 专门为 Swift 制作的 WWDC22 页面。
  • Visualize and optimize Swift concurrency
  • Link fast: Improve build and launch times 构建和发动加快
  • Demystify parallelization in Xcode builds
  • Create macOS or Linux virtual machines

第三天

02.jpg
03.jpg

WWDC.playground 很精彩,怎样感觉昨日的 WWDC.playground 像是听了一期枫言枫语呢。预感 11 号或许会变成为一期 weak self 呢。

昨日老司机还收拾了份 WWDC22 Session 观看介绍的列表

Apple 出的内容看不行的话,可运用 Follow WWDC 2022 News! 来看最新的 WWDC 相关的社区文章。

下面是我今日的一些记载。

Xcode

代码补全的更新。曾经多个可选参数的体验很差,这次输入参数比方 frame 里的 maxWidth,会只显现当时要补全的参数。而且速度快了许多。

曾经是编完源码再生成 module,然后 link编好的文件,最终再 link。现在整个进程改成并行履行,一起 link 还快了两倍。成果是比曾经快了25%,核越多效果越显着。还有可可视化整个进程。

多渠道曾经是多个 tagets,现在是在一个 target 里办理。

Hangs 是官方线上主线程被卡了的查看东西,在 Organizer 里查看对应问题仓库也很便利。

当然独爱的仍是 sticky headers,秒杀其它编辑器 (虽然我仍是觉得 Emacs 最好,因为会暴露年纪,一般我都不说)。

还有内存也好了许多,总体来说,这次 Xcode 更新很棒。

完好 Xcode release notes

WidgetKit

WidgetKit 将 WatchOS 上的 Circular、Rectangle 还有 Inline 带到了 iOS 和其他渠道。

WeatherKit

安全便利获得用户方位信息,只用于天气。

VisionKit

Live Text API,感觉这类库都是为了今后出眼镜做铺垫的。

macOS

macOS 支撑window,menuBar也支撑了。

Swift

distrubuted actor 更安全,还能够在设备间(本地设备<->本地设备本地设备<->服务器)进行通讯保护。

泛型新语法 some 和 any 要害字写起来真的简化了许多。

Swift 的更新了什么,除了 Session 外,还能够参看 Paul Hudson 这篇文章 What’s new in Swift 5.7 ,还有 Donny Wals 的这篇 What’s the difference between any and some in Swift 5.7? 。

SwiftUI

SwiftUI里没有用特点包装的特点也能够和视图改变绑定了。

关于 SwiftUI 的更新,Paul Hudson 写了许多比方 What’s new in SwiftUI for iOS 16 。

Reda Lemeden 收拾了 WWDC22 SwiftUI 的一切相关内容 SwiftUI @ WWDC 2022 。可见社区对 SwiftUI 热情依然是最高的。

SPM

Swift Package Plugin,本来用其他言语,比方 ruby 、python 或 shell 做的作业,现在能够经过 Swift 言语来完结了,写的 plugin 还能够便利的在 Xcode 中运用。

虚机

运用 Virtualization 结构,享受 Rosetta 2 的优势,运转 x86-64 Linux 体系。

Apple 出虚机可运转 Linux 体系这点能够看得出 Apple 对开源的拥抱,原因还有一点是 Swift 也能够用在 Linux 服务器上了,Apple 用心良苦,也是想让开发者用本计划买其它硬件的钱来买 Apple 的硬件吧,更好的榨干 Apple 硬件过于优秀的功用,好像新出 Stage Manager 经过投到大屏来榨干 M1 的 iPad 功用。 不光是这样,还有文件,也便是存储设备也只需求一份了,更便利,还有苹果特有的 Trackpad 和 Magic mouse 也能够用于 Linux 体系中。

虚机运转 Linux 和 macOS 的区别是,发动 Linux 运用的是 EFI Boot Loader 来加载 Linux 文件,VirtioGraphicDevice 进行 Linux 体系图形界面的设置和烘托。运用Rosetta 运转 Linux 体系,运转 Linux 便是比其它虚机要快。

介绍的 session Create macOS or Linux virtual machines ,代码阐明 Running GUI Linux in a virtual machine on a Mac,相关主题 Virtualization

第四天

04.png

今晚五神会现身 WWDC.playground 。内容触及 SwiftUI 和 AR,不要错过。

今日零星记载

从 Apple 推出 WeatherKit 能够看出,Apple 喜爱把要害和有想象空间盈利价值的技能掌握在自己手上,WeatherKit 供给许多数据,包含分钟、小时、每日预告,还有提早警报,这些信息的商业价值本就很大。

今日看了 WeatherKit、Swift Chart 还有 SwiftUI 的 Layout,感觉 Apple 的接口规划才能很值得学习,或许具备了这些才能才能更好地交流。

swift-algorithms 能够运用 .indexed() 来替代 zip。

Federico Zanetello 对 Platforms State of the Union 这个 Session 做的笔记 。

运用层面,今日还有好多 Swift Chart 的介绍。

Layout

Grid、Layout、ViewThatFits、AnyLayout,特别是 Grid 还统一了 HStack 和 VStack。这些布局办法,让从前杂乱的要凭借 GeometryReader,且简略出错的布局有了更易的写法。Layout 协议能够为 layout 创立自界说特点,别的布局核算也会被缓存。

Link

Link fast: Improve build and launch time 具体讲了 Apple 本年怎样改善了 link,思路很棒,很值得学习。

Static linking 和 Dynamic linking ,也便是静态链接和动态链接。

静态链接便是链接各个编译好的源文件以及链接源文件和编译好的库文件,经过将函数名放到符号表,链接新文件时确认从前是否有包含的 undefined 符号,给函数的数据指令分配地址,最终生成一个有 TEXT、DATA、LINKEDIT 段的可履行文件。

本年 Apple 经过运用多核优势让静态链接快了两倍。

具体做法是,并行的复制文件内容。并行构建 LINKEDIT 段的各个不同部分。并行改变 UUID 核算和 codesigning 哈希。然后是进步 exports-trie 构建器的算法。运用最新的 Crypto 库运用硬件加速的优势加速 UUID 核算。进步其它静态库处理算法库,debug-notes 生成也更快了。

Apple 引荐静态库最佳实践是:

运用 -all_load-force_load 能够让 .a 文件像 .o 文件那样并行处理,不过敞开这个选项需求先处理重复的符号。别的一个副作用是会将一些被判断无用的代码也被链接进来,使包体变大,因而敞开之前能够先运用静态剖析东西剖析处理,这个进程定时做就行,不必放到每次编译进程中。演讲者引荐运用 -dead_strip 选项,但是这样做并没有实在去掉费代码,今后这些代码仍是会被编译剖析,假如仅仅暂时不必,能够先注释掉。

运用 -no_exported_symbols 选项。链接器生成的 LINKEDIT 段的一部分是 exports trie,这是一个前缀树,对一切导出的符号称号、地址和标志进行编码。动态库 是会导出符号的,但运转的二进制文件其实是不必这些符号的,因而能够用 -no_exported_symbols 选项来越过 LINKEDIT 中 trie 数据结构的创立,这样链接起来就快多了。假如程序导出符号是一百万个,这个选项就能够削减 2 到 3 秒的时刻。但需求留意的是,假如要加载插件链接回主程序就需求一切的导出的 trie 数据,无法用这个选项。

别的一个是 -no_deduplicate 选项。从前 Apple 给链接器加了个 pass 用来兼并函数的指令相同,函数名不相同,这个 pass 会对每个函数的指令进行递归散列,用这种办法来找重复指令,这样做比较费 CPU,因为调试时其实是不需求重视包巨细,因而能够加上 -no_deduplicate 选项来越过这个 pass。

这些选项在 Xcode 的 Other Linker Flags 里进行设置即可。

动态库也便是 dylib,其它渠道便是 DSO 或 DLL。 动态链接器不是将代码从库里考到主二进制里,而是记载某种承诺,记载从动态库中运用符号称号,还有库途径。这样做优点便是好复用动态库,不必复制多份。虚拟内存看到多进程运用相同动态库,就会从头给这个动态库用相同的物理内存页。

动态库优点是构建快了,发动加载慢了,多个动态库不光要加载,还要在发动时链接。也便是把链接本钱从本地构建换到了用户发动时。动态库还有个缺陷是依据动态库的程序会有更多的 dirty 页,因为静态链接时会把大局数据放到主程序同一个 DATA 页中,动态库的话,每个都在自己的 DATA 页中。

动态库作业的原理是,可履行的二进制会有不同权限的段,至少会有 TEXT、DATA 和 LINKEDIT。分段总是操作体系页巨细的倍数。TEXT 段有履行的权限,CPU 能够将页上的字节作为机器代码指令。运转时,dyld 会依据每个段权限将可履行文件 mmap() 到内存,这些段是页巨细和页对齐的,虚拟内存体系能够直接将程序或动态库文件设置为 VM 规模的备份存储。在这些页的内存拜访前是不会被加载到 RAM 里,就会触发一个页 fault,导致 VM 去读取文件的子规模,将内存填充到需求 RAM 页中。光映射不行,还要用某种办法“wired up”或绑到动态库上。比方要调用动态库上的某个函数,会转换成调用 site,调用 site 成为一个在相同 TEXT 段合成的 sub 的调用,相对地址在构建时就知道了,就意味着能够正确的形成 BL 指令。这样做的优点是,stub 从 DATA 加载一个指针并跳到对应的方位,不必在运转时修正 TEXT 段,dyld 只在运转时改 DATA 段。dyld 所进行的修正很简略,便是在 DATA 段里设置了一个指针而已。

当 dyld 或运用程序的指针指向自己时要 rebase,ASLR 使 dyld 以随机地址加载动态库,内部指针不能在构建时设置,dyld 在发动时 rebase 这些指针,磁盘上,假如动态库在地址零出被加载,这些指针包含它们的方针地址。LINKEDIT 需求记载的便是每个重定位的方位。然后,dyld 只需将动态库的实践加载地址增加到每个 rebase 方位。还有种修正办法是绑定,绑定便是符号引证,符号存储在 LINKEDIT 中,dyld 在动态库的 exports tire 中找实践地址,然后 dyld 将该值存储在绑定指定的方位。

本年 Apple 发布了一个新的修正办法 chained fixups。较前面两种的优势便是能够使 LINKEDIT 更小。新格局只存储每个 DATA 页中第一个 fixup 方位和一个导入的符号列表。其它信息编码到 DATA 段。iOS 13.4 就开端支撑了。

下面先说下 dyld 原理介绍。

dyld 从主可履行文件开端,解析 mach-o 找依靠动态库,对动态库进行 mmap()。然后对每个动态库进行遍历并解析 mach-o 结构,依据需求加载其它动态库。加载完毕,dyld 会查找一切需求绑定符号,并在修正时运用这些地址。最终修正完,dyld 自下而上运转初始化程序。从前做的优化是只需程序和动态库,dyld 许多步骤都能够在初次发动时被缓存。

本年 Apple 做了更多的优化,这个优化叫 page-in linking,便是 dyld 在发动时做的 DATA 页面修正放到 page-in 时,也能够理解为懒修正。曾经,在 mmap() 区域的某些页面中第一次运用某些地址会触发内核读入该页面。现在假如它是一个数据页,内核会运用改页需求的修正。这种机制削减了 dirty 内存和发动时刻。意味着 DATA_CONST 也是洁净的,能够像 TEXT 页相同被 evicted 和从头创立,以削减内存压力。需求留意的是 page-in linking 只用于发动,dlopen() 不支撑。你看,Apple 优化发动的思路也是按需加载。

Apple 还供给了追踪 dyld 运转情况的 dyld_usage 东西。查看磁盘和 dyld 缓存中的二进制文件的 dyld_info 东西。

今日引荐 Session

除了 link 外,还有 Meet distributed actors in Swift 也是比看的,Mike Ash 和 Doug Gregor 一年的心血就在这了。

第五天

05.png

功用

功用的 Improve app size and runtime performance Session 值得一看。

本年苹果经过更有用的查看 Swift 协议,使 OC 音讯发送调用更小,使 autorelease elision 更快更小这几个个方面来让 App 体积更小,功用更高。

Swift 协议查看。

一个协议经过 as 操作符查看传递值是否契合协议,这种查看会在编译器的构建时刻被优化掉,所以往往需求在运转时凭借之前核算协议查看元数据来看目标是否真的契合了协议。一些元数据是在编译时建的,但还有许多元数据只能在发动时树立,特别是运用泛型时。协议多了,会增加耗时,差不多会多一半发动时刻。

本年 Apple 推出新的 Swift 运转时,能够提早核算 Swift 协议元数据,作为 App 可履行文件和它在发动时运用的任何动态库的 dyld 闭包的一部分。这个是在体系上的,因而,只需是运用了本年最新体系的 App 都会享受这个优化,能够理解为,新体系上发动老 App 也会快些。

音讯发送。

Xcode 14 中新的编译器和链接器现已将 ARM64 的音讯发送调用从 12 字节削减到 8 字节。因而假如你的 App 都是 OC 代码的话,运用 Xcode 14 编出来的二进制文件能够少 2%。老体系也有用。

运用 objc_stubs_small 选项能够只优化巨细,获得最大的巨细优化。objc_msgSend 调动有 8 个字节指令,也便是2个指令是专门用来准备 selector 的,关于任何特定的 selector,总是相同的代码,因为始终是相同的代码,那么就能够对其同享,每个 selector 只 emit 一次,而不是每次发送音讯时都 emit。同享这段代码当地是一个叫 selector stub 的函数。

ARC 会在编译器插入许多的 c 的 retain/release 函数调用。这些调用遵守渠道运用二进制接口(ABI)所界说的 c 言语 call convention。也就意味着咱们要更多代码来完结这些调用,用来传递正确寄存器的指针。Apple 本年推出了自界说的 call convention 依据指针方位,当令运用正确变量而不必移动它,然后摆脱了调用里的多余代码。Apple 果然是坚持用户体验优先,为了更好体验不吝修正 c 的 ABI。

autorelease elision 。

App 本年对 objc 运转时进行了修正,使 autorelease elision 更小更快。deployment target 为 iOS 16 本年新体系时才可享受哦。

Apple 怎样做的呢?

ARC 在调用方插入一个 retain,在被调用的函数中插入一个 release。当咱们回来咱们的暂时目标时,咱们需求在函数中先开释它,因为它要脱离 scope。在它还没有任何其它引证时还不能这么做,否则回来前他就会被毁掉。Apple 现在运用一个新的 convention ,让其能够回来暂时目标。做法是当回来一个主动开释值,编译器会发出一个特别符号,这个符号会告知运转时这是契合主动开释条件的。它的后面是 retain,咱们会在后面履行。获取回来地址,也便是一个指针,将它先保存起来,然后脱离运转时的主动开释调用。在运转时,能够将保留时得到的指正和从前做主动开释时保存的指针进行比较,这样符号指令不再是数据之间的比较,比较指针内存拜访少。比较成功就能够省去 autorelease/retain。

autorelease elision 的优化相同也能够削减 2% 巨细。感谢 Apple 为了用户和开发者 OKR 的付出。

SwiftUI

new navigation api,看完感觉我做的小册子还有幻灯运用要花些时刻好好改改了。

接下来,有活干了。

WWDC.playground

明天的 WWDC.playground 嘉宾有谜底科技和 weak self,欢迎来助威。

下面是按分类做的记载:

Swift

String Index 大晋级 String Index Overhaul

参阅

  • WWDC22 Swift 专题
  • Swift 主题
  • Swift Session
  • Swift 文档
  • What’s new in Swift

Regex

规范库多了个 Regex<Output> 类型,Regex 语法与 Perl、Python、Ruby、Java、NSRegularExpression 和许多其他言语兼容。能够用 let regex = try! Regex("a[bc]+")let regex = /a[bc]+/ 写法来运用。SE-0350 Regex Type and Overview 引进 Regex 类型。SE-0351 Regex builder DSL 运用 result builder 来构建正则表达式的 DSL。SE-0354 Regex Literals 简化的正则表达式。SE-0357 Regex-powered string processing algorithms 提案里有依据正则表达式的新字符串处理算法。

RegexBuilder 文档

session Meet Swift Regex 、Swift Regex: Beyond the basics

Regex 示例代码如下:

let s1 = "I am not a good painter"
print(s1.ranges(of: /good/))
do {
    let regGood = try Regex("[a-z]ood")
    print(s1.replacing(regGood, with: "bad"))
} catch {
    print(error)
}
print(s1.trimmingPrefix(/i am /.ignoresCase()))
let reg1 = /(.+?) read (\d+) books./
let reg2 = /(?<name>.+?) read (?<books>\d+) books./
let s2 = "Jack read 3 books."
do {
    if let r1 = try reg1.wholeMatch(in: s2) {
        print(r1.1)
        print(r1.2)
    }
    if let r2 = try reg2.wholeMatch(in: s2) {
        print("name:" + r2.name)
        print("books:" + r2.books)
    }
} catch {
    print(error)
}

运用 regex builders 的官方示例:

// Text to parse:
// CREDIT  03/02/2022  Payroll from employer     $200.23
// CREDIT  03/03/2022  Suspect A           $2,000,000.00
// DEBIT   03/03/2022  Ted's Pet Rock Sanctuary    $2,000,000.00
// DEBIT   03/05/2022  Doug's Dugout Dogs      $33.27
import RegexBuilder
let fieldSeparator = /\s{2,}|\t/
let transactionMatcher = Regex {
  /CREDIT|DEBIT/
  fieldSeparator
  One(.date(.numeric, locale: Locale(identifier: "en_US"), timeZone: .gmt)) // 👈🏻 we define which data locale/timezone we want to use
  fieldSeparator
  OneOrMore {
    NegativeLookahead { fieldSeparator } // 👈🏻 we stop as soon as we see one field separator
    CharacterClass.any
  }
  fieldSeparator
  One(.localizedCurrency(code: "USD").locale(Locale(identifier: "en_US")))
}

在正则表达式中捕获数据,运用 Capture:

let fieldSeparator = /\s{2,}|\t/
let transactionMatcher = Regex {
  Capture { /CREDIT|DEBIT/ } // 👈🏻
  fieldSeparator
  Capture { One(.date(.numeric, locale: Locale(identifier: "en_US"), timeZone: .gmt)) } // 👈🏻
  fieldSeparator
  Capture { // 👈🏻
    OneOrMore {
      NegativeLookahead { fieldSeparator }
      CharacterClass.any
    }
  }
  fieldSeparator
  Capture { One(.localizedCurrency(code: "USD").locale(Locale(identifier: "en_US"))) } // 👈🏻
}
// transactionMatcher: Regex<(Substring, Substring, Date, Substring, Decimal)>

泛型与协议

session Embrace Swift generics 、Design protocol interfaces in Swift

swift 5.6 和之前编写泛型接口如下:

func feed<A>(_ animal: A) where A: Animal
// 👆🏻👇🏻 Equivalents
func feed<A: Animal>(_ animal: A)

swift 5.7 能够这样写:

func feed(_ animal: some Animal)

some 要害字能够用于参数和结构类型。some 会确保类型联系,而 any 会持有任意具体类型,删去类型联系。

SE-0347 Type inference from default expressions 扩展 Swift 泛型参数类型的默许值才能。如下代码示例:

func suffledArray<T: Sequence>(from options: T = 1...100) -> [T.Element] {
    Array(options.shuffled())
}
print(suffledArray())
print(suffledArray(from: ["one", "two", "three"]))

SE-0341 Opaque Parameter Declarations 运用 some 参数简化泛型参数声明。SE-0328 Structural opaque result types 扩展不透明成果回来类型能够运用的规模。SE-0360 Opaque result types with limited availability 可用性有限的不透明成果类型,比方 if #available(macOS 13.0, *) {} 就能够依据体系不同版别回来不同类型,新版别呈现新类型的 View 就能够和曾经的 View 类型区别开。

SE-0309 Unlock existentials for all protocols 改善了 existentials 和 泛型的交互。这样就能够更便利的查看 Any 类型的两个值是否相等

any 要害字充当的是类型擦除的助手,是经过告知编译器你运用 existential 作为类型,此语法可兼容曾经体系。

SE-0346 Lightweight same-type requirements for primary associated types 引进一种新语法,用于契合泛型参数并经过相同类型要求束缚相关类型。SE-0358 Primary Associated Types in the Standard Library 引进首要相关类型概念,并将其带入了规范库。这些相关类型很像泛型,答应开发者将给定相关类型的类型指定为通用束缚。

SE-0353 Constrained Existential Types 依据 SE-0309 和 SE-0346 提案,在 existential 类型的上下文中重用轻量相关类型的束缚。

SE-0352 Implicitly Opened Existentials 答应 Swift 在许多情况下运用协议调用泛型函数。

Swift 论坛上一个对 any 和 some 要害字语法运用场景的讨论,Do any and some help with “Protocol Oriented Testing” at all? 。

Swift Concurrency

session Eliminate data races using Swift Concurrency 、Visualize and optimize Swift concurrency 、Meet Swift Async Algorithms 。

表明持续时刻有了新的放来来表达,对应提案是 SE-0329 Clock, Instant, and Duration ,continuous clock 是在体系睡觉状况还会增加时刻,suspending clock 在体系睡觉状况不会增加时刻。Instants 表明一个确认的时刻。Duration 表明两个时刻阅历了多久。

新增 SE-0338 Clarify the Execution of Non-Actor-Isolated Async Functions 经过收紧可发送性查看的规矩来避免潜在的数据竞赛。

SE-0343 Concurrency in Top-level Code 这个提案首要是更好地支撑指令行东西的开发,能够直接将 concurrency 代码写到 main.swift 文件里。

SE-0340 Unavailable From Async Attribute 供给 noasync 语法以答应咱们将类型和函数符号为在异步上下文不可用。

Task 是按次序履行的,是异步的,在 await 时能够暂停任意次数。task 是自包含的,有自己的资源,能够独立于任何其他 task 独立运转。task 经过在 body 末尾回来一个值来传递目标,值类型没问题,假如是引证类型有或许呈现数据竞赛。

经过 Sendable 协议 Swift 能够协助告知咱们什么时候 task 之间同享数据是安全的。Sendable 描绘的类型能够跨阻隔 domain,不会有数据竞赛,Swift 编译器会在构建时查看数据竞赛。task 的回来类型要契合 Sendable。

引证类型只能在很少的情况下契合 Sendable。比方 final class 只有不可变的存储。关于自己内部同步的引证类型,比方锁,能够用 @unchecked Sendable

class ConcurrentCache<Key: Hashable & Sendable, Value: Sendable>: @unchecked Sendable {
  var lock: NSLock
  var storage: [Key: Value]
  // ...
}

Actor 供给了一种阻隔状况的办法能够消除数据竞赛。运用 task 来履行 actor 界说的代码。一次只能在一个 actor 上履行一个 task。actor 也是依靠 Sendable。actor 是引证类型,但阻隔了他们一切特点和代码来防止并发拜访。@MainActor 表明的是主线程,你要在运用中更新 UI 时来用它。

@MainActor func updateView() {  }
Task { @MainActor in
  // update UI here
}

@MainActor 也能够用于类,类的特点和办法只能在主 main actor 上拜访,除非符号为 nonisolated

@MainActor
class ChickenValley: Sendable {
  var flock: [Chicken]
  var food: [Pineapple]
  func advanceTime() {
    for chicken in flock {
      chicken.eat(from: &food)
    }
  }
}

Distributed Actors

actor 具有分布式方法作业才能,也便是能够 RPC 经过网络读取和写入特点或许调用办法。规划为保护在跨多个进程中的低等级数据竞赛。Distributed actors 能够在两个进程间树立通道,阻隔它们状况,并在它们之间异步通讯。每个 distributed actors 在 actor 初始化时分配一个不能够手动创立的 id,在它所属整个 distributed actor 体系中仅有标识所指 actor,这样无论 distributed actors 在哪,都能够以相同的办法与之交互。

session Meet distributed actors in Swift 。这儿有个 distributed actors 的代码示例 TicTacFish: Implementing a game using distributed actors

SE-0336 Distributed Actor Isolation 和 SE-0344 Distributed Actor Runtime 是两个 Distributed Actors 的相关提案。

Apple 供给了一个参阅的服务端 cluster actor 体系完结示例,cluster actor system implementation 。

Optional

SE-0345 if let shorthand for shadowing an existing optional variable 引进的新语法,用于 unwrapping optinal。

let s1: String? = "hey"
let s2: String? = "u"
if let s1 {
    print(s1)
}
guard let s1, let s2 else { return }
print(s1 + " " + s2)

类型推断

SE-0326 进步了 Swift 对闭包运用参数和类型推断的才能。如下代码:

let a = [1,2,3]
let r = a.map { i in
    if i >= 2 {
        return "\(i) 大于等于2"
    } else {
        return "\(i) 小于2"
    }
}
print(r)

Result Builders

SE-0348 buildPartialBlock for result builders 简化了完结杂乱 result buiders 所需的重载。

Swift-DocC

现在支撑 Swift、OC 和 C,文档符号相同。.doccarchive 包含可布置的网站内容,兼容大多数托管服务,比方 Github pages。布置到在线服务上可参阅 Generating Documentation for Hosting Online 和 Publishing to GitHub Pages 文档。

和 SPM 集成参看 SwiftDocCPlugin 。

session 有 What’s new in Swift -DocC 和 Improve the discoverability of your Swift-DocC content

SE-0356 Swift Snippets 代码片段用于示例文档的提案。

调试

session Debug Swift debugging with LLDB

编译器编译 swift 文件生成 .o 文件会有 __debug_info 段,其间有能够映射到源文件和行号的地址。debug 信息能够链接到 .dSYM 包。debug 信息链接器叫 dsymutil,dsymutil 能够为每个动态库、framework 或 dylib 和可履行文件打包一个 debug 信息存档(.dSYM 包)。

image 和途径怎样重映射。运用 image list nameOfFramework 来查看 LLDB 是否找到了咱们运用程序里嵌入的第三方结构的 debug dSYM。运用 image lookup 0xMemoryAddressHere 获取当时地址更多信息。要从头映射源文件 .dSYM 途径,运用 settings set target.source-map old/path new/path。每个 .dSYM 都有一个 UUID.plist,咱们能够在其间设置 DBGSourcePathRemapping 这个字典。

Xcode 14 新增 swift-healthcheck 指令,这个指令能够了解 module 为何导入失败。

LLDB 怎样找到 Swift module?每个 .dSYM 包都能够包含二级制 swift module,其间或许包含桥头文件、swift 接口文件 .swiftinterface,还有 debug 信息。静态存档不是由链接器生成的,需求向链接器注册 swift module,运用 ld ... -add-ast-path /path/to/My.swiftmodule ,动态库和可履行文件的话,Xcode 会主动完结此操作。能够运用 dsymutil 来 dump 你可履行文件的符号表,并用 grep 找 swiftmodule,指令是 dsymutil -s MyApp | grep .swiftmodule

内存办理

相关提案包含 SE-0349 Unaligned Loads and Stores from Raw Memory 、SE-0334 Pointer API Usability Improvements 、SE-0333 Expand usability of withMemoryRebound

Set 运用新的 Temporary Buffers 功用,让 intersect 速度提升了 4 到 6 倍。

SwiftUI

介绍

Kuba Suder 做了一个 SwiftUI Index/Changelog ,从官方文档中提取版别信息,一目了然 SwiftUI 每个版别 view,modifier 还有特点做了哪些增加和改变。当然也包含这次 SwiftUI 4 的更新。还有份对本年更新收拾的 cheat sheet What’s New In SwiftUI for iOS Cheat Sheet – WWDC22 。

SwiftUI 4 做了许多细节更新,比方增加了后台任务函数 backgroundTask(_:action:) 。List 改用 UICollectionView。AnyLayout 让 HStack 和 VStack 之间能够自由切换。scrollDismissesKeyboard() modifier 能够让键盘在翻滚时主动 dismiss。scrollIndicators() modifier 能够躲藏 ScrollView 和 List 等视图的翻滚指示。defersSystemGestures() modifier 答应咱们的手势优先于体系的内置手势。色彩的 .gradient 能够获得很简略的突变,Rectangle().fill(.red.gradient),还有 .shadow 用来创立投影 Rectangle().fill(.red.shadow(.drop(color: .black, radius: 10))),还有 .inner 内阴影。lineLimit() modifier 支撑规模设置。还有一些 modifier 支撑 toggle 参数,比方 .bold().italic() 等,这样利于运转时进行调整。

参阅

  • WWDC22 SwiftUI 和 UI 库相关专题
  • 官方教程 Learnning SwiftUI
  • SwiftUI 主题
  • SwiftUI Session
  • SwiftUI 文档
  • Learning SwiftUI 一年一度官方入门教程
  • Food Truck: Building a SwiftUI multiplatform app 一套代码适配 Mac、iPad 和 iPhone 的官方示例
  • Reda Lemeden 收拾的 WWDC22 一切 SwiftUI 相关内容

session:

  • What’s new in SwiftUI

社区收拾的和 SwiftUI 的 digital lounges 内容:

  • WWDC swiftui-lounge
  • WWDC 2022: Lessons from the SwiftUI Digital Lounges javier 收拾的,做了具体的分类
  • #swiftui-lounge #wwdc22

Navigation 接口

控制导航发动状况、办理 size class 之间的 transition 和呼应 deep link。

Navigation bar 有新的默许行为,假如没有供给标题,导航栏默许为 inline title 显现形式。运用 navigationBarTitleDisplayMode(_:) 改变显现形式。假如 navigation bar 没有标题、东西栏项或查找内容,它就会主动躲藏。运用 .toolbar(.visible) modifier 显现一个空 navigation bar。

参阅:

  • Migrating to New Navigation Types 官方搬迁攻略
  • NavigationStack
  • NavigationSplitView
  • The SwiftUI cookbook for navigation

NavigationStack 的示例:

struct PNavigationStack: View {
    @State private var a = [1, 3, 9] // 深层链接
    var body: some View {
        NavigationStack(path: $a) {
            List(1..<10) { i in
                NavigationLink(value: i) {
                    Label("第 \(i) 行", systemImage: "\(i).circle")
                }
            }
            .navigationDestination(for: Int.self) { i in
                Text("第 \(i) 行内容")
            }
            .navigationTitle("NavigationStack Demo")
        }
    }
}

这儿的 path 设置了 stack 的深度途径。

NavigationSplitView 两栏的比方:

struct PNavigationSplitViewTwoColumn: View {
    @State private var a = ["one", "two", "three"]
    @State private var choice: String?
    var body: some View {
        NavigationSplitView {
            List(a, id: \.self, selection: $choice, rowContent: Text.init)
        } detail: {
            Text(choice ?? "选一个")
        }
    }
}

NavigationSplitView 三栏的比方:

struct PNavigationSplitViewThreeColumn: View {
    struct Group: Identifiable, Hashable {
        let id = UUID()
        var title: String
        var subs: [String]
    }
    @State private var gps = [
        Group(title: "One", subs: ["o1", "o2", "o3"]),
        Group(title: "Two", subs: ["t1", "t2", "t3"])
    ]
    @State private var choiceGroup: Group?
    @State private var choiceSub: String?
    @State private var cv = NavigationSplitViewVisibility.automatic
    var body: some View {
        NavigationSplitView(columnVisibility: $cv) {
            List(gps, selection: $choiceGroup) { g in
                Text(g.title).tag(g)
            }
            .navigationSplitViewColumnWidth(250)
        } content: {
            List(choiceGroup?.subs ?? [], id: \.self, selection: $choiceSub) { s in
                Text(s)
            }
        } detail: {
            Text(choiceSub ?? "选一个")
            Button("点击") {
                cv = .all
            }
        }
        .navigationSplitViewStyle(.prominentDetail)
    }
}

navigationSplitViewColumnWidth() 是用来自界说宽的,navigationSplitViewStyle 设置为 .prominentDetail 是让 detail 的视图尽量坚持其巨细。

SwiftUI 新加了个功用能够装备是否躲藏 Tabbar,这样在从主页进入下一级时就能够挑选不显现底部标签栏了,示例代码如下:

ContentView().toolbar(.hidden, in: .tabBar)

相比较曾经 NavigationView 增强的是 destination 能够依据值的不同类型展现不同的意图页面,示例代码如下:

struct PNavigationStackDestination: View {
    var body: some View {
        NavigationStack {
            List {
                NavigationLink(value: "字符串") {
                    Text("字符串")
                }
                NavigationLink(value: Color.red) {
                    Text("红色")
                }
            }
            .navigationTitle("不同类型 Destination")
            .navigationDestination(for: Color.self) { c in
                c.clipShape(Circle())
            }
            .navigationDestination(for: String.self) { s in
                Text("\(s) 的 detail")
            }
        }
    }
}

Swift Charts

可视化数据,运用 SwiftUI 语法来创立。还能够运用 ChartRenderer 接口将图标烘托成图。

官方文档 Swift Charts

入门参看 Hello Swift Charts

Apple 文章 Creating a chart using Swift Charts

高档定制和创立更精密图表,能够看这个 session Swift Charts: Raise the bar 这个 session 也会说到如安在图表中进行交互。这儿是 session 对应的代码示例 Visualizing your app’s data 。

图表规划的 session,Design an effective chart 和 Design app experiences with charts 。

下面是一个简略的代码示例:

import Charts
struct PChartModel: Hashable {
    var day: String
    var amount: Int = .random(in: 1..<100)
}
extension PChartModel {
    static var data: [PChartModel] {
        let calendar = Calendar(identifier: .gregorian)
        let days = calendar.shortWeekdaySymbols
        return days.map { day in
            PChartModel(day: day)
        }
    }
}
struct PlayCharts: View {
    var body: some View {
        Chart(PChartModel.data, id: \.self) { v in
            BarMark(x: .value("天", v.day), y: .value("数量", v.amount))
        }
        .padding()
    }
}
struct PSwiftCharts: View {
    struct CData: Identifiable {
        let id = UUID()
        let i: Int
        let v: Double
    }
    @State private var a: [CData] = [
        .init(i: 0, v: 2),
        .init(i: 1, v: 20),
        .init(i: 2, v: 3),
        .init(i: 3, v: 30),
        .init(i: 4, v: 8),
        .init(i: 5, v: 80)
    ]
    var body: some View {
        Chart(a) { i in
            LineMark(x: .value("Index", i.i), y: .value("Value", i.v))
            BarMark(x: .value("Index", i.i), yStart: .value("开端", 0), yEnd: .value("完毕", i.v))
                .foregroundStyle(by: .value("Value", i.v))
        } // end Chart
    } // end body
}

BarMark 用于创立条形图,LineMark 用于创立折线图。SwiftUI Charts 结构还供给 PointMark、AxisMarks、AreaMark、RectangularMark 和 RuleMark 用于创立不同类型的图表。注释运用 .annotation modifier,修正色彩能够运用 .foregroundStyle modifier。.lineStyle modifier 能够修正线宽。

AxisMarks 的示例如下:

struct MonthlySalesChart: View {
    var body: some View {
        Chart(data, id: \.month) {
            BarMark(
                x: .value("Month", $0.month, unit: .month),
                y: .value("Sales", $0.sales)
            )
        }
        .chartXAxis {
            AxisMarks(values: .stride(by: .month)) { value in
                if value.as(Date.self)!.isFirstMonthOfQuarter {
                    AxisGridLine().foregroundStyle(.black)
                    AxisTick().foregroundStyle(.black)
                    AxisValueLabel(
                        format: .dateTime.month(.narrow)
                    )
                } else {
                    AxisGridLine()
                }
            }
        }
    }
}

可交互图表明例如下:

struct InteractiveBrushingChart: View {
    @State var range: (Date, Date)? = nil
    var body: some View {
        Chart {
            ForEach(data, id: \.day) {
                LineMark(
                    x: .value("Month", $0.day, unit: .day),
                    y: .value("Sales", $0.sales)
                )
                .interpolationMethod(.catmullRom)
                .symbol(Circle().strokeBorder(lineWidth: 2))
            }
            if let (start, end) = range {
                RectangleMark(
                    xStart: .value("Selection Start", start),
                    xEnd: .value("Selection End", end)
                )
                .foregroundStyle(.gray.opacity(0.2))
            }
        }
        .chartOverlay { proxy in
            GeometryReader { nthGeoItem in
                Rectangle().fill(.clear).contentShape(Rectangle())
                    .gesture(DragGesture()
                        .onChanged { value in
                            // Find the x-coordinates in the chart’s plot area.
                            let xStart = value.startLocation.x - nthGeoItem[proxy.plotAreaFrame].origin.x
                            let xCurrent = value.location.x - nthGeoItem[proxy.plotAreaFrame].origin.x
                            // Find the date values at the x-coordinates.
                            if let dateStart: Date = proxy.value(atX: xStart),
                               let dateCurrent: Date = proxy.value(atX: xCurrent) {
                                range = (dateStart, dateCurrent)
                            }
                        }
                        .onEnded { _ in range = nil } // Clear the state on gesture end.
                    )
            }
        }
    }
}

社区做的更多 Swift Charts 范例 Swift Charts Examples 。

Advanced layout control

session Compose custom layouts with SwiftUI

供给了新的 Grid 视图来一起满足 VStack 和 HStack。还有一个更低等级 Layout 接口,能够完全控制构建运用所需的布局。别的还有 ViewThatFits 能够主动挑选填充可用空间的办法。

Grid 示例代码如下:

Grid {
    GridRow {
        Text("One")
        Text("One")
        Text("One")
    }
    GridRow {
        Text("Two")
        Text("Two")
    }
    Divider()
    GridRow {
        Text("Three")
        Text("Three")
            .gridCellColumns(2)
    }
}

gridCellColumns() modifier 能够让一个单元格跨多列。

ViewThatFits 的新视图,答应依据适合的巨细放视图。ViewThatFits 会主动挑选关于当时屏幕巨细适宜的子视图进行显现。Ryan Lintott 的示例效果 ,对应示例代码 LayoutThatFits.swift 。

新的 Layout 协议能够观看 Swift Talk 第 308 期 The Layout Protocol 。

经过契合 Layout 协议,咱们能够自界说一个自界说的布局容器,直接参与 SwiftUI 的布局进程。新的 ProposedViewSize 结构,它是容器视图供给的巨细。 Layout.Subviews 是布局视图的子视图署理集合,咱们能够在其间为每个子视图请求各种布局特点。

public protocol Layout: Animatable {
  static var layoutProperties: LayoutProperties { get }
  associatedtype Cache = Void
  typealias Subviews = LayoutSubviews
  func updateCache(_ cache: inout Self.Cache, subviews: Self.Subviews)
  func spacing(subviews: Self.Subviews, cache: inout Self.Cache) -> ViewSpacing
  /// We return our view size here, use the passed parameters for computing the
  /// layout.
  func sizeThatFits(
    proposal: ProposedViewSize, 
    subviews: Self.Subviews, 
    cache: inout Self.Cache // 👈🏻 use this for calculated data shared among Layout methods
  ) -> CGSize
  /// Use this to tell your subviews where to appear.
  func placeSubviews(
    in bounds: CGRect, // 👈🏻 region where we need to place our subviews into, origin might not be .zero
    proposal: ProposedViewSize, 
    subviews: Self.Subviews, 
    cache: inout Self.Cache
  )
  // ... there are more a couple more optional methods
}

下面比方是一个自界说的水平 stack 视图,为其一切子视图供给其最大子视图的宽度:

struct MyEqualWidthHStack: Layout {
  /// Returns a size that the layout container needs to arrange its subviews.
  /// - Tag: sizeThatFitsHorizontal
  func sizeThatFits(
    proposal: ProposedViewSize,
    subviews: Subviews,
    cache: inout Void
  ) -> CGSize {
    guard !subviews.isEmpty else { return .zero }
    let maxSize = maxSize(subviews: subviews)
    let spacing = spacing(subviews: subviews)
    let totalSpacing = spacing.reduce(0) { $0 + $1 }
    return CGSize(
      width: maxSize.width * CGFloat(subviews.count) + totalSpacing,
      height: maxSize.height)
  }
  /// Places the stack's subviews.
  /// - Tag: placeSubviewsHorizontal
  func placeSubviews(
    in bounds: CGRect,
    proposal: ProposedViewSize,
    subviews: Subviews,
    cache: inout Void
  ) {
    guard !subviews.isEmpty else { return }
    let maxSize = maxSize(subviews: subviews)
    let spacing = spacing(subviews: subviews)
    let placementProposal = ProposedViewSize(width: maxSize.width, height: maxSize.height)
    var nextX = bounds.minX + maxSize.width / 2
    for index in subviews.indices {
      subviews[index].place(
        at: CGPoint(x: nextX, y: bounds.midY),
        anchor: .center,
        proposal: placementProposal)
      nextX += maxSize.width + spacing[index]
    }
  }
  /// Finds the largest ideal size of the subviews.
  private func maxSize(subviews: Subviews) -> CGSize {
    let subviewSizes = subviews.map { $0.sizeThatFits(.unspecified) }
    let maxSize: CGSize = subviewSizes.reduce(.zero) { currentMax, subviewSize in
      CGSize(
        width: max(currentMax.width, subviewSize.width),
        height: max(currentMax.height, subviewSize.height))
    }
    return maxSize
  }
  /// Gets an array of preferred spacing sizes between subviews in the
  /// horizontal dimension.
  private func spacing(subviews: Subviews) -> [CGFloat] {
    subviews.indices.map { index in
      guard index < subviews.count - 1 else { return 0 }
      return subviews[index].spacing.distance(
        to: subviews[index + 1].spacing,
        along: .horizontal)
    }
  }
}

自界说 layout 只能拜访子视图署理 Layout.Subviews ,而不是视图或数据模型。咱们能够经过 LayoutValueKey 在每个子视图上存储自界说值,经过 layoutValue(key:value:) modifier 设置。

private struct Rank: LayoutValueKey {
  static let defaultValue: Int = 1
}
extension View {
  func rank(_ value: Int) -> some View { // 👈🏻 convenience method
    layoutValue(key: Rank.self, value: value) // 👈🏻 the new modifier
  }
}

然后,咱们就能够经过 Layout 办法中的 Layout.Subviews 署理读取自界说 LayoutValueKey 值:

func placeSubviews(
  in bounds: CGRect,
  proposal: ProposedViewSize,
  subviews: Subviews,
  cache: inout Void
) {
  let ranks = subviews.map { subview in
    subview[Rank.self] // 👈🏻
  }
  // ...
}

要在布局之间改变运用动画,需求用 AnyLayout,代码示例如下:

struct PAnyLayout: View {
    @State private var isVertical = false
    var body: some View {
        let layout = isVertical ? AnyLayout(VStack()) : AnyLayout(HStack())
        layout {
            Image(systemName: "star").foregroundColor(.yellow)
            Text("Starming.com")
            Text("戴铭")
        }
        Button("Click") {
            withAnimation {
                isVertical.toggle()
            }
        } // end button
    } // end body
}

一起 Text 和图片也支撑了样式布局改变,代码示例如下:

struct PTextTransitionsView: View {
    @State private var expandMessage = true
    private let mintWithShadow: AnyShapeStyle = AnyShapeStyle(Color.mint.shadow(.drop(radius: 2)))
    private let primaryWithoutShadow: AnyShapeStyle = AnyShapeStyle(Color.primary.shadow(.drop(radius: 0)))
    var body: some View {
        Text("Dai Ming Swift Pamphlet")
            .font(expandMessage ? .largeTitle.weight(.heavy) : .body)
            .foregroundStyle(expandMessage ? mintWithShadow : primaryWithoutShadow)
            .onTapGesture { withAnimation { expandMessage.toggle() }}
            .frame(maxWidth: expandMessage ? 150 : 250)
            .drawingGroup()
            .padding(20)
            .background(.cyan.opacity(0.3), in: RoundedRectangle(cornerRadius: 6))
    }
}

分享接口

Transferable 协议使数据能够用于剪切板、拖放和 Share Sheet。

能够在自己运用程序之间或你的运用和其他运用之间发送或接受可传输项目。

支撑 SwiftUI 来运用。

官方文档 Core Transferable

session Meet Transferable

新增一个专门用来接受 Transferable 的按钮视图 PasteButton,运用示例如下:

struct PPasteButton: View {
    @State private var s = "戴铭"
    var body: some View {
        TextField("输入", text: $s)
            .textFieldStyle(.roundedBorder)
        PasteButton(payloadType: String.self) { str in
            guard let first = str.first else { return }
            s = first
        }
    }
}

ShareLink

ShareLink 视图能够让你轻松同享数据。示例代码如下:

struct PShareLink: View {
    let url = URL(string: "https://ming1016.github.io/")!
    var body: some View {
        ShareLink(item: url, message: Text("戴铭的博客"))
        ShareLink("戴铭的博客", item: url)
        ShareLink(item: url) {
            Label("戴铭的博客", systemImage: "swift")
        }
    }
}

锁屏的 Widget

和 WatchOS 相同,能够瞟一眼就获取信息。

官方攻略 Creating Lock Screen Widgets and Watch Complications

Bottom Sheet

SwiftUI 新推出的 presentationDetents() modifier 能够创立一个能够定制的 bottom sheet。示例代码如下:

struct PSheet: View {
    @State private var isShow = false
    var body: some View {
        Button("显现 Sheet") {
            isShow.toggle()
        }
        .sheet(isPresented: $isShow) {
            Text("这儿是 Sheet 的内容")
                .presentationDetents([.medium, .large])
        }
    }
}

detent 默许值是 .large。也能够供给一个百分比,比方 .presentationDetents([.fraction(0.7)]),或许直接指定高度 .presentationDetents([.height(100)])

presentationDragIndicator modifier 能够用来显现躲藏拖动标识。

List

list 支撑 Section footer。

list 分隔符能够自界说,运用 HorizontalEdge.leadingHorizontalEdge.trailing

list 不运用 UITableView 了。

本年 list 还新增了一个 EditOperation 能够主动生成移动和删去,新增了 edits 参数,传入 [.delete, .move] 数组即可。这也是一个演示怎么更好扩展和装备功用的办法。

ScrollView

新增 modifier

ScrollView {
    ForEach(0..<300) { i in
        Text("\(i)")
            .id(i)
    }
}
.scrollDisabled(false)
.scrollDismissesKeyboard(.interactively)
.scrollIndicators(.visible)

TextField

支撑多行,运用 Axis.vertical 以答应多行。TextField 超越行约束能够变成翻滚视图。

本年 TextField 能够嵌到 .alert 里了。

Search

.searchable 支撑 token 和 scope,示例如下:

struct PSearchTokensAndScopes: View {
    enum AttendanceScope {
        case inPerson, online
    }
    @State private var queryText: String
    @State private var queryTokens: [InvitationToken]
    @State private var scope: AttendanceScope
    var body: some View {
        invitationCountView()
            .searchable(text: $queryText, tokens: $queryTokens, scope: $scope) { token in
                Label(token.diplayName, systemImage: token.systemImage)
            } scopes: {
                Text("In Person").tag(AttendanceScope.inPerson)
                Text("Online").tag(AttendanceScope.online)
            }
    }
}

Gauge

SwiftUI 引进一个新显现进展的视图 Gauge。

简略示例如下:

struct PGauge: View {
    @State private var progress = 0.45
    var body: some View {
        Gauge(value: progress) {
            Text("进展")
        } currentValueLabel: {
            Text(progress.formatted(.percent))
        } minimumValueLabel: {
            Text(0.formatted(.percent))
        } maximumValueLabel: {
            Text(100.formatted(.percent))
        }
        Gauge(value: progress) {
        } currentValueLabel: {
            Text(progress.formatted(.percent))
                .font(.footnote)
        }
        .gaugeStyle(.accessoryCircularCapacity)
        .tint(.cyan)
    }
}

Group Form

Form 本年也得到了增强,示例如下:

Form {
    Section {
        LabeledContent("Location") {
            AddressView(location)
        }
        DatePicker("Date", selection: $date)
        TextField("Description", text: $eventDescription, axis: .vertical)
            .lineLimit(3, reservesSpace: true)
    }
    Section("Vibe") {
        Picker("Accent color", selection: $accent) {
            ForEach(Theme.allCases) { accent in
                Text(accent.rawValue.capitalized).tag(accent)
            }
        }
        Picker("Color scheme", selection: $scheme) {
            Text("Light").tag(ColorScheme.light)
            Text("Dark").tag(ColorScheme.dark)
        }
#if os(macOS)
        .pickerStyle(.inline)
#endif
        Toggle(isOn: $extraGuests) {
            Text("Allow extra guests")
            Text("The more the merrier!")
        }
        if extraGuests {
            Stepper("Guests limit", value: $spacesCount, format: .number)
        }
    }
    Section("Decorations") {
        Section {
            List(selection: $selectedDecorations) {
                DisclosureGroup {
                    HStack {
                        Toggle("Balloons 🎈", isOn: $includeBalloons)
                        Spacer()
                        decorationThemes[.balloon].map { $0.swatch }
                    }
                    .tag(Decoration.balloon)
                    HStack {
                        Toggle("Confetti 🎊", isOn: $includeConfetti)
                        Spacer()
                        decorationThemes[.confetti].map { $0.swatch }
                    }
                    .tag(Decoration.confetti)
                    HStack {
                        Toggle("Inflatables 🪅", isOn: $includeInflatables)
                        Spacer()
                        decorationThemes[.inflatables].map { $0.swatch }
                    }
                    .tag(Decoration.inflatables)
                    HStack {
                        Toggle("Party Horns 🥳", isOn: $includeBlowers)
                        Spacer()
                        decorationThemes[.noisemakers].map { $0.swatch }
                    }
                    .tag(Decoration.noisemakers)
                } label: {
                    Toggle("All Decorations", isOn: [
                        $includeBalloons, $includeConfetti,
                        $includeInflatables, $includeBlowers
                    ])
                    .tag(Decoration.all)
                }
#if os(macOS)
                .toggleStyle(.checkbox)
#endif
            }
            Picker("Decoration theme", selection: themes) {
                Text("Blue").tag(Theme.blue)
                Text("Black").tag(Theme.black)
                Text("Gold").tag(Theme.gold)
                Text("White").tag(Theme.white)
            }
#if os(macOS)
            .pickerStyle(.radioGroup)
#endif
        }
    }
}
.formStyle(.grouped)

Button

.buttonStyle 可组合,示例如下:

struct PButtonStyleComposition: View {
    @State private var isT = false
    var body: some View {
        Section("标签") {
            VStack(alignment: .leading) {
                HStack {
                    Toggle("Swift", isOn: $isT)
                    Toggle("SwiftUI", isOn: $isT)
                }
                HStack {
                    Toggle("Swift Chart", isOn: $isT)
                    Toggle("Navigation API", isOn: $isT)
                }
            }
            .toggleStyle(.button)
            .buttonStyle(.bordered)
        }
    }
}

Tap Location

能够获取点击的方位,示例代码如下:

Rectangle()
    .fill(.green)
    .frame(width: 50, height: 50)
    .onTapGesture(coordinateSpace: .global) { location in
        print("Tap in \(location)")
    }

其间 coordinateSpace 指定为 .global 表明方位是相对屏幕左上角,默许是相对当时视图的左上角的方位。

挑选多个日期

MultiDatePicker 视图会显现一个日历,用户能够挑选多个日期,能够设置挑选规模。示例如下:

struct PMultiDatePicker: View {
    @Environment(\.calendar) var cal
    @State var dates: Set<DateComponents> = []
    var body: some View {
        MultiDatePicker("挑选个日子", selection: $dates, in: Date.now...)
        Text(s)
    }
    var s: String {
        dates.compactMap { c in
            cal.date(from:c)?.formatted(date: .long, time: .omitted)
        }
        .formatted()
    }
}

PhotosPick

支撑图片挑选,示例代码如下:

import PhotosUI
import CoreTransferable
struct ContentView: View {
    @ObservedObject var viewModel: FilterModel = .shared
    var body: some View {
        NavigationStack {
            Gallery()
                .navigationTitle("Birthday Filter")
                .toolbar {
                    PhotosPicker(
                        selection: $viewModel.imageSelection,
                        matching: .images
                    ) {
                        Label("Pick a photo", systemImage: "plus.app")
                    }
                    Button {
                        viewModel.applyFilter()
                    } label: {
                        Label("Apply Filter", systemImage: "camera.filters")
                    }
                }
        }
    }
}

Table

本年 iOS 和 iPadOS 也能够运用上一年只能在 macOS 上运用的 Table了,据 digital lounges 里说,iOS table 的功用和 list 差不多,table 默许为 plian list。我想 iOS 上加上 table 仅仅为了兼容 macOS 代码吧。

table 运用示例如下:

Table(attendeeStore.attendees) {
    TableColumn("Name") { attendee in
        AttendeeRow(attendee)
    }
    TableColumn("City", value: \.city)
    TableColumn("Status") { attendee in
        StatusRow(attendee)
    }
}
.contextMenu(forSelectionType: Attendee.ID.self) { selection in
    if selection.isEmpty {
        Button("New Invitation") { addInvitation() }
    } else if selection.count == 1 {
        Button("Mark as VIP") { markVIPs(selection) }
    } else {
        Button("Mark as VIPs") { markVIPs(selection) }
    }
}

Toolbar

对 toolbar 的自界说,示例如下:

.toolbar(id: "toolbar") {
    ToolbarItem(id: "new", placement: .secondaryAction) {
        Button(action: {}) {
            Label("New Invitation", systemImage: "envelope")
        }
    }
}
.toolbarRole(.editor)

SF Symbol

SF Symbol 支撑变量值,能够经过设置 variableValue 来填充不同部分,比方 wifi 图标,不同值会亮不同部分,Image(systemName: "wifi", variableValue: 0.5)

Gradient 和 Shadow

下面是个简略示例:

struct PGradientAndShadow: View {
    var body: some View {
        Image(systemName: "bird")
            .frame(width: 150, height: 150)
            .background(in: Rectangle())
            .backgroundStyle(.cyan.gradient)
            .foregroundStyle(.white.shadow(.drop(radius: 1, y: 3.0)))
            .font(.system(size: 60))
    }
}

Paul Hudson 运用 Core Motion 做了一个阴影随设备倾斜而改变的效果,十分棒,How to use inner shadows to simulate depth with SwiftUI and Core Motion 。

嵌入 UIKit

示例如下:

cell.contentConfiguration = UIHostingConfiguration {
    VStack {
        Image(systemName: "wand.and.stars")
            .font(.title)
        Text("Like magic!")
            .font(.title2).bold()
    }
    .foregroundStyle(Color.purple)
}

macOS

支撑了 window,能够控制方位和巨细。官方代码示例 Bringing multiple windows to your SwiftUI app

openWindow 代码示例如下:

struct PartyPlanner: App {
    var body: some Scene {
        WindowGroup("Party Planner") {
            PartyPlannerHome()
        }
        Window("Party Budget", id: "budget") {
            Text("Budget View")
        }
        .keyboardShortcut("0")
        .defaultPosition(.topLeading)
        .defaultSize(width: 220, height: 250)
    }
}
struct DetailView: View {
    @Environment(\.openWindow) var openWindow
    var body: some View {
        Text("Detail View")
            .toolbar {
                Button {
                    openWindow(id: "budget")
                } label: {
                    Image(systemName: "dollarsign")
                }
            }
    }
}

session Bring multiple windows to your SwiftUI app 两个新 Scene 类型。WindowGroup 答应多 window。MenuBarExtra。可编程办法翻开新 window 和 document。

MenuBarExtra 代码示例如下:

struct PartyPlanner: App {
    var body: some Scene {
        Window("Party Budget", id: "budget") {
            Text("Budget View")
        }
        MenuBarExtra("Bulletin Board", systemImage: "quote.bubble") {
            BulletinBoard()
        }
        .menuBarExtraStyle(.window)
    }
}

和解 AppKit 混编的 session Use SwiftUI with AppKit

The craft of SwiftUI API design: Progressive disclosure 运用 windows 还有 MenuBarExtra,运用 modifier 来自界说运用程序 window 的 presentation 和行为。

运用 .dropDestination 来支撑拖动。示例如下:

.dropDestination(payloadType: Image.self) { receivedImages, location in
        guard let image = receivedImages.first else {
            return false
        }
        viewModel.imageState = .success(image)
        return true
    }

本年有新的 FormStyle ,示例如下:

Form {
    Picker("Notify Me About:", selection: $notifyMeAbout) {
        Text("Direct Messages").tag(NotifyMeAboutType.directMessages)
        Text("Mentions").tag(NotifyMeAboutType.mentions)
        Text("Anything").tag(NotifyMeAboutType.anything)
    }
    Toggle("Play notification sounds", isOn: $playNotificationSounds)
    Toggle("Send read receipts", isOn: $sendReadReceipts)
    Picker("Profile Image Size:", selection: $profileImageSize) {
        Text("Large").tag(ProfileImageSize.large)
        Text("Medium").tag(ProfileImageSize.medium)
        Text("Small").tag(ProfileImageSize.small)
    }
    .pickerStyle(.inline)
}
.formStyle(.columns)

Apple 自身在 macOS 体系中运用了多少 SwiftUI 呢?邮件、iWork 和 Keychain Access 的部分视图运用了,笔记、照片 和 Xcode 部分功用及新增功用的完好界面都是用的 SwiftUI,别的控制中心、字体册和体系设置的大部分都是用 SwiftUI 开发了。

ImageRenderer

能够将 SwiftUI 的 View 生成图片。

官方参阅文档 ImageRenderer

后台任务

session Efficiency awaits: Background tasks in SwiftUI 了解怎么运用 SwiftUI 后台任务 API 简练地处理任务。展现怎么运用 Swift Concurrency 来处理网络呼应、后台改写等——一起坚持功用和功率。

Xcode 14

Xcode 14 里有新的 Swift 5.7,其间对泛型和协议有很大的改善。

参阅

  • WWDC22 开发东西专题
  • 装备多渠道运用程序
  • 运用 DocC 给运用程序、结构、包创立文档
  • 在设备上启用开发者形式
  • Xcode 14 Beta Release Notes
  • What’s new in Xcode
  • Demystify parallelization in Xcode builds
  • Use Xcode to develop a multiplatform app
  • Use Xcode for server-side development
  • Simplify C++ templates with concepts

通用

编出来的二进制小 30%。

改善了并行性,构建提速 25%。

改善了在 iOS 设备上调试 Swift 程序的功用。

供给单一图标巨细,Xcode 完结剩余的。

更智能的代码完结,翻滚时置顶类、结构体和函数名。过错音讯在从头处理时会变暗。

Xcode 查找和替换栏中能够运用正则表达式。信任今后社区会呈现许多好用的正则表达式分享。

Xcode Organizer 中新增 Hang 陈述,用来供给主线程上产生挂起的调用仓库信息,以及供给设备和 iOS 版别信息等统计信息。

Xcode 14 现在支撑为 iPadOS 开发 DriverKit 驱动程序。

创立新 C++ 项目,Clang 默许运用 C++20。现已完结了几篇 C++20 和 C++2b 论文。

iOS、tvOS 和 watchOS 的构建默许不再包含 bitcode。

legacy 构建体系被删去,LLVM 14 也不再支撑 legacy。

Xcode 中的 Swift-DocC 现支撑 OC 和 C 的 API 构建文档。生成的 Swift-DocC 文档网站包含一个新的导航侧边栏,用于浏览和过滤文档。可将 Swift-DocC 布置到 GitHub Pages。

功用问题修正

代码完结不再主动导入模块。

进步了杂乱表达式 SwiftUI 中代码完结的速度和准确性。

修正了包含许多过错或警告的文件时导致功用下降的问题。

修正了 minimap 在长文件时功用问题。

源码编辑器

翻滚编辑器时,Xcode 会将代码结构的元素固定到编辑器顶部。

支撑了 Regex 表达式语法高亮。Editor > Refactoring > Convert to Regex Builder 能够将正则文本转成等效 Regex builder。

能够输入匹配参数来挑选代码完结中默许参数的任意组合。

Swift 中代码完结供给依据变量名的 map、filter 和 contains 的 snippet。

进步 Swift 代码完结的准确性。

SwiftUI 的代码完结,现在有了 List 和 ForEach 的 snippet。

Xcode 14 还要许多贴心代码完结改善,比方写 struct 的 init 能够主动完结。Codable 的 encode 也能够主动完结。

Xcode Preview

Preview 增强,默许是交互式的。

创立新项目会主动 resume。许多编辑时也不会暂停。会动态调整更新频率。

Swift Packages

引进新参数 moduleAliases 来为冲突的模块界说仅有称号,并以新称号构建而不必改代码。留意的是起别名的模块要是纯 Swift 模块。

答应运用 Swift Package command plugins。Xcode 为 Swift Package plugins 供给了 XcodeProjectPlugin 接口,这个接口扩展了 Swift Package Manager 的 PackagePlugin 接口。用这个接口能够获得 Xcode 项目结构的简化描绘。

session 有 Meet Swift Package plugins 和 Create Swift Package plugins 。

Instrument

Hang Tracing 东西,能够显现运用程序的主线程什么时候无法长时刻处理传入事情,然后导致 UI 卡住。

Runloop 东西,显现 runloop 的运用和独自的迭代,视觉上区分了进程中一切 runloop 的 runloop sleep 和 busy interval。

Instrument 新模板更便利调试 distributed actors 和其它 Swift concurrency 特性。

memory graph 调试器能够显现 memory graph 的一切传入和传出引证。

Instrument 现有一个新的 Swift Concurrency 模板,用于盯梢 swift concurrency 的运用。这个模板包含 Swift Tasks 东西,可显现随时刻改变的 task 的状况,总结 task 状况,供给具体的 task 描绘,task 联系和 task 创立 callstacks 的调用树结构。还有 Swift Actors 东西,能够盯梢 actor 之间的 task 行为,显现每个 actor 的 task 队列,并协助诊断 actor-isolated 代码等问题。

Instrument 里的代码查看更好显现包含了功用数据。Interleave 形式,能够一起查看源码和相关的反汇编。源码查看现在会在源码和反汇编判断显现 CPU 计数器,PMC 事情和动态公式。

修正了许多 Swift 相关显现不友好的问题。

多端

官方比方 Configuring a multiplatform app 。一个示例了 NavigationSplitView、Layout、Chart 和 WeatherKit 的运用的官方比方 Food Truck: Building a SwiftUI multiplatform app

Session 笔记

www.wwdcnotes.com/notes/wwdc2…

下面是 App Intents、WidgetKit 相关内容,这些都归于 App Services,WWDC22 专门收拾了 App Service 专题 。新体系服务比方 Messages collaboration、网络、CloudKit 的 System Service 主题 。

Widget

iOS 16 和 WatchOS 9 能够运用同一套代码编写 widget。iOS 新增场景是锁屏和 Live Activities(晚些时候推出)。

运用 Smart Stack,让 widget 呈现到栈顶,能够运用 TimelineEntryRelevance 。

官方参阅:

  • WidgetKit 主题
  • WidgetKit Session

介绍怎样将 widgets 增加到 lock screen 的 session Complications and widgets: Reloaded 。对应的实例代码 Adding widgets to the Lock Screen and watch faces

App Intents

打通 App Shortcuts,从 Shortcuts 运用、Spotlight 和 Siri 运转你的 App 特定任务。

对应 Session

  • Dive into App Intents
  • Implement App Shortcuts with App Intents
  • Meet Focus filters
  • Design App Shortcuts

文档 App Intents

官方几篇 App Intents 文章:

  • Providing your app’s capabilities to system services
  • Integrating custom data types into your intents
  • App intents
  • Focus

关于 Shortcut 的运用少数派有篇很棒的文章 《iOS 方便指令搭配 Notion API,更快速地编辑内容》 。

WeatherKit

Apple 收购 Dark Sky 后带来了 WeatherKit 和 WeatherKit REST API。有着易用的 Swift 接口,还有配套的 REST API。WeatherKit 内置了 async/await 支撑。

WeatherKit 攻略
WeatherKit 文档

session Meet WeatherKit 。一个 Apple 供给的天气代码示例 Fetching weather forecasts with WeatherKit 。

HealthKit

供给了更具体的睡觉和锻炼数据。session 介绍 What’s new in HealthKit

Vision

更新介绍 session What’s new in Vision

VisionKit 现在有一个结合 AVCapture 和 Vision 的数据扫描仪进行实时捕捉。 session Capture machine-readable codes and text with VisionKit 。

Live Text 接口

视觉库的运用接口。能够从照片和暂停视频中获取文本。

官方参阅:

  • Add Live Text interaction to your app
  • Enabling Live Text interactions with images
  • Scanning data with the camera

ScreenCaptureKit

creenCaptureKit 结构能够给你的 macOS 程序增加对高功用屏幕录制的支撑。文档地址:ScreenCaptureKit

App Store

内购

能够将 App Store Connect 内购产品同步到 Xcode。

新测试功用,比方在沙盒和 Xcode 里请求测试告诉和测试其它运用内购买场景。

官方参阅:

  • WWDC22 的 App Store 发布和市场的专题
  • StoreKit2 主题
  • What’s new in StoreKit testing
  • What’s new with in-app purchase
  • Implement proactive in-app purchase restore
  • Explore in-app purchase integration and migration
  • Discover Benchmarks in App Analytics
  • What’s new with SKAdNetwork
  • App Store Server Notifications V2
  • App Store Server API
  • App Analytics
  • SKAdNetwork 主题 What’s new with SKAdNetwork
  • 主动更新订阅
  • 办理主动续期订阅的定价

这儿有个 Kevin 开源的微信付出 SDK wechatpay-swift

全球化

session Build global apps: Localization by example

request review

你能够用 requestReview 这个 environment 键提示用户对你的 App 进行谈论。示例代码如下:

struct PRequestReview: View {
    @Environment(\.requestReview) var rr
    var body: some View {
        Button("来谈论吧") {
            rr()
        }
    }
}

Apple 的最佳实践比方 Requesting App Store Reviews 。

参阅

  • What’s new in App Store Connect
  • StoreKit 文档 运用内购和 App Store 互动
  • App Store Server API 办理 App Store 交易
  • App Store Server Notifications 实时监控运用内购事情
  • Notary API 对 macOS 软件进行公证

审阅

这次审阅,规矩 4.2.3 中取消二进制要有发动时满足的内容,这或许是因为 Background Assets 的推出能够让用户更快更聪明的下载。别的 5.3.3 放宽了彩排等约束。

功用

Apple 除了做编译优化体积外,还供给了一个 Background Assets 在运用装置后、运用更新时以及运用保留在设备上时定时在后台下载资源,看起来相似 ODR。Background Assets 的 session Meet Background Assets 。

官方参阅:

  • Link fast: Improve build and launch times
  • MetricKit
  • MXMetricManager 办理自界说目标
  • MXAppLaunchDiagnostic 发动诊断
  • MXAppLaunchMetric 发动相关目标
  • Improve app size and runtime performance
  • Track down hangs with Xcode and on-device detection
  • Power down: Improve battery consumption

硬件和虚机

官方参阅:

  • Virtualization 文档 创立虚拟机并运转依据 macOS 和 Linux 的操作体系
  • DriverKit 文档 开发在用户空间运转的设备驱动程序
  • SCSIPeripheralsDriverKit
  • DeviceDiscoveryExtension
  • Running GUI Linux in a virtual machine on a Mac (示例代码)

session 有:

  • Bring your driver to iPad with DriverKit
  • Create macOS or Linux virtual machines

网络

session Reduce networking delays for a more responsive app 和 Build device-to-device interactions with Network Framework

Metal 3

运用多核优势,高分辨率图形烘托更快,资源加载更快。运用 GPU 训练机器学习网络。WWDC22 期间社区有个给布景增加雨水效果有些流行,作者放出了代码,介绍了怎么将 Metal 引进 SwiftUI 作业流,Atmos 。

官方参阅:

  • Metal 主题
  • Metal Session

RoomPlan

ARKit 支撑的新 Swift 接口。运用摄像头和 LiDAR 创立 3D 平面图。别的还有一个视觉库的代码比方很有趣,便是从视频中检测人物行为,Detecting Human Actions in a Live Video Feed 。

官方参阅:

  • RoomPlan 主题
  • RoomPlan 文档

session Create parametric 3D room scans with RoomPlan 。官方示例代码 Create a 3D model of an interior room by guiding the user through an AR experience

Passkeys

身份验证,运用行业规范。

官方参阅:

  • Passkeys 主题
  • Meet passkeys

交互规划

Apple 的人机界面交互攻略 Human Interface Guidelines 。内容超级具体,触及程序界面方方面面。

官方参阅:

  • Human Interface Guidelines > What’s New 内有图标模板等,各类 Session 汇总

材料

  • WWDC22 Sample Code
  • iOS 和 iPadOS 16 Beta Release Note
  • macOS 13 Ventura Beta Release Notes
  • WWDC22 按主题分类
  • Public Apple Frameworks 查看 Apple 结构在不同渠道可用性的汇总