摆脱警告:在主要参与者隔离的上下文之外传递不可发送类型“AVAssetExportSession”的参数可能会引入数据竞争

问题描述 投票:0回答:1

如何摆脱此警告

await exportSession.export()
:

enter image description here

代码:

func extractAudioFromImportedVideo(videoURL: URL, success: @escaping ((URL) -> Void), failure: @escaping ((Error?) -> Void)) async {
        
        do {
            let asset = AVURLAsset(url: videoURL)
            let audioTracks = try await asset.loadTracks(withMediaType: .audio)
            
            guard !audioTracks.isEmpty else {
                failure(NSError(domain: "Audio Extraction Error", code: 0, userInfo: [NSLocalizedDescriptionKey: "Video does not contain audio"]))
                return
            }
            
            guard let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetAppleM4A) else {
                failure(NSError(domain: "Audio Extraction Error", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to create export session"]))
                return
            }
            
            guard let audioURL = makeFileOutputURL(fileName: "ExtractedAudio.m4a") else {
                failure(NSError(domain: "Audio Extraction Error", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to create output URL"]))
                return
            }
            
            print("audioTracks", audioTracks)
            exportSession.outputURL = audioURL
            exportSession.outputFileType = .m4a

            
            await exportSession.export()
            print("exportSession.status", exportSession.status.rawValue)
            if exportSession.status == .completed {
                // Audio extraction succeeded
                print("Audio extraction succeeded")
                success(audioURL)
            } else {
                // Audio extraction failed
                print("Audio extraction failed: \(exportSession.error?.localizedDescription ?? "")")
                failure(exportSession.error)
            }
        }
        catch {
            print("extractAudioFromImportedVideo Error:", error.localizedDescription)
        }
    }
swift uikit swift-concurrency
1个回答
0
投票

避免此错误的简单方法是使您的函数

nonisolated
:

nonisolated func extractAudioFromImportedVideo(videoURL: URL, success: @escaping ((URL) -> Void), failure: @escaping ((Error?) -> Void)) async {
    …
}

就我个人而言,我会消除这些关闭并遵循

async
模式:

nonisolated func extractAudioFromImportedVideo(videoURL: URL) async throws -> URL {
    do {
        let asset = AVURLAsset(url: videoURL)
        let audioTracks = try await asset.loadTracks(withMediaType: .audio)

        guard !audioTracks.isEmpty else {
            throw AudioExtractionError.noAudio
        }

        guard let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetAppleM4A) else {
            throw AudioExtractionError.exportFailed
        }

        guard let audioURL = makeFileOutputURL(fileName: "ExtractedAudio.m4a") else {
            throw AudioExtractionError.outputUrlFailed
        }

        print("audioTracks", audioTracks)
        exportSession.outputURL = audioURL
        exportSession.outputFileType = .m4a


        await exportSession.export()
        print("exportSession.status", exportSession.status.rawValue)
        if let error = exportSession.error {
            throw error
        }

        print("Audio extraction succeeded")
        return audioURL
    } catch {
        print("extractAudioFromImportedVideo Error:", error.localizedDescription)
        throw error
    }
}

注意,我也退休了

NSError
,替换为:

enum AudioExtractionError: LocalizedError {
    case noAudio
    case exportFailed
    case outputUrlFailed

    nonisolated var errorDescription: String? {
        return switch self {
        case .noAudio: NSLocalizedString("Video does not contain audio", comment: "AudioExtractionError")
        case .exportFailed: NSLocalizedString("Failed to create export session", comment: "AudioExtractionError")
        case .outputUrlFailed: NSLocalizedString("Failed to create output URL", comment: "AudioExtractionError")
        }
    }
}

这实际上是本地化的,将细节与该函数隔离,并且枚举错误支持更丰富的错误处理。


FWIW,一旦你完成了这项工作,你就可以消除很多麻烦,进一步简化:

nonisolated func extractAudioFromImportedVideo(videoURL: URL) async throws -> URL {
    let asset = AVURLAsset(url: videoURL)
    let audioTracks = try await asset.loadTracks(withMediaType: .audio)

    guard !audioTracks.isEmpty else {
        throw AudioExtractionError.noAudio
    }

    guard let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetAppleM4A) else {
        throw AudioExtractionError.exportFailed
    }

    guard let audioURL = makeFileOutputURL(fileName: "ExtractedAudio.m4a") else {
        throw AudioExtractionError.outputUrlFailed
    }

    exportSession.outputURL = audioURL
    exportSession.outputFileType = .m4a

    await exportSession.export()
    if let error = exportSession.error {
        throw error
    }

    return audioURL
}
© www.soinside.com 2019 - 2024. All rights reserved.