Skip to content

Commit f0661dd

Browse files
committed
fix(ios): decode images on main thread, keep file alive during decode
decodeImage runs through RenderContext which is not thread-safe and races with beginFrame/endFrame on the main thread. Move it to run synchronously within the existing MainActor context. For font/audio (thread-safe), keep background decode but capture self strongly so the ReferencedAssetLoader (and its activeFileRef) stays alive until the dispatch completes.
1 parent 526244c commit f0661dd

1 file changed

Lines changed: 17 additions & 17 deletions

File tree

ios/ReferencedAssetLoader.swift

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -43,36 +43,36 @@ final class ReferencedAssetLoader {
4343
completion()
4444
return
4545
}
46-
Self.decodeQueue.async {
47-
switch asset {
48-
case let imageAsset as RiveImageAsset:
49-
let decodedImage = factory.decodeImage(data)
50-
DispatchQueue.main.async {
51-
imageAsset.renderImage(decodedImage)
52-
completion()
53-
}
54-
case let fontAsset as RiveFontAsset:
46+
switch asset {
47+
case let imageAsset as RiveImageAsset:
48+
// decodeImage is not thread-safe — decode on main thread, synchronously
49+
// within the current MainActor context (caller is already on main).
50+
let decodedImage = factory.decodeImage(data)
51+
imageAsset.renderImage(decodedImage)
52+
completion()
53+
case let fontAsset as RiveFontAsset:
54+
Self.decodeQueue.async { [self] in
5555
let decodedFont = factory.decodeFont(data)
5656
DispatchQueue.main.async {
5757
fontAsset.font(decodedFont)
5858
completion()
59+
_ = self
5960
}
60-
case let audioAsset as RiveAudioAsset:
61+
}
62+
case let audioAsset as RiveAudioAsset:
63+
Self.decodeQueue.async { [self] in
6164
guard let decodedAudio = factory.decodeAudio(data) else {
62-
DispatchQueue.main.async {
63-
completion()
64-
}
65+
DispatchQueue.main.async { completion() }
6566
return
6667
}
6768
DispatchQueue.main.async {
6869
audioAsset.audio(decodedAudio)
6970
completion()
70-
}
71-
default:
72-
DispatchQueue.main.async {
73-
completion()
71+
_ = self
7472
}
7573
}
74+
default:
75+
completion()
7676
}
7777
}
7878

0 commit comments

Comments
 (0)