Apple Swift 團隊在 WWDC26 實驗室裡說了什麼
Apple 把 WWDC26 的 Swift Group Lab 發布為一小時未經劇本的問答,由來自 Swift、Foundation 與伺服器網路團隊的四位工程師參與,然後在沒有字幕的情況下推出。1 我們把這段影片送進本機的轉錄流程,看看他們究竟說了什麼。經過打磨的議程只告訴你某項功能能做什麼,而實驗室才是 Holly 坦承自己在一項核心並行處理決策上判斷錯誤的地方、是 Corey 解釋在已取消程式碼中會悄然失效的清理模式的地方,也是整個小組不斷重複那句行銷永遠不會說的建議的地方:別再蒐集語言功能了。坦率的版本就在這裡。
關於出處的說明:Apple 並未為這場實驗室發布官方逐字稿。下文每一段引述都是根據已發布影片的本機轉錄所做的轉述,附上大致的時間戳記。發言者依逐字稿所示,以名字與所屬團隊標註:Holly(Swift 語言團隊,泛型與並行處理)、Corey(Swift 伺服器網路團隊)、Tony(Foundation 與標準函式庫)以及 Doug(Swift 語言團隊)。1
TL;DR
- Holly 表示,若團隊今天重新設計 Swift 並行處理,nonisolated async 函式從第一天起就會在呼叫端的脈絡中執行。她「很長一段時間」抱持相反的信念,後來因現實世界的證據而改變想法。Swift 6.2 已將呼叫端脈絡這個預設行為定為標準。1
- 反覆出現的指引:刻意把型別設為非
Sendable。~Sendable(SE-0518,已在 Swift 6.4 中實作)提供了更乾淨的寫法,而 Foundation 正在重新標註那些它先前標為禁止的型別,其中 UserDefaults 的全域實例將取得 Sendable 一致性。21 - Corey 的非同步清理模式:已取消的脈絡會悄然跳過非同步清理,因此請檢視每一個
async defer,找出會掛起的await呼叫,並用 cancellation shield 將它們包起來。SE-0493(asyncdefer)與 SE-0504(withTaskCancellationShield)都會在 Swift 6.4 登場。34 - 對技術藍圖的坦白:
Disconnected型別仍是論壇上的活躍提案,tuple 一致性「快完成了」但形式上又退回修訂階段,UniqueArray原則上已獲接受,Subprocess 1.0 即將釋出,而 SwiftPM 正統一改用 Swift Build。5678 - 小組反覆出現的主題:「語言功能不是收藏品。」先做剖析,採用 profiler 指向的那個窄用途工具,其餘的就別去碰。1
Apple 今天會做出不同決定的並行處理抉擇
Holly 的並行處理回顧大約從 33:42 開始。整場實驗室沒有官方字幕;以下逐字稿來自本機 ASR。
一位開發者向小組提出了一個經過打磨的議程很少邀請的問題:既然 Swift 6 並行處理已在實際環境中運行夠久、足以觀察採用情況,團隊今天有沒有什麼會想用不同方式去設計?Holly 毫不含糊地回答:當然有。
具體的遺憾在於 nonisolated async 函式究竟在哪裡執行。兩項 Swift Evolution 提案把這個行為推往相反的方向。第一項讓 nonisolated async 函式一律跳轉到全域並行執行緒池;後來那項在 Swift 6.2 中,讓它們留在呼叫它們的脈絡上,因此從 main actor 呼叫的函式就會留在 main actor。1 Holly 把這次反轉歸因於那些在真實 App 與函式庫中執行早期並行處理檢查旗標的人所提供的證據:他們在 actor 隔離脈絡與這些 nonisolated async 函式之間來回傳遞非 Sendable 型別,而全域池這個預設行為產生了資料競爭錯誤,因為原本的 actor 在 async 函式於他處執行時仍持有那些值。1
接著是任何議程錄影中都不會出現的那一段。「我很長一段時間都抱持這個信念,認為在全域並行執行緒池上執行才是著眼長期效益的正確模型,」Holly 說,「但隨著時間推移,現實世界專案中的問題說服了我」(ASR 轉述,約 35:50)。1 Doug 把最初的決定詮釋為對整體系統合理的押注:可用的並行處理越多,潛在的平行性就越多,這可能意味著更好的效能。代價只有在人們動用完整的安全模型後才浮現,而它把太多型別往 Sendable 推,Doug 稱這「並非表達所有這些概念的自然方式」。1 呼叫端脈絡這個預設行為更平易近人,因為在你明確選擇平行性之前,它的行為就跟非並行程式碼一樣。如果你採用了 Swift 6.2,並好奇為什麼並行處理的整體感受突然變得平靜許多,答案就是:設計它的人承認最初的預設是錯的,並推出了修正。
刻意把你的型別設為非 Sendable
實驗室裡最反直覺的建議,與兩年來的遷移習慣背道而馳。Holly 說她不斷遇到開發者問如何讓自己的型別變成 Sendable,而更好的問題往往是反過來的:這個型別是否應該是非 Sendable?1 對於在單一計算內使用的短暫型別,明確標記為非 Sendable 會產生更乾淨的資料模型,也在「你打算跨隔離邊界傳遞的東西」與「你不打算傳遞的東西」之間劃出更清晰的界線。這也有助於效能,因為傳遞型別的成本,正是你想在那些根本不需要移動的中間值上避免支付的。1
Swift 6.4 為這個意圖提供了真正的寫法。~Sendable(SE-0518)讓你直接抑制這項一致性,就像 ~Copyable 抑制可複製性一樣,而不必撰寫一個 unavailable 一致性。2 Holly 把這個區別講得很精準:unavailable 的 Sendable 一致性宣告該型別及其每一個子類別都絕對不可傳送,並把這點向整個階層往下傳播;而 ~Sendable 只是缺少一致性而已,因此一個沒有新增可變狀態的子類別,仍然可以加上自己的 Sendable 一致性。21
這份彈性正是 Foundation 所需要的。Tony 解釋了 Foundation 最初 Sendable 稽核中的第三類:父類別安全、但子類別可能不安全的類別。他舉的例子是 NSString,它不可變且可傳送,相對於 NSMutableString,後者是可變的子類別且不可傳送。1 Foundation 沒有倉促套上錯誤的標註,而是把這些模稜兩可的類別標為非 Sendable 並靜觀其變。Tony 在實驗室裡說,現在團隊正使用 Swift 6.4 的標註來準確地重新標註這些型別,而他預期全域的標準 UserDefaults 將取得 Sendable 一致性。1 請把 UserDefaults 的一致性與更廣泛的 Foundation 重新標註視為實驗室出處的說法:Tony 在問答中陳述了這兩點,而它們並非我能從已發布提案中獨立確認的功能。小組長久以來的警告在此同樣適用,這次出自 Tony:別為了強行進入 Swift 6 模式而動用 @unchecked Sendable,因為每一個 unchecked 標註都會捨棄編譯器原本能為你證明的安全性。1
非同步清理,做到它真的會執行
Corey 負責實驗室裡最實用的一項修正,而且這正是那種你會在不知不覺中發布出去的 bug。結構化並行處理的招牌優勢在於自動傳播取消:取消一個 task,所有為它服務而衍生出來的東西也會被取消,這正是 view 被關閉或用戶端斷線時你想要的結果。1 陷阱藏在清理裡。你可能有一個寫到一半的檔案需要刷新到已知良好的狀態,或是一筆需要回滾的資料庫交易,而這個清理本身就是非同步的。如 Corey 所說,大多數 Swift 程式碼在已取消的脈絡中拒絕執行,因為它假定自己應該盡快收尾,因此在已取消 task 內執行的非同步清理,可能會悄然無法完成它該做的事。1
解法是 cancellation shield,而它與 async defer 直接搭配。SE-0493 讓 defer 區塊得以包含 await 呼叫,將在 Swift 6.4 登場。3 SE-0504 新增 withTaskCancellationShield,同樣在 Swift 6.4,它會像未曾請求取消那樣執行一個區塊,好讓會掛起的清理得以完成。4 Corey 的稽核訣竅很具體:檢視每一個 async defer 區塊,自問裡頭的任何 await 是否真的會掛起。如果會,就把它包進 cancellation shield。1 他稱這兩者是「絕佳的搭檔」,也是「把資源漂亮收拾乾淨的一記真正出色的組合拳」。1 如 Corey 所言,非 Sendable 型別強化了同樣的紀律,因為一個無法跨越並行處理領域的值,會迫使你的非同步控制流保持線性、易於推理。1
Corey 對結構化並行處理更廣泛的建議為本節作結。要果斷地擁抱它,因為麻煩正來自那些逃生口。除非你是刻意把工作送往他處,否則「幾乎要不計一切代價」避開非結構化 task(Task.detached 或裸 Task),而且在主線流程中絕對不要用。把 task group 當作你的預設選擇,讓物件的生命週期貼合其語彙範圍,並撰寫線性的非同步程式碼:一份先 A、再 B、再 C 的步驟清單,只有在工作真正擴散時才在 task group 內部動用平行性。1
對技術藍圖的坦白
實驗室也是小組把已釋出功能與樂觀預期區分開來的地方,而當你在決定要在什麼之上去建構時,這道落差很重要。
如何儲存一個已轉移的非 Sendable 值,這個問題有個真正的答案正在路上。今天你用 sending 關鍵字進行轉移,而以區域為基礎的隔離讓編譯器得以證明原本的擁有者已釋放存取權;但如果你需要儲存這樣的值,就只有那些不安全的 opt-out 才行得通。1 Holly 指向 Disconnected,這是論壇上一個活躍的提案,提議一種能在儲存過程中保留轉移特性的型別,讓你可以先把一個值收起來、稍後再交出去。它正在設計與討論之中,尚未實作。51
Tuple 一致性是工程師樂觀與形式狀態之間最鮮明的例子。當被問到 tuple 要有條件地一致於 Equatable、Hashable 與 Comparable 還缺什麼時,Holly 解釋這是 parameter pack 的延伸:語言需要一套語法,用來為元素型別是 parameter pack 的 tuple 撰寫 extension,並以 where 子句要求每個元素都一致。1 她說有一個實驗性實作已存在於編譯器的程式碼庫中,而且「幾乎完全到位了」。1 形式上的紀錄則更為謹慎。SE-0283,也就是最初的 tuple 一致性提案,已被退回修訂,其 2020 年的實作也被還原;一般化的 parameter pack 做法如今只存在於一個實驗性的 TupleConformances 編譯器旗標之後。10 請把 Holly 的「快完成了」讀作一位工程師對實作的誠實判斷,而非一項已釋出的功能。
效能容器的進展更快。Tony 提到的 UniqueArray 出自 SE-0527(「RigidArray 與 UniqueArray」),現已原則上獲得接受,引入一個全新的標準函式庫 Containers 模組;它已以早期形式隨 swift-collections 1.3 釋出。7 Tony 把它定位為某種 Array 的升級選項——也就是那種寫時複製的 retain/release 流量會在 Instruments 追蹤中現形的 Array。1 Subprocess,這個 Tony 點名為自己最愛的跨平台開源 process API,今年將釋出 1.0 版;1.0 里程碑已宣布,而最新發布的標籤仍停在 0.5,因此它是即將釋出而非已釋出。61 在工具方面,Holly 描述了開發者也許不會注意到的 SwiftPM 變動:Xcode 的套件建置與開源工具鏈的建置現在共用同一套實作——Swift Build,它正逐步成為預設的建置系統後端(在 main 上已是預設,目標為 6.4)。81
最後,是 Holly 一開始就提到的遷移路徑:@diagnose,出自 SE-0522(「Source-Level Control Over Compiler Warnings」)的新屬性,已獲接受。9 它提供原始碼層級的警告控制,讓你能在某個區域抑制 deprecation 警告,或在最要緊的範圍內選擇啟用預設關閉的警告,例如 strict memory safety 或 strict concurrency,這使它成為分階段 Swift 6 遷移更細緻的工具。1
工程師指引,集結成冊
實驗室的價值在於那些累積起來、永遠塞不進一場議程時段的實務建議。重點如下,附上出處:
- 撰寫線性的非同步程式碼。 Corey:幾乎不計一切代價避開非結構化 task,讓每個 task 都是一份循序的步驟清單,只在工作真正擴散時才於 task group 內部引入平行性。1
- 一份 MainActor 遷移訣竅。 Holly:從葉節點型別開始,由內往外推進;或者對一個應該完全屬於 main actor 的模組開啟 main-actor-by-default,再把那些卸載出去的部分明確標註。把不觸碰任何可變狀態的方法標為
nonisolated,並把一個從未真正被改動的static var轉成let,好讓它得以保持 nonisolated。1 - 一致性的成本並不對等。 Doug:一個未使用的
Equatable或Hashable一致性會把它的 witness 程式碼留在二進位檔中,因為執行期的as?對 existential 的轉型有可能發現它,所以它會耗費程式碼大小;Sendable則是純粹的編譯期標記,沒有執行期表示,因此一個未使用的Sendable一致性是免費的。1 @inlinable加@inline(never)的組合。 Corey 最愛的技巧:@inlinable把函式主體跨越模組邊界暴露出來,解鎖泛型特化與 effects 傳播;而@inline(never)則讓一條冷僻、程式碼龐大的路徑(按位元組的後備複製)不被內聯,好讓熱路徑保持快速。他在「整個 Swift 網路程式碼組合裡用過這對組合三次」,用於不尋常的冷路徑效能問題。1- 最佳化最熱的路徑,而非整個專案。 Corey:「我們僅僅沿著最熱的路徑引入 span 和幾個 unique array,就獲得了極大的成功」,以一項小而有編譯器支援的變動,交付了幾乎全部的效能收益。讓這些新的效能型別保持隔離,這樣採用它們就永遠不會逼你做一次龐大的重構。1
- 別再蒐集功能了。 小組反覆出現的那句話,出自 Corey 引述的一位朋友:「語言功能不是收藏品。」用上全部功能並不會給你獎賞。先做剖析,伸手去拿 profiler 指向的那個窄用途工具(non-copyable 型別、
UniqueArray、Span),把其餘的時間花在修 bug 與做功能上。1
常見問題
Apple 真的把 WWDC26 的 Swift 實驗室在沒有字幕的情況下發布了嗎?
是的。Apple 在開發者網站上把 Swift Group Lab(議程 8001)以一段沒有官方逐字稿或字幕的影片形式發布。1 為了準確引述,我把錄影送進本機的轉錄流程,因此本文中每一段引述都是出自那份本機 ASR 的轉述,附上大致的時間戳記,並以名字與團隊標註。1
Swift 團隊說他們會把並行處理改成什麼樣子?
Holly 說,若 Apple 今天設計 Swift 並行處理,nonisolated async 函式從一開始就會在呼叫端的脈絡中執行,而非跳轉到全域並行執行緒池。她長期抱持全域池的信念,後來因現實世界的證據而改變想法,Swift 6.2 已把呼叫端脈絡的行為定為預設。1
我該讓 Swift 型別變成 Sendable 還是非 Sendable?
實驗室的建議是刻意把短暫的計算型別設為非 Sendable。Swift 6.4 為此新增了 ~Sendable 寫法(SE-0518),它有別於 unavailable 一致性,因為當子類別未新增可變狀態時,仍可加上 Sendable。2 Tony 說 Foundation 正用這項新功能重新標註其模稜兩可的類別,並預期全域的 UserDefaults 將取得 Sendable 一致性,兩者皆為實驗室出處的說法。1
當 task 被取消時,我該如何確保非同步清理會執行?
已取消的脈絡會使大多數 Swift 程式碼跳過會掛起的工作,因此非同步清理可能悄然失效。Corey 的模式是檢視每一個 async defer,找出真的會掛起的 await 呼叫,並把它們包進 cancellation shield。Async defer(SE-0493)與 withTaskCancellationShield(SE-0504)都會在 Swift 6.4 登場。341
Tuple 一致性會在 Swift 中釋出嗎?
還沒有。SE-0283 已被退回修訂,其原始實作也被還原;一般化的 parameter pack 做法只存在於一個實驗性的 TupleConformances 旗標之後。Holly 在實驗室裡說,編譯器中的一個實驗性實作「幾乎完全到位了」,這反映的是工程師的樂觀,而非一項已釋出的功能。1
實驗室是這些公告的坦率夥伴:想了解已釋出功能在脈絡中的樣貌,請閱讀 Swift 2026 有什麼新東西;想了解 Holly 所談呼叫端脈絡預設背後的遷移機制,請見 Swift 6.2 並行處理實戰。小組「先剖析、再採用窄用途工具」的哲學也延伸到了測試,詳見 Swift Testing 對決 XCTest。完整的 WWDC26 報導收錄於 Apple Ecosystem Series。
參考資料
-
Apple, WWDC 2026 session 8001, Swift Group Lab. Apple published no official transcript or captions for this lab; all quotes attributed to it are paraphrases from a local transcription of the published video, with approximate timestamps. Source for the concurrency retrospective (Holly, ~33:42), the make-types-non-Sendable guidance, the Foundation re-annotation and UserDefaults Sendable conformance (both lab-attributed to Tony), the async-cleanup and cancellation-shield pattern (Corey), the structured-concurrency and MainActor migration advice (Corey and Holly), the conformance-cost explanation (Doug), the
@inlinableplus@inline(never)combo and hottest-path performance guidance (Corey), theDisconnected, tuple-conformance,UniqueArray, Subprocess, SwiftPM, and@diagnoseremarks, and the “language features aren’t collectibles” theme. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
Apple / Swift Evolution, SE-0518,
~Sendablefor explicitly marking non-Sendabletypes. Status: Implemented (Swift 6.4). Source for suppressing theSendableconformance and the distinction from an unavailable conformance. ↩↩↩↩ -
Apple / Swift Evolution, SE-0493, Support
asynccalls indeferbodies. Status: Implemented (Swift 6.4). Source forawaitinsidedeferblocks. ↩↩↩ -
Apple / Swift Evolution, SE-0504, Task cancellation shields. Status: Implemented (Swift 6.4). Source for
withTaskCancellationShield. ↩↩↩ -
Swift Forums, Pitch:
Disconnectedtype for modeling disconnected values. Active forums pitch for safely storing transferred non-Sendablevalues; not implemented. ↩↩ -
Apple / Swift, Subprocess — cross-platform, open-source process API announced in 2025; version 1.0 announced as releasing this year, with the latest published tag at 0.5. Status per the lab and the project’s published releases. ↩↩
-
Apple / Swift Evolution, SE-0527, RigidArray and UniqueArray. Status: Accepted in Principle; introduces a new standard-library Containers module and ships in an early form in swift-collections 1.3. ↩↩
-
Swift Forums, SwiftPM development update: default build system change. Swift Build is becoming the default SwiftPM build-system backend (default on main, targeting 6.4). ↩↩
-
Apple / Swift Evolution, SE-0522, Source-Level Control Over Compiler Warnings. Status: Accepted. Source for the
@diagnoseattribute and region-scoped warning control. ↩ -
Apple / Swift Evolution, SE-0283, Tuples Conform to
Equatable,Comparable, andHashable. Status: Returned for revision; original implementation reverted. Source for the formal status of tuple conformances against the experimentalTupleConformancesflag. ↩
