     /// of assets that are required for later use in an app. This code will not try and update any UI
     /// with the results of the process.
     public func start() {
-        guard !stopped else {
-            assertionFailure("You can not restart the same prefetcher. Try to create a new prefetcher.")
-            handleComplete()
-            return
-        }
-
-        guard maxConcurrentDownloads > 0 else {
-            assertionFailure("There should be concurrent downloads value should be at least 1.")
-            handleComplete()
-            return
-        }
-
-        // Empty case.
-        guard prefetchSources.count > 0 else {
-            handleComplete()
-            return
-        }
-
-        let initialConcurrentDownloads = min(prefetchSources.count, maxConcurrentDownloads)
-        for _ in 0 ..< initialConcurrentDownloads {
-            if let resource = self.pendingSources.popFirst() {
-                self.startPrefetching(resource)
+        pretchQueue.async {
+            guard !self.stopped else {
+                assertionFailure("You can not restart the same prefetcher. Try to create a new prefetcher.")
+                self.handleComplete()
+                return
+            }
+
+            guard self.maxConcurrentDownloads > 0 else {
+                assertionFailure("There should be concurrent downloads value should be at least 1.")
+                self.handleComplete()
+                return
+            }
+
+            // Empty case.
+            guard self.prefetchSources.count > 0 else {
+                self.handleComplete()
+                return
+            }
+
+            let initialConcurrentDownloads = min(self.prefetchSources.count, self.maxConcurrentDownloads)
+            for _ in 0 ..< initialConcurrentDownloads {
+                if let resource = self.pendingSources.popFirst() {
+                    self.startPrefetching(resource)
+                }
             }
         }
     }
 
     /// Stops current downloading progress, and cancel any future prefetching activity that might be occuring.
     public func stop() {
-        if finished { return }
-        stopped = true
-        tasks.values.forEach { $0.cancel() }
-    }
-    
-    func downloadAndCache(_ source: Source) {
+        pretchQueue.async {
+            if self.finished { return }
+            self.stopped = true
+            self.tasks.values.forEach { $0.cancel() }
+        }
+    }
+    
+    private func downloadAndCache(_ source: Source) {
 
         let downloadTaskCompletionHandler: ((Result<RetrieveImageResult, KingfisherError>) -> Void) = { result in
             self.tasks.removeValue(forKey: source.cacheKey)

        }
    }
    
    func reportProgress() {
        progressSourceBlock?(skippedSources, failedSources, completedSources)
        progressBlock?(
            skippedSources.compactMap { $0.asResource },
            failedSources.compactMap { $0.asResource },
            completedSources.compactMap { $0.asResource }
        )
    }
    
    func reportCompletionOrStartNext() {
        CallbackQueue.mainAsync.execute {
            if let resource = self.pendingSources.popFirst() {
                self.startPrefetching(resource)
            } else {
                guard self.tasks.isEmpty else { return }
                self.handleComplete()
            }
        }
    }
    
    func handleComplete() {
        // The completion handler should be called on the main thread
        CallbackQueue.mainCurrentOrAsync.execute {
            self.completionSourceHandler?(self.skippedSources, self.failedSources, self.completedSources)

        // We want all callbacks from our prefetch queue, so we should ignore the callback queue in options.
        // Add our own callback dispatch queue to make sure all internal callbacks are
        // coming back in our expected queue.
        options.callbackQueue = .dispatch(pretchQueue)
        optionsInfo = options

        let cache = optionsInfo.targetCache ?? .default
