是否有任何怪癖或問題與火力地堡存儲?需要解決的某種 緩存?
UploadTask
執行asynchronously
。如果我在上傳圖像後立即嘗試下載圖像,我可以重現您的錯誤。發生什麼情況是下載代碼在圖像完成上傳之前執行,產生圖像不存在的錯誤。你可以看到,在下載代碼執行在回調打印出一些消息太早:
let storage = FIRStorage.storage()
let storageRef = storage.reference() //You don't need to explicitly write the url in your code.
//The config file GoogleService-Info.plist will handle that.
let imageRef = storageRef.child("images/align_menu.tiff")
let localURL = NSBundle.mainBundle().URLForResource(
"align_menu",
withExtension: "tiff"
)!
//Upload the image:
let uploadTask = imageRef.putFile(localURL, metadata: nil) { (metadata, error) -> Void in
if let returnedError = error {
// Uh-oh, an error occurred!
print("[My Upload Error]: \(returnedError)")
} else {
// Metadata contains file metadata such as size, content-type, and download URL.
print("[My Upload Success]:")
let downloadURL = metadata!.downloadURL()!
print("[URL for download]: \(downloadURL)")
}
}
//Download the image:
imageRef.dataWithMaxSize(1 * 1024 * 1024) { (data, error) -> Void in
if let returnedError = error {
// Uh-oh, an error occurred!
print("[My Download Error]: \(returnedError)")
}
else {
print("[My Download Success]:")
if let validImage = UIImage(data: data!) {
NSOperationQueue.mainQueue().addOperationWithBlock() {
self.imageView.image = validImage
}
}
}
}
該代碼產生輸出:
[My Download Error]: ...."Object images/align_menu.tiff does not exist."...
,然後在幾秒鐘後我看到的輸出:
[My Upload Success]:
[URL for download]: ...
它演示了下載回調在上傳回調之前執行。我無法弄清楚爲什麼發生這種情況的細節 - 但顯然這些回調不會添加到串行隊列中。 *
爲了治癒異步問題,你有幾種選擇:
1)把下載的代碼的回調上傳代碼裏面。
這樣,直到圖片成功上傳後,下載纔會開始執行。我做了之後,使用火力地堡存儲網頁上運行的應用程序之前刪除的圖像對我的上傳/下載無不利影響,而且這些消息都按預期的順序輸出:
[My Upload Success]:
[URL for download]: ...
[My Download Success]:
2)附上。成功觀察uploadTask。
正如火力地堡文檔描述的,在Monitor Upload Progress section,你可以得到通知,如果uploadTask成功上傳的圖片:
let storage = FIRStorage.storage()
let storageRef = storage.reference() //You don't need to explicitly write the url in your code.
//The config file GoogleService-Info.plist will handle that.
let imageRef = storageRef.child("images/align_menu.tiff")
let localURL = NSBundle.mainBundle().URLForResource(
"align_menu",
withExtension: "tiff"
)!
//Upload the image:
let uploadTask = imageRef.putFile(localURL, metadata: nil) { (metadata, error) -> Void in
if let returnedError = error {
// Uh-oh, an error occurred!
print("[My Upload Error]: \(returnedError)")
} else {
// Metadata contains file metadata such as size, content-type, and download URL.
print("[My Upload Success]:")
let downloadURL = metadata!.downloadURL()!
print("[URL for download]: \(downloadURL)")
}
}
let observer = uploadTask.observeStatus(.Success) { (snapshot) -> Void in
//Download the image:
imageRef.dataWithMaxSize(1 * 1024 * 1024) { (data, error) -> Void in
if let returnedError = error {
// Uh-oh, an error occurred!
print("[My Download Error]: \(returnedError)")
}
else {
print("[My Download Success]:")
if let validImage = UIImage(data: data!) {
NSOperationQueue.mainQueue().addOperationWithBlock() {
self.imageView.image = validImage
}
}
}
}
}
3)使用大中央調度通知您當上載是成功的。
您無法控制回調添加到哪些隊列(Firebase方法實現決定),但您可以使用Grand Central Dispatch在任意代碼執行完成時通知您。對我來說,以下工作:
let storage = FIRStorage.storage()
let storageRef = storage.reference() //You don't need to explicitly write the url in your code.
//The config file GoogleService-Info.plist will handle that.
let imageRef = storageRef.child("images/align_menu.tiff")
let localURL = NSBundle.mainBundle().URLForResource(
"align_menu",
withExtension: "tiff"
)!
let myExecutionGroup = dispatch_group_create()
dispatch_group_enter(myExecutionGroup)
//Upload the image:
let _ = imageRef.putFile(localURL, metadata: nil) { (metadata, error) -> Void in
if let returnedError = error {
// Uh-oh, an error occurred!
print("[My Upload Error]: \(returnedError)")
} else {
// Metadata contains file metadata such as size, content-type, and download URL.
print("[My Upload Success]:")
let downloadURL = metadata!.downloadURL()!
print("[URL for download]: \(downloadURL)")
dispatch_group_leave(myExecutionGroup)
}
}
let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)
dispatch_group_notify(myExecutionGroup, queue) {
//This callback executes for every dispatch_group_leave().
//Download the image:
imageRef.dataWithMaxSize(1 * 1024 * 1024) { (data, error) -> Void in
if let returnedError = error {
// Uh-oh, an error occurred!
print("[My Download Error]: \(returnedError)")
}
else {
print("[My Download Success]:")
if let validImage = UIImage(data: data!) {
NSOperationQueue.mainQueue().addOperationWithBlock() {
self.imageView.image = validImage
}
}
}
}
}
*
我試圖把原來的代碼上傳和下載的代碼之間的sleep(10)
,並沒有緩解這個問題。我認爲如果上傳回調在後臺線程上執行,那麼在主線程正在休眠時上傳回調將有時間完成,然後在完成睡眠後下載代碼將執行並且下載回調將被添加到隊列中某處,然後下載回調將執行。由於睡眠(10)沒有解決問題,這意味着上傳回調必須已被添加到主線程的執行隊列中,並且睡眠暫停主線程和隊列中的任何內容執行。
這使我相信,上傳和下載的回調被添加到異步隊列主線程(它不是一個同步隊列,否則將回調爲了執行)。我認爲主線程上的一個異步隊列意味着當主線程上有空閒時間時,隊列中的任務將會執行,並且當特定任務中有空閒時間時,您還可以在各種任務之間快速切換,如等待HTTP響應。例如,如果主線程上的異步隊列中有兩個任務,那麼每當任何一個線程中都有空閒時間時,主線程,task1和task2之間會快速切換。
在我看來,'signedInUser.uid'作爲一個對象返回(可能是因爲你沒有強迫它到'String!'?),它指向錯誤的文件。你能證實你得到了正確的「uid」,而且路徑確實正確嗎? –