Swift 6使用consuming关键字引发编译错误,求解决思路
Swift 6迁移中
consuming关键字引发编译崩溃的排查方案 问题背景
迁移代码至Swift 6时,在UNNotificationServiceExtension的异步任务代码中使用consuming关键字修饰参数,触发编译器崩溃,报错栈信息显示崩溃发生在MoveOnlyTypeEliminator处理阶段,涉及代码片段为异步下载图片后修改通知内容并调用回调。
编译错误栈信息
1. Apple Swift version 6.0.2 (swiftlang-6.0.2.1.2 clang-1600.0.26.4) 2. Compiling with the current language version 3. While evaluating request ExecuteSILPipelineRequest(Run pipelines { Mandatory Diagnostic Passes + Enabling Optimization Passes } on SIL for PushNotificationServiceExtension) 4. While running pass #615 SILFunctionTransform "MoveOnlyTypeEliminator" on SILFunction "@$s32PushNotificationServiceExtension0bC0C011setupCustomB4Task33_8D4DCFB31FB634FB0683A4519898C954LL8imageUrl18bestAttemptContent14contentHandlery10Foundation3URLV_So09UNMutablebR0CnySo014UNNotificationR0CcntFyyYaKcfU_". for expression at [/Users/home/project/iOS/PushNotificationServiceExtension/NotificationService.swift:73:10 - line:81:5] RangeText="{ let (location, _) = try await URLSession.shared.download(from: imageUrl) let desiredLocation = URL(fileURLWithPath: \"\(location.path)\(imageUrl.lastPathComponent)\") try FileManager.default.moveItem(at: location, to: desiredLocation) let attachment = try UNNotificationAttachment(identifier: imageUrl.absoluteString, url: desiredLocation, options: nil) bestAttemptContent.attachments = [attachment] contentHandler(bestAttemptContent) " Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it): 0 swift-frontend 0x00000001066c29ac llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 56 1 swift-frontend 0x00000001066c0c00 llvm::sys::RunSignalHandlers() + 112 2 swift-frontend 0x00000001066c2f78 SignalHandler(int) + 292 3 libsystem_platform.dylib 0x000000018a946584 _sigtramp + 56 4 swift-frontend 0x0000000101ea251c swift::SILInstructionVisitor<(anonymous namespace)::SILMoveOnlyWrappedTypeEliminatorVisitor, bool>::visitAllocPackInst(swift::AllocPackInst*) + 40 5 swift-frontend 0x0000000101ea1b8c (anonymous namespace)::SILMoveOnlyWrappedTypeEliminatorPass::run() + 5144 6 swift-frontend 0x0000000101eae988 swift::SILPassManager::runFunctionPasses(unsigned int, unsigned int) + 3448 7 swift-frontend 0x0000000101eaaf6c swift::SILPassManager::executePassPipelinePlan(swift::SILPipelinePlan const&) + 11968 8 swift-frontend 0x0000000101ee44b8 swift::SimpleRequest<swift::ExecuteSILPipelineRequest, std::__1::tuple<> (swift::SILPipelineExecutionDescriptor), (swift::RequestFlags)1>::evaluateRequest(swift::ExecuteSILPipelineRequest const&, swift::Evaluator&) + 56 9 swift-frontend 0x0000000101ec7e1c swift::ExecuteSILPipelineRequest::OutputType swift::Evaluator::getResultUncached<swift::ExecuteSILPipelineRequest, swift::ExecuteSILPipelineRequest::OutputType swift::evaluateOrFatal<swift::ExecuteSILPipelineRequest>(swift::Evaluator&, swift::ExecuteSILPipelineRequest)::'lambda'()>(swift::ExecuteSILPipelineRequest const&, swift::ExecuteSILPipelineRequest::OutputType swift::evaluateOrFatal<swift::ExecuteSILPipelineRequest>(swift::Evaluator&, swift::ExecuteSILPipelineRequest)::'lambda'()) + 412 10 swift-frontend 0x0000000101eca598 swift::runSILDiagnosticPasses(swift::SILModule&) + 612 11 swift-frontend 0x0000000101440fc4 swift::CompilerInstance::performSILProcessing(swift::SILModule*) + 84 12 swift-frontend 0x000000010106bcb0 performCompileStepsPostSILGen(swift::CompilerInstance&, std::__1::unique_ptr<swift::SILModule, std::__1::default_delete<swift::SILModule>>, llvm::PointerUnion<swift::ModuleDecl*, swift::SourceFile*>, swift::PrimarySpecificPaths const&, int&, swift::FrontendObserver*) + 1376 13 swift-frontend 0x000000010106aebc swift::performCompileStepsPostSema(swift::CompilerInstance&, int&, swift::FrontendObserver*) + 984 14 swift-frontend 0x000000010106e174 performCompile(swift::CompilerInstance&, int&, swift::FrontendObserver*) + 1684 15 swift-frontend 0x000000010106cea0 swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 3572 16 swift-frontend 0x0000000100ff3f64 swift::mainEntry(int, char const**) + 3680 17 dyld 0x000000018a58b154 start + 2476 Command SwiftCompile failed with a nonzero exit code
涉事代码
private func downloadImageTask( imageUrl: URL, bestAttemptContent: consuming UNMutableNotificationContent, contentHandler: consuming @escaping (UNNotificationContent) -> Void ) { self.setupImageTask = Task { let (location, _) = try await URLSession.shared.download(from: imageUrl) let desiredLocation = URL(fileURLWithPath: "\(location.path)\(imageUrl.lastPathComponent)") try FileManager.default.moveItem(at: location, to: desiredLocation) let attachment = try UNNotificationAttachment(identifier: imageUrl.absoluteString, url: desiredLocation, options: nil) bestAttemptContent.attachments = [attachment] contentHandler(bestAttemptContent) } }
解决思路
移除
consuming关键字,改用对象副本修改UNMutableNotificationContent和逃逸闭包并非Swift 6的可移动类型,添加consuming会导致编译器所有权跟踪逻辑冲突。去掉consuming后,创建通知内容的副本进行修改,避免原对象的生命周期问题:private func downloadImageTask( imageUrl: URL, bestAttemptContent: UNMutableNotificationContent, contentHandler: @escaping (UNNotificationContent) -> Void ) { self.setupImageTask = Task { let (location, _) = try await URLSession.shared.download(from: imageUrl) let desiredLocation = URL(fileURLWithPath: "\(location.path)\(imageUrl.lastPathComponent)") try FileManager.default.moveItem(at: location, to: desiredLocation) let attachment = try UNNotificationAttachment(identifier: imageUrl.absoluteString, url: desiredLocation, options: nil) // 创建副本修改后传递 let modifiedContent = bestAttemptContent.mutableCopy() as! UNMutableNotificationContent modifiedContent.attachments = [attachment] contentHandler(modifiedContent) } }升级Swift版本
Swift 6.0.2存在可移动类型处理的已知bug,升级到最新的Swift 6.x版本(如6.0.3及以上),新版本通常会修复这类SIL阶段的编译崩溃问题。避免异步Task捕获
consuming参数consuming要求参数所有权立即转移,但异步Task会延长参数生命周期,导致编译器无法正确处理所有权路径。若需所有权转移,应在进入Task前完成移交,或包装为可移动容器类型。临时关闭编译优化
作为临时解决方案,在Build Settings中将Optimization Level改为No Optimization,跳过触发崩溃的优化阶段,保证代码先能编译运行,后续再跟进版本修复。
内容的提问来源于stack exchange,提问作者Seto
相关产品推荐
相关产品推荐

