I have the following piece of code that works in Swift 5
func test() {
let url = Bundle.main.url(forResource: "movie", withExtension: "mov")
let videoAsset = AVURLAsset(url: url!)
let t1 = CMTime(value: 1, timescale: 1)
let t2 = CMTime(value: 4, timescale: 1)
let t3 = CMTime(value: 8, timescale: 1)
let timesArray = [
NSValue(time: t1),
NSValue(time: t2),
NSValue(time: t3)
]
let generator = AVAssetImageGenerator(asset: videoAsset)
generator.requestedTimeToleranceBefore = .zero
generator.requestedTimeToleranceAfter = .zero
generator.generateCGImagesAsynchronously(forTimes: timesArray ) { requestedTime, image, actualTime, result, error in
let img = UIImage(cgImage: image!)
}
}
When I compile and run it in Swift 6 it gives a
EXC_BREAKPOINT (code=1, subcode=0x1021c7478)
I understand that Swift 6 adopts strict concurrency. My question is if I start porting my code, what is the recommended way to change the above code?
Rgds, James
Thanks for the crash report. It confirms that my force unwrap guess from yesterday is wrong. Check out the crashing thread backtrace:
Thread 16 Crashed:: Dispatch queue: com.apple.coremedia.assetimagegenerator.notifications
0 libdispatch.dylib … _dispatch_assert_queue_fail + 116
1 libdispatch.dylib … dispatch_assert_queue + 188
2 libswift_Concurrency.dylib … swift_task_isCurrentExecutorImpl(swift::SerialExecutorRef) + 280
3 Migrate.debug.dylib … closure #1 in ContentView.test() + 256
4 Migrate.debug.dylib … thunk for @escaping @callee_guaranteed (@unowned CMTime, @guaranteed CGImageRef?…
5 AVFCore … -[AVAssetImageGenerator _didGenerateCGImage:] + 540
6 AVFCore … aig_didGenerateCGImage + 44
7 CoreFoundation … __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 120
Frame 7 shows that this code is running in response to a notification being posted. Notifications like this run synchronously. This is on thread 16, so the poster posted the notification on thread 16. Obvious that’s not the main thread (-:
Frames 6 and 5 are the AVFoundation code routing the callback to you. Frameworks 4 and 3 is code in your app, but probably not you code. Rather, it’s glue generated by the compiler. That’s calling down into the Swift runtime, frames 2 through 0, to check the current executor context. And that check has failed, resulting in the trap you’re seeing.
In short, it’s crashing before it runs any code in your completion handler.
What should you do about this? This isn’t really my area of expertise, but I’ll note that the docs for the method you’re using say:
Swift clients should prefer the asynchronous images(for:) method instead.
So, I’m thinking that the best path forward here is for you to follow that advice and adopt the images(for:)
method. I believe that’ll avoid this problem and yield nicer code!
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"