SwiftUI解析BookmarkData编译失败及音频无限循环实现求助
问题解决方案
1. 解析书签的编译错误修复
报错Cannot pass immutable value as inout argument: literals are not mutable是因为bookmarkDataIsStale参数为inout类型,必须传入可变变量的引用,不能直接传字面量false。修改解析代码如下:
do { var isBookmarkStale = false // 传入可变变量的引用,替代字面量false musicUrl = try URL(resolvingBookmarkData: asana.musicBookmark, options: .withSecurityScope, relativeTo: nil, bookmarkDataIsStale: &isBookmarkStale) // 可选:如果书签过期,重新生成并保存 if isBookmarkStale, let validUrl = musicUrl { do { asana.musicBookmark = try validUrl.bookmarkData(options: .withSecurityScope) } catch { print("Failed to refresh bookmark: \(error)") } } // 启动安全域访问(必须步骤) guard musicUrl.startAccessingSecurityScopedResource() else { print("Failed to access security-scoped resource") return } defer { musicUrl.stopAccessingSecurityScopedResource() } musicSound = try AVAudioPlayer(contentsOf: musicUrl) musicSound?.numberOfLoops = -1 // 无限循环 musicSound?.play() } catch { print("Failed to play Music: \(error.localizedDescription).") }
2. iOS书签保存的权限问题
iOS中要生成跨启动有效的安全域书签,必须在调用bookmarkData()时指定.withSecurityScope选项,同时确保正确管理资源访问权限。修改保存代码:
.fileImporter(isPresented: $chooseMusic, allowedContentTypes: [.audio]) { result in switch result { case .success(let fileUrl): let hasAccess = fileUrl.startAccessingSecurityScopedResource() defer { if hasAccess { fileUrl.stopAccessingSecurityScopedResource() } } do { // 生成带安全域权限的书签 asana.musicBookmark = try fileUrl.bookmarkData( options: .withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil ) } catch { print("Failed to create bookmark: \(error)") } case .failure(let error): print("File importer failed: \(error)") } }
- 使用
defer确保stopAccessingSecurityScopedResource()一定会被调用,避免资源泄漏 - 将
allowedContentTypes改为.audio,更精准匹配音频文件 - 必须添加
.withSecurityScope选项,否则书签无法保留跨启动的访问权限
3. 音频无限循环与终止实现
- 无限循环:将
AVAudioPlayer的numberOfLoops设为-1(官方标准写法,比设大数更可靠) - 终止播放:在视图消失或用户点击停止按钮时,调用
stop()并释放播放器实例:
struct YourMusicView: View { @State private var musicSound: AVAudioPlayer? // 其他状态变量... var body: some View { VStack { Button("停止播放") { musicSound?.stop() musicSound = nil // 释放资源,彻底终止 } // 其他视图元素 } .onDisappear { // 视图离开时自动停止播放 musicSound?.stop() musicSound = nil } } }
内容的提问来源于stack exchange,提问作者Sphere
相关产品推荐
相关产品推荐

