是否有任何怪癖或问题与火力地堡存储?需要解决的某种 缓存?
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”,而且路径确实正确吗? –