文档【免费下载链接】swift-evolutionThis maintains proposals for changes and user-visible enhancements to the Swift Programming Language.项目地址https://gitcode.com/gh_mirrors/sw/swift-evolution点击查看免费下载SE-0463Import Objective-C completion handler parameters asSendable为 Swift 与 Objective-C 的并发互操作带来一项关键默认值改进从 Swift 6.2 开始导入的 Objective-C 方法若满足特定条件其 completion handler完成处理器闭包参数将自动以Sendable导入从而让调用方在 actor 隔离边界上传入闭包时获得静态与动态的数据竞争安全保证。本文以该提案为主体结合 SE-0297 的 async 互操作规则、SE-0423 的动态 actor 隔离机制以及 approachable-concurrency 愿景文档 中的迁移路径深入讲解它的动机、设计规则、豁免情形、退出机制与兼容性考量。读完本文你将理解为何缺失Sendable会导致运行时崩溃、SE-0463 如何在导入层面自动修复这一问题以及如何在 Clang 头文件中用nonSendable显式退出该默认行为。背景Sendable缺失如何演化成运行时崩溃Swift 的数据竞争安全模型要求函数声明在签名中明确编码其并发不变量。Sendable注解表示闭包参数在调用之前会被传递到一个隔离边界之外——也就是说闭包可能在不同隔离域如某个 actor 的执行器中被调用因此闭包内部不能捕获或访问非Sendable的可变共享状态。当一个库的函数签名缺少Sendable注解时影响会传导到所有调用它的客户端调用方可能无意中引入数据竞争调用方无法从签名得知闭包会被投递到其他隔离域执行于是可能在闭包内捕获并修改 actor 隔离状态造成数据竞争。触发 SE-0423 的运行时断言SE-0423 为从非严格并发上下文调用、且传入非Sendable闭包参数的函数注入了动态 actor 隔离断言。当任何代码在 actor 隔离上下文中调用这类 API 时缺失Sendable注解可能导致运行时崩溃而不是编译期诊断。SE-0463 提案原文特别强调这对于正在迁移到 Swift 6 语言模式的项目极其痛苦——迁移方客户端已经开启了严格并发检查而被调用的 Objective-C 框架或尚未适配的库却没有补齐注解结果错误地在运行时以崩溃形式暴露。approachable-concurrency 愿景文档的 Mitigating runtime assertions due to isolation mismatches 一节也把自动将异步函数 completion handler 导入为Sendable列为缓解 SE-0423 运行时断言的明确路径之一见 visions/approachable-concurrency.md。好消息是有一大类带闭包参数的 API 即使缺少注解也能被自动识别为Sendable函数带 completion handler 参数的 Objective-C 方法。对于这类方法Sendable几乎总是正确的默认值。方案概览导入时自动补上SendableSE-0463 的核心提议非常直接自动将来自 Objective-C 方法的 completion handler 参数导入为Sendable函数无需修改任何 Objective-C 头文件。这本质上是 Clang 导入规则Clang importer的一项改动编译器在把 Objective-C 声明翻译为 Swift 时对识别出的 completion handler 参数自动附加Sendable。开发者无需逐个头文件审计并手动标注这正是社区在 Clang sendability 审计讨论 中一直寻求的自动化方案。详细设计触发条件与导入效果触发条件async 变体 nonisolated并非所有带 completion handler 的 Objective-C 方法都会被导入为Sendable。SE-0463 设定的触发条件是导入的方法存在 async 变体——即该方法满足 SE-0297 中异步 completion-handler 方法的识别规则见下节回顾该方法隐式或显式地是nonisolated。满足这两个条件时原始方法将带着Sendable注解的 completion handler 参数被导入。SE-0297 的 async 变体识别规则回顾要理解存在 async 变体的判断标准需要回顾 SE-0297 的 heuristics。一个 Objective-C 方法被视为潜在的异步 completion-handler 方法需要满足方法本身返回void所有结果通过 block 交付completion handler 是返回void的 block且在所有执行路径上恰好被调用一次若方法可能报错block 中应有一个非_Nonnull的NSError *参数。当方法未显式使用swift_async属性标注时编译器通过以下命名规则推断 completion handler若方法只有单一参数且第一个 selector 片段以WithCompletion、WithCompletionHandler、WithCompletionBlock、WithReplyTo、WithReply之一结尾则该参数即 completion handler匹配短语会从导入的 Swift 函数名中移除若方法有多个参数且最后一个参数的 selector 片段或参数名为completion、withCompletion、completionHandler、withCompletionHandler、completionBlock、withCompletionBlock、replyTo、withReplyTo、reply或replyTo则最后一个参数是 completion handler若方法有多个参数且最后一个参数以上述后缀结尾后缀前的文本会追加到 Swift 函数基名中。此外SE-0297 还提供__attribute__((swift_async(...)))等 Clang 属性来显式控制转换none关闭转换、指定索引参数为 handler、控制throws与_Nullable_result语义等。SE-0463 正是在这些规则识别出的 completion handler 参数上追加Sendable。导入示例提案原文给出了如下 Objective-C 方法签名- (void)performOperation:(NSString * _Nonnull)operation completionHandler:(void (^ _Nullable)(NSString * _Nullable, NSError * _Nullable))completionHandler;Swift 将把它导入为带Sendable的版本preconcurrency func perform( operation: String, completionHandler: Sendable escaping ((String?, Error?) - Void)? )注意两个细节参数类型仍是可选闭包(…)?保留了 Objective-C 侧_Nullable的语义函数被标注为preconcurrency——这正是下面要展开的兼容性关键。从 actor 调用时的行为变化当从 Swift actor 调用perform方法时此前允许非Sendable闭包被隔离到其形成上下文的推断规则将不再适用。具体表现闭包会被推断为nonisolated若闭包内访问了 actor 区域中的可变状态编译器将产生警告。需要特别说明的是由于所有从 C/C/Objective-C 导入的 API 都自动带有preconcurrency语义SE-0337 明确规定Objective-C declarations are always imported as though they were annotated withpreconcurrency见 proposals/0337-support-incremental-migration-to-concurrency-checking.md数据竞争安全违规即使在 Swift 6 语言模式下也只会产生警告不会升级为错误。这保证了迁移期间代码仍然可以编译运行。例外全局 actor 隔离函数的 completion handler 不导入为SendableSE-0463 为隔离到全局 actorglobal actor的函数设置了一个重要豁免这类函数的 completion handler不会被导入为Sendable。理由非常务实主 actor 隔离的函数其 completion handler 总是在主 actor 上被调用是 Objective-C 中极其常见的模式。如果一律导入为Sendable当头文件中恰好缺少 completion handler 参数上的主 actor 标注时就会产生大量误报警告。该豁免不会引入任何新的动态断言因此不会带来新的运行时崩溃风险。这是提案在 pitch 讨论后修订加入的内容见提案末尾 Revisions 一节是权衡减少误报与保持安全后的折中。退出机制用nonSendable标注不需要Sendable的 handler如果某个 completion handler 在调用前不会跨越隔离边界例如保证在相同隔离域内同步调用可以在 Objective-C 头文件中用nonSendable属性显式退出 SE-0463 的默认导入行为__attribute__((swift_attr(nonSendable)))SE-0297 中定义的__attribute__((swift_attr(...)))是一个通用 Clang 属性允许直接在 Objective-C 声明上书写任意 Swift 属性例如全局 actor 标注MainActor。SE-0463 复用这一机制将nonSendable作为 Clang 头文件注解的专用形式。需要强调的是nonSendable只用于 Clang 头文件注解不用于 Swift 代码。Swift 侧抑制Sendable的机制是~Sendable泛型参数标记见 SE-0518二者面向的场景不同不要混淆。兼容性分析源兼容性Source compatibilitySE-0463 的兼容性设计高度依赖preconcurrency的降级机制源自 SE-0337在 Swift 6 之前的语言模式下使用最小并发检查minimal concurrency checking时本改动没有任何效果使用完整并发检查complete concurrency checking时即使在 Swift 6 语言模式下也只会引入警告根本原因从 C/C/Objective-C 导入的声明隐式带有preconcurrency它把所有数据竞争安全违规都降级为警告。因此存量代码不会因为升级语言模式而突然编译失败这为大型项目渐进迁移到 Swift 6 提供了缓冲。ABI 兼容性提案明确指出对现有 ABI 没有任何影响。Sendable是纯编译期注解不改变调用约定、不增加运行时元数据因此导入规则的改动完全不影响二进制兼容。备选方案为什么用Sendable而不是sendingSE-0463 在备选方案一节详细讨论了将 completion handler 导入为sending参数的替代路线并解释了为何最终选择Sendable实现历史与验证实验性的SendableCompletionHandlers实现自 2021 年起就存在经过了大量源兼容性测试Sendable也已被 Objective-C 框架显式采用多年编译器实现对Sendable不匹配的边界情况已经过充分打磨。sending成熟度不足sending仍是相对较新的参数属性生态采用度远不如Sendable并且与preconcurrency结合时不支持在 Swift 6 语言模式下降级诊断——这直接破坏了上文所述的兼容性缓冲。SE-0423 运行时断言的紧迫性动态 actor 隔离断言带来的崩溃痛苦足够严重值得先用Sendable保守地解决问题。提案同时预警将来若改为sending会引入源兼容性问题——协议要求以sendingcompletion handler 导入后用Sendablecompletion handler 实现该要求将变得非法类方法重写也存在同样问题。因此如果开发者想利用区域隔离region isolation的更强保证推荐路径是使用async/await现代化代码即调用 SE-0297 导入的 async 变体而不是依赖 completion handler 签名。与相关提案的协作关系提案角色SE-0297定义 completion handler 的识别规则与 async 变体导入SE-0463 的触发条件存在 async 变体以此为基础SE-0423对非Sendable闭包注入运行时断言SE-0463 的动机直接来自其崩溃风险且提供-disable-dynamic-actor-isolation作为应急开关SE-0337提供preconcurrency降级机制使 SE-0463 的所有诊断保持为警告approachable-concurrency 愿景将自动Sendablecompletion handler 列为缓解运行时断言、提升数据竞争安全可及性的官方路线SE-0518提供 Swift 侧~Sendable泛型标记与 Clang 侧的nonSendable注解形成互补从实现角度看SE-0463 是 Clang importer 层面的规则变更编译器在按 SE-0297 规则翻译 Objective-C 方法时对满足存在 async 变体且 nonisolated条件的方法的 completion handler 参数自动附加Sendable。它不要求修改任何头文件也不要求开发者书写新注解属于默认即安全的导入改进。实践要点总结升级到 Swift 6.2 后符合条件的 Objective-C completion handler 方法会自动以Sendable导入你无需改动任何代码即可获得更强的数据竞争检查从 actor 调用这类 API 时闭包被推断为nonisolated访问 actor 隔离状态会得到警告而非错误请据此修正闭包内对共享可变状态的访问若某个 handler 确实不跨越隔离边界在 Objective-C 头文件中用__attribute__((swift_attr(nonSendable)))标注即可退出默认行为全局 actor 隔离的 Objective-C 方法不受此规则影响其 completion handler 仍按原有方式导入不会产生新的误报或动态断言追求更强区域隔离保证时优先将代码现代化为async/await形态SE-0297 导入的 async 变体而非依赖 completion handler 签名层面的sending。赞分享文档【免费下载链接】swift-evolutionThis maintains proposals for changes and user-visible enhancements to the Swift Programming Language.项目地址https://gitcode.com/gh_mirrors/sw/swift-evolution点击查看免费下载相关推荐Midscene.js 接入 Playwright3 步搞定视觉化端到端测试Midscene.js 接入 Playwright3 步搞定视觉化端到端测试 副标题别再追着选择器改了——用自然语言描述操作让多模态模型完成定位与点击。文档Swift 3 桥接机制核心提案 SE-0116将 Objective-C id 导入为 Swift Any 类型Swift 3 桥接机制核心提案 SE 0116将 Objective C id 导入为 Swift Any 类型 SE 0116Import Objec文档10个Tullio.jl实用案例从矩阵乘法到高级张量收缩10个Tullio.jl实用案例从矩阵乘法到高级张量收缩 Tullio.jl 是 Julia 生态中最灵活的张量收缩Tensor Contraction与文档创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考