                     DDLogError("Error moving cached file: \(error)")
                 }
                 moc.perform {
-                    self.removePermanentCacheTask(groupKey: groupKey, key: key, variant: variant)
                     guard let item = self.fetchOrCreateCacheItem(key: key, variant: variant, moc: moc), let group = self.fetchOrCreateCacheGroup(key: groupKey, moc: moc) else {
-                        failure(ImageControllerError.invalidImageCache)
+                        self.permanentCacheCompletionManager.complete(groupKey, identifier: identifier, enumerator: { (completion) in
+                            completion.failure(ImageControllerError.invalidImageCache)
+                        })
                         return
                     }
                     group.addToCacheItems(item)
                     self.save(moc: moc)
-                    success()
+                    self.permanentCacheCompletionManager.complete(groupKey, identifier: identifier, enumerator: { (completion) in
+                        completion.success()
+                    })
                 }
             })
             task.priority = priority
-            groupTasks[groupTaskKey] = task
-            self.permanentCacheTasks[groupKey] = groupTasks
+            self.permanentCacheCompletionManager.add(task, forGroup: groupKey, identifier: identifier)
             task.resume()
         }
     }


fileprivate class ImageControllerCompletionManager<T> {
    var completions: [String: [T]] = [:]
    var tasks: [String: URLSessionTask] = [:]
    let queue = DispatchQueue(label: "ImageControllerCompletionManager-" + UUID().uuidString)
    
    func add(_ completion: T, forKey key: String) -> Bool {
        return queue.sync {
            var completionsForKey = completions[key] ?? []
            let isFirst = completionsForKey.count == 0
            completionsForKey.append(completion)
            completions[key] = completionsForKey
            return isFirst
        }
    }
    
    func add(_ task: URLSessionTask, forKey key: String) {
        queue.sync {
            tasks[key] = task
        }
    }
    
    func cancel(_ key: String) {
        queue.async {
            guard let task = self.tasks[key] else {
                return
            }
            task.cancel()
        }
    }
    
    func complete(forKey key: String, enumerator: @escaping (T) -> Void) {
        queue.async {
            guard let completionsForKey = self.completions[key] else {
                return
            }
            for completion in completionsForKey {
                enumerator(completion)
            }
            self.completions.removeValue(forKey: key)
            self.tasks.removeValue(forKey: key)
        }
    }
}


        }
    }
    
    public func permanentlyCache(url: URL, groupKey: String, priority: Float = 0, failure: @escaping (Error) -> Void, success: @escaping () -> Void) {
        let key = self.cacheKeyForURL(url)
        let variant = self.variantForURL(url)
        let identifier = self.identifierForKey(key, variant: variant)
        let completion = ImageControllerPermanentCacheCompletion(success: success, failure: failure)
        guard permanentCacheCompletionManager.add(completion, forIdentifier: identifier) else {
            return
        }
        let moc = self.managedObjectContext
        moc.perform {
            if let item = self.fetchCacheItem(key: key, variant: variant, moc: moc) {
                if let group = self.fetchOrCreateCacheGroup(key: groupKey, moc: moc) {
                    group.addToCacheItems(item)
                }
                self.save(moc: moc)
                self.permanentCacheCompletionManager.complete(groupKey, identifier: identifier, enumerator: { (completion) in
                    completion.success()
                })
                return
            }
            let schemedURL = (url as NSURL).wmf_urlByPrependingSchemeIfSchemeless() as URL
            let task = self.session.downloadTask(with: schemedURL, completionHandler: { (fileURL, response, error) in
                guard let fileURL = fileURL, let response = response else {
                    let err = error ?? ImageControllerError.invalidResponse
                    self.permanentCacheCompletionManager.complete(groupKey, identifier: identifier, enumerator: { (completion) in
                        completion.failure(err)
                    })
                    return
                }
                let permanentCacheFileURL = self.permanentCacheFileURL(key: key, variant: variant)
