SwiftUI中自定义Transferable类型的ShareLink无法使用问题排查
问题描述
在SwiftUI中尝试使用ShareLink分享Core Data存储的音频文件时,初始化ShareLink出现编译错误:No exact matches in call to initializer。已让Recording实体遵循Transferable协议,但问题仍存在。
相关代码
Recording实体扩展代码
extension Recording { @nonobjc public class func fetchRequest() -> NSFetchRequest<Recording> { return NSFetchRequest<Recording>(entityName: "Recording") } @NSManaged public var date: Date @NSManaged public var id: UUID @NSManaged public var url: String @NSManaged public var title: String } extension Recording : Identifiable, Transferable { static var containerUrl = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) public static var transferRepresentation: some TransferRepresentation { FileRepresentation(exportedContentType: .audio) { audio in SentTransferredFile(URL(string: audio.url)!) } } }
视图代码
struct AudioPlayerView: View { @ObservedObject var recording: Recording var body: some View { NavigationStack { VStack(spacing: 20){ VStack { Text(recording.title) .font(.title) .bold() Text("\(recording.date, format: .dateTime)") .foregroundColor(.secondary) } } } .toolbar { ToolbarItem(placement: .navigationBarLeading) { ShareLink(item: recording) { // 编译错误行 Image(systemName: "square.and.arrow.up") } } } } }
解决方案
1. 让Recording遵循Sendable协议
ShareLink的item参数要求类型同时符合Transferable和Sendable,Core Data的NSManagedObject子类默认不遵循Sendable,需显式添加@unchecked Sendable(NSManagedObject本身并非线程安全,但在UI主线程使用场景下可安全使用)。
2. 修复Transferable实现的安全问题
原代码中URL(string: audio.url)!使用强制解包,若字符串无法转为URL会导致崩溃,需添加错误处理逻辑;同时建议指定具体的音频 contentType(如.audio.wav或.audio.mp3),提升兼容性。
修复后的Recording扩展代码
extension Recording : Identifiable, Transferable, @unchecked Sendable { static var containerUrl = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) public static var transferRepresentation: some TransferRepresentation { // 根据实际音频格式指定contentType,示例为wav FileRepresentation(exportedContentType: .audio.wav) { audio in guard let fileUrl = URL(string: audio.url) else { throw TransferError.invalidAudioURL } return SentTransferredFile(fileUrl) } } // 定义自定义错误类型 enum TransferError: Error { case invalidAudioURL } }
3. 验证ShareLink初始化
修改后ShareLink(item: recording)即可正常编译,因为Recording现在同时满足Transferable和Sendable协议要求。
内容的提问来源于stack exchange,提问作者LucasC
相关产品推荐
相关产品推荐

