Skip to content

Commit 6572e43

Browse files
committed
fix(iOS): use per-call ReferencedAssetLoader to prevent concurrent access crash
The shared ReferencedAssetLoader on HybridRiveFileFactory caused a data race when multiple RiveFile loads ran concurrently. Concurrent GCD threads calling setFileRef() on the same instance wrote to activeFileRef without synchronization — a non-atomic property write that double-released the previous RiveFile, causing EXC_BAD_ACCESS crashes.
1 parent edbde13 commit 6572e43

1 file changed

Lines changed: 6 additions & 4 deletions

File tree

ios/HybridRiveFileFactory.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import NitroModules
22
import RiveRuntime
33

44
final class HybridRiveFileFactory: HybridRiveFileFactorySpec, @unchecked Sendable {
5-
let assetLoader = ReferencedAssetLoader()
65

76
/// Asynchronously creates a `HybridRiveFileSpec` by performing the following steps:
87
/// 1. Executes `check()` to validate or fetch initial data.
@@ -34,9 +33,10 @@ final class HybridRiveFileFactory: HybridRiveFileFactorySpec, @unchecked Sendabl
3433
DispatchQueue.global(qos: .userInitiated).async {
3534
do {
3635

36+
let assetLoader = ReferencedAssetLoader()
3737
let referencedAssetCache = SendableRef(ReferencedAssetCache())
3838
let factoryCache: SendableRef<RiveFactory?> = .init(nil)
39-
let customLoader = self.assetLoader.createCustomLoader(
39+
let customLoader = assetLoader.createCustomLoader(
4040
referencedAssets: referencedAssets, cache: referencedAssetCache,
4141
factory: factoryCache
4242
)
@@ -47,11 +47,13 @@ final class HybridRiveFileFactory: HybridRiveFileFactorySpec, @unchecked Sendabl
4747
} else {
4848
try file(prepared)
4949
}
50-
self.assetLoader.setFileRef(riveFile)
50+
if customLoader != nil {
51+
assetLoader.setFileRef(riveFile)
52+
}
5153

5254
let result = (
5355
file: riveFile, cache: referencedAssetCache.value, factory: factoryCache.value,
54-
loader: customLoader != nil ? self.assetLoader : nil
56+
loader: customLoader != nil ? assetLoader : nil
5557
)
5658
DispatchQueue.main.async {
5759
continuation.resume(returning: result)

0 commit comments

Comments
 (0)