I've been struggling with this for 2 hours now. I'm building an app in Swift, using Firebase Database and storage.
我一直在努力奋斗2个小时。我正在使用Firebase数据库和存储在Swift中构建应用程序。
The goal is to update User profile. The user has 2 images - Profile and header. Now, I have to first check if they've selected an image from the photo library, if not - just get the old URL from the database and submit it back to the database with the rest of the updated information. If it's a new selected image, upload the image to the Storage, get back the URL using downloadURL
assign it to the var storageHeaderDownloadedURL
and/or var storageProfileDownloadedURL
and submit the string values with the rest of the user data to Firebase Database.
目标是更新用户个人资料。用户有2个图像 - 配置文件和标题。现在,我必须首先检查他们是否从照片库中选择了一个图像,如果没有 - 只需从数据库中获取旧URL并将其与其他更新信息一起提交回数据库。如果是新选择的图像,请将图像上传到存储,使用downloadURL获取URL,将其分配给var storageHeaderDownloadedURL和/或var storageProfileDownloadedURL,并将其余用户数据的字符串值提交给Firebase数据库。
The problem is that it obviously assigns the values of an empty String
(I've declared them as such) BEFORE I get back the downloaded URL. If the user doesn't update the images but the rest of the UITextFields
it all works, the old URL is submitted to the Firebase Database.
问题是它明显地分配了一个空字符串的值(我已经声明它们)在我找回下载的URL之前。如果用户不更新图像,但其余的UITextField都可以正常工作,则旧URL将提交给Firebase数据库。
My question is how do I execute the downloaded URL methods for from the storage and then assign it to var storageHeaderDownloadedURL
and var storageProfileDownloadedURL
first hand?
我的问题是如何从存储中执行下载的URL方法,然后将其分配给var storageHeaderDownloadedURL和var storageProfileDownloadedURL?
func updateUserProfile ()
{
if let userID = FIRAuth.auth()?.currentUser?.uid
{
// Note: Storage references to profile images & profile headers folder
let storageUserProfileID = Storage.storage.profile_images.child(userID)
let storageUserHeaderID = Storage.storage.profile_headers.child(userID)
guard let imageProfile = profileImage.image else { return }
guard let headerImage = headerImage.image else { return }
if let newProfileImage = UIImagePNGRepresentation(imageProfile), let newHeaderImage = UIImagePNGRepresentation(headerImage)
{
storageUserProfileID.put(newProfileImage, metadata: nil, completion: { (metadata, error) in
if error != nil
{
showAlert(title: "Oops!", msg: (error?.localizedDescription)!, actionButton: "OK", viewController: self)
return
}
// Get the URL from the storage
storageUserProfileID.downloadURL(completion: { (url, error) in
if error != nil
{
showAlert(title: "Oops!!!", msg: (error?.localizedDescription)!, actionButton: "OK", viewController: nil)
return
}
else
{
if let profileImgDownloadedURL = url?.absoluteString
{
self.storageProfileDownloadedURL = profileImgDownloadedURL
print(self.storageProfileDownloadedURL)
self.selectedProfileImage = .True
}
}
})
})
storageUserHeaderID.put(newHeaderImage, metadata: nil, completion: { (metadata, error) in
if error != nil
{
showAlert(title: "Oops!", msg: (error?.localizedDescription)!, actionButton: "OK", viewController: self)
return
}
// Get the URL from the storage
storageUserHeaderID.downloadURL(completion: { (url, error) in
if error != nil
{
showAlert(title: "Oops!!!", msg: (error?.localizedDescription)!, actionButton: "OK", viewController: self)
return
}
else
{
if let headerImgDownloadedURL = url?.absoluteString
{
self.storageHeaderDownloadedURL = headerImgDownloadedURL
print(self.storageHeaderDownloadedURL)
self.selectedHeaderImage = .True
}
}
})
})
//Note: Update the info for that user in Database
print(self.storageHeaderDownloadedURL)
print(self.storageProfileDownloadedURL)
var finalHeaderImageURL = String()
switch self.selectedHeaderImage {
case .True:
finalHeaderImageURL = self.storageHeaderDownloadedURL
break
case .False:
finalHeaderImageURL = self.oldHeaderImageInDB
break
}
print(finalHeaderImageURL)
var finalProfileImageURL = String()
switch self.selectedProfileImage {
case .True:
finalProfileImageURL = self.storageProfileDownloadedURL
break
case .False:
finalProfileImageURL = self.oldProfilePhotoImageInDB
break
}
print(finalProfileImageURL)
guard let newDisplayName = self.displayNameTextField.text else { return }
guard let newLocation = self.locationTextField.text else { return }
guard let newDescription = self.bioTextField.text else { return }
guard let newWebsite = self.websiteTextField.text else { return }
guard let newBirthday = self.birthdayTextField.text else { return }
let newUpdatedUserDictionary = ["imageProfile": finalProfileImageURL,
"imageHeader" : finalHeaderImageURL,
"description" : newDescription,
"location": newLocation,
"displayName": newDisplayName,
"website": newWebsite,
"birthday": newBirthday,
]
Database.dataService.updateUserProfile(uid: userID, user: newUpdatedUserDictionary)
showAlert(title: "Hey", msg: "Your profile was updated", actionButton: "OK", viewController: self)
} // Get new uploaded profile and header image URLs
}
}
The enums I use for the switch statements to determine if it's an old URL or a new one:
我用于switch语句的枚举,以确定它是旧URL还是新URL:
enum SelectedHeaderImage
{
case True
case False
}
enum SelectedProfileImage
{
case True
case False
}
Class outlets:
分店:
var storageProfileDownloadedURL = String()
var storageHeaderDownloadedURL = String()
var oldProfilePhotoImageInDB = String()
var oldHeaderImageInDB = String()
var selectedHeaderImage = SelectedHeaderImage.False
var selectedProfileImage = SelectedProfileImage.False`
1 个解决方案
#1
1
From what I understood, your problem is with queuing. You want the code below to execute after the download is complete but it executes in its normal flow. If this is what your problem is then I would suggest you to create another enum
, with three download states/count. And move that code below you want to be executed later in a function. Increment the state of new enum
when download is complete. It would look something like this:
根据我的理解,你的问题是排队。您希望下载代码在下载完成后执行,但它在正常流程中执行。如果这是你的问题,那么我建议你创建另一个枚举,有三个下载状态/计数。并将下面的代码移到您希望稍后在函数中执行的代码中。下载完成后,增加新枚举的状态。它看起来像这样:
enum DownloadCount
{
case Zero
case One
case Two
}
var downloadCount = DownloadCount.Zero
and in each of the success block of your download complete change it to, I will just write one here to give you the idea of what needs to be done.
并且在下载的每个成功块中完成更改,我将在此处写一个,以便让您了解需要完成的工作。
if let profileImgDownloadedURL = url?.absoluteString
{
self.storageProfileDownloadedURL = profileImgDownloadedURL
print(self.storageProfileDownloadedURL)
self.selectedProfileImage = .True
if(downloadCount == .Zero)
{
downloadCount = DownloadCount.One
}
else
{
downloadCount = DownloadCount.Two
}
self.newAssigningFunction()
}
func newAssigningFunction()
{
if(downloadCount == .Two)
{
//Do your storage/saving work here
}
}
Also if you need to execute this function again, it would be best to set downloadCount
back to Zero
at start of your updateUserProfile
function. Let me know if somethis is unclear or you need further help. Or if this was not your case.
此外,如果您需要再次执行此功能,最好在updateUserProfile函数启动时将downloadCount设置为Zero。如果有些不清楚,或者您需要进一步的帮助,请告诉我。或者如果这不是你的情况。
#1
1
From what I understood, your problem is with queuing. You want the code below to execute after the download is complete but it executes in its normal flow. If this is what your problem is then I would suggest you to create another enum
, with three download states/count. And move that code below you want to be executed later in a function. Increment the state of new enum
when download is complete. It would look something like this:
根据我的理解,你的问题是排队。您希望下载代码在下载完成后执行,但它在正常流程中执行。如果这是你的问题,那么我建议你创建另一个枚举,有三个下载状态/计数。并将下面的代码移到您希望稍后在函数中执行的代码中。下载完成后,增加新枚举的状态。它看起来像这样:
enum DownloadCount
{
case Zero
case One
case Two
}
var downloadCount = DownloadCount.Zero
and in each of the success block of your download complete change it to, I will just write one here to give you the idea of what needs to be done.
并且在下载的每个成功块中完成更改,我将在此处写一个,以便让您了解需要完成的工作。
if let profileImgDownloadedURL = url?.absoluteString
{
self.storageProfileDownloadedURL = profileImgDownloadedURL
print(self.storageProfileDownloadedURL)
self.selectedProfileImage = .True
if(downloadCount == .Zero)
{
downloadCount = DownloadCount.One
}
else
{
downloadCount = DownloadCount.Two
}
self.newAssigningFunction()
}
func newAssigningFunction()
{
if(downloadCount == .Two)
{
//Do your storage/saving work here
}
}
Also if you need to execute this function again, it would be best to set downloadCount
back to Zero
at start of your updateUserProfile
function. Let me know if somethis is unclear or you need further help. Or if this was not your case.
此外,如果您需要再次执行此功能,最好在updateUserProfile函数启动时将downloadCount设置为Zero。如果有些不清楚,或者您需要进一步的帮助,请告诉我。或者如果这不是你的情况。