这个问题困扰着我。我想怀疑一个种族状况。但是我不能得出结论。
这是我的代码的简单版本:
override func viewDidLoad() {
private func downloadAssets(completion: @escaping () -> Void) {
getAssetsForCurrentUser {
let images = Image.all()
for image in images {
// uiImage here sometimes is nil
// and it causes a crash because I am not handling `nil`.
// and restarting the app would fix itself
// but reading my code over and over again still brought
// me to the conclusion that I am strictly reading the
// content of the file after it completed the download.
// So why would I be getting `nil` here?
let uiImage = UIImage(contentOf: image.localPath)
}
}
}
private func getAssetsForCurrentUser(inProgress: @escaping (Float) -> Void, completion: @escaping () -> Void) {
let assetsManager = AssetsManager()
assetsManager.getAssetsForCurrentUser(inProgress: { progressPercentage in
inProgress(Float(progressPercentage))
}, completion: {
completion()
}, onError: { errMsg in
print(errMsg)
})
}
}
class AssetManager {
func getAssetsForCurrentUser(inProgress: @escaping (_ progressPercentage: Float) -> Void,
completion: @escaping () -> Void,
onError: @escaping (_ errMsg: String) -> Void) {
API().getAssetsForUserWithId(userId, completion: { imagesAssetUrlStrings in
self.downloadAssetsFromImagesAssetUrlStrings(imagesAssetUrlStrings, inProgress: { _ in
inProgress(self.progressPercentage)
}, completion: completion)
}, onError: { error in
onError("error when getting alubms for current user \(error)")
})
}
private func downloadAssetsFromImagesAssetUrlStrings(_ imagesAssetUrlStrings: AlbumsAPI.AlbumDataType, inProgress: @escaping (_ progressPercentage: Float) -> Void, completion: @escaping () -> Void) {
if imagesAssetUrlStrings.count == 0 {
print("no image")
completion()
}
totalTaskCount = imagesAssetUrlStrings.count
for image in imagesAssetUrlStrings {
let imageDownloadTask = FileDownloader().downloadFile(.Image, from: imageRemoteUrlString, as: imageFileName, completion: { _ in
print("Image download success from \(imageRemoteUrlString)")
self.markTaskAsCompleted()
if self.isAllTaskDone {
completion()
}
})
imageDownloadTask.observe(.progress) { snapshot in
let completedUnitCount = snapshot.progress?.completedUnitCount ?? 0
let totalUnitCount = snapshot.progress?.totalUnitCount ?? 0
let taskId = imageDownloadTask.id
inProgress(self.progressPercentage)
self.recordProgress(taskId: taskId, completedUnitCount: completedUnitCount, totalUnitCount: totalUnitCount)
}
}
}
}
class FileDownloader {
func downloadFile(_ fileType: FileType, from urlString: String, as fileName: String, completion: @escaping (String?) -> Void) -> DownloadTask {
let filePath = LocalStorage.documentPath(of: fileType).appendingPathComponent(fileName)
if !LocalStorage.fileExists(of: fileType, fileName: fileName) {
print("file not found at \(filePath)")
let storage = Storage.storage()
let storageRef = storage.reference(forURL: urlString)
let downloadTask = storageRef.write(toFile: filePath) { (localUrl, error) in
if let err = error {
Rollbar.error(
withMessage: "Error writing file",
data: [
"error": err,
"localUrl": localUrl,
"fileName": fileName
]
)
print("Error writing file: \(err)")
} else {
print("file saved at \(filePath.path)")
completion(filePath.relativePath)
}
}
return downloadTask
} else {
print("file found at \(filePath)")
completion(filePath.relativePath)
return DownloadTask(firebaseDownloadTask: nil)
}
}
}