Skip to content

Commit 94a8929

Browse files
authored
425 bug turboimageprefetch hangs when called concurrently due to race condition with instance variable (#428)
* fix: prefetch hangs when called concurrently * refactor: remove dispose function * docs: update readme
1 parent 28111da commit 94a8929

3 files changed

Lines changed: 8 additions & 55 deletions

File tree

README.md

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Performant image component for React Native. Powered by [Nuke](https://github.co
2828

2929
## Benchmarks
3030

31-
>Disclaimer: Benchmark results are based on controlled testing environments and may vary in real-world applications depending on factors such as network conditions, device specifications, image sizes, and concurrent tasks.
31+
> Results may vary in real-world applications depending on factors such as network conditions, device specifications, image sizes, and concurrent tasks.
3232
3333
For example, loading 120 images in flatlist. See the code in the example folder:
3434

@@ -98,12 +98,6 @@ import TurboImage from 'react-native-turbo-image';
9898
await TurboImage.prefetch([Source]);
9999
```
100100

101-
### `dispose`
102-
103-
```ts
104-
await TurboImage.dispose([Source]);
105-
```
106-
107101
### `clearMemoryCache`
108102

109103
```ts

android/src/main/java/com/turboimage/TurboImageModule.kt

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -59,33 +59,6 @@ class TurboImageModule(private val context: ReactApplicationContext) :
5959
}
6060
}
6161

62-
@ReactMethod
63-
fun dispose(sources: ReadableArray, promise: Promise) {
64-
val imageRequests = sources.toArrayList().map { source ->
65-
val uri = (source as HashMap<*, *>)["uri"] as String
66-
val headers = source["headers"] as? HashMap<*, *>
67-
68-
if (headers != null) {
69-
val headersBuilder = Headers.Builder()
70-
headers.map { (key, value) ->
71-
headersBuilder.add(key as String, value as String)
72-
}
73-
ImageRequest.Builder(context)
74-
.headers(headersBuilder.build())
75-
.data(uri)
76-
.build()
77-
} else {
78-
ImageRequest.Builder(context)
79-
.data(uri)
80-
.build()
81-
}
82-
}
83-
imageRequests.forEach { imageRequest ->
84-
imageLoader?.enqueue(imageRequest)?.dispose()
85-
}
86-
promise.resolve("Success")
87-
}
88-
8962
@ReactMethod
9063
fun clearMemoryCache(promise: Promise) {
9164
Coil.imageLoader(context).memoryCache?.clear()

ios/TurboImageViewManager.swift

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import Nuke
33
@objc(TurboImageViewManager)
44
class TurboImageViewManager: RCTViewManager {
55

6-
private var prefetcher: ImagePrefetcher?
6+
private var prefetchers: [String: ImagePrefetcher] = [:]
77

88
override func view() -> (TurboImageView) {
99
return TurboImageView()
@@ -23,6 +23,7 @@ extension TurboImageViewManager {
2323
with cachePolicy: String,
2424
resolve: @escaping RCTPromiseResolveBlock,
2525
reject: @escaping RCTPromiseRejectBlock) {
26+
2627
let imageRequests: [ImageRequest] = sources.map {
2728
guard let uri = $0["uri"] as? String,
2829
let url = URL(string: uri)
@@ -34,37 +35,22 @@ extension TurboImageViewManager {
3435
}
3536
return ImageRequest(urlRequest: urlRequest)
3637
}.compactMap{ $0 }
38+
39+
let key = UUID().uuidString
40+
var prefetcher: ImagePrefetcher?
3741
if(cachePolicy == "dataCache") {
3842
prefetcher = ImagePrefetcher(pipeline: ImagePipeline(configuration: .withDataCache))
3943
} else {
4044
prefetcher = ImagePrefetcher()
4145
}
46+
prefetchers[key] = prefetcher
4247
prefetcher?.startPrefetching(with: imageRequests)
4348
prefetcher?.didComplete = {
4449
resolve(true)
50+
self.prefetchers[key] = nil
4551
}
4652
}
4753

48-
@objc
49-
func dispose(_ sources: [Source],
50-
resolve: @escaping RCTPromiseResolveBlock,
51-
reject: @escaping RCTPromiseRejectBlock) {
52-
let imageRequests: [ImageRequest] = sources.map {
53-
guard let uri = $0["uri"] as? String,
54-
let url = URL(string: uri)
55-
else { return nil }
56-
57-
var urlRequest = URLRequest(url: url)
58-
if let headers = $0["headers"] as? [String: String] {
59-
urlRequest.allHTTPHeaderFields = headers
60-
}
61-
return ImageRequest(urlRequest: urlRequest)
62-
}.compactMap{ $0 }
63-
64-
prefetcher?.stopPrefetching(with: imageRequests)
65-
resolve("Success")
66-
}
67-
6854
@objc
6955
func clearMemoryCache(_ resolve: @escaping RCTPromiseResolveBlock,
7056
reject: @escaping RCTPromiseRejectBlock) {

0 commit comments

Comments
 (0)