Есть ли какие-то особенности или проблемы с Firebase Storage? Какое-то кэширование, которое нужно решить?
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) Поместите код загрузки в обратный вызов для кода загрузки.
Таким образом, загрузка не начнется до тех пор, пока изображение не будет успешно загружено. После того, как я это сделал, удаление изображения с помощью веб-страницы Firebase Storage перед запуском приложения не оказало пагубного влияния на мою загрузку/выгрузку, и сообщения выводились в ожидаемом порядке:
[My Upload Success]:
[URL for download]: ...
[My Download Success]:
2) Прикрепите наблюдателя .Success к uploadTask.
Как описано в документации Firebase, в разделе Отслеживание хода загрузки. , вы можете получить уведомление, если 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) Используйте Grand Central Dispatch, чтобы уведомить вас об успешной загрузке.
У вас нет контроля над тем, в какие очереди добавляются обратные вызовы (это решает реализация метода 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)
между исходным кодом загрузки и кодом загрузки, но это не решило проблему. Я думал, что если обратный вызов загрузки выполняется в фоновом потоке, то обратный вызов загрузки будет иметь время для завершения, пока основной поток спит, а затем после завершения сна код загрузки будет выполняться, и обратный вызов загрузки будет добавлен в очередь где-нибудь, тогда будет выполнен обратный вызов загрузки. Поскольку sleep(10) не решил проблему, это означало, что обратный вызов загрузки должен был быть добавлен в очередь выполнения для основного потока, а сон останавливал выполнение основного потока и всего, что находилось в очереди.
Это наводит меня на мысль, что обратные вызовы загрузки и выгрузки добавляются в асинхронную очередь в основном потоке (это не синхронная очередь, иначе обратные вызовы выполнялись бы по порядку). Я думаю, что асинхронная очередь в основном потоке означает, что когда в основном потоке есть мертвое время, задачи в очереди будут выполняться, и вы также получаете быстрое переключение между различными задачами, когда в конкретной задаче есть мертвое время, например ожидание HTTP-ответа. Например, если в асинхронной очереди в основном потоке есть две задачи, то происходит быстрое переключение между основным потоком, задачей1 и задачей2 всякий раз, когда в любой из них есть мертвое время.
person
7stud
schedule
16.06.2016
signedInUser.uid
возвращается как объект (может быть, потому, что вы не принуждаете его кString!
?), и он указывает на неправильный файл. Можете ли вы убедиться, что вы получаете правильныйuid
и что путь действительно правильный? - person Mike McDonald   schedule 16.06.2016