Я даю пользователям возможность настроить Project-Details в приложении. Так как есть также возможность загрузить изображение, мне придется использовать Firebase Storage. Поскольку я хочу дать пользователям обзор своих проектов, объединяющих данные и загруженную картинку, мне нужно сделать ссылку между DocumentID в базе данных и ImageID в хранилище.
Я думал о двухэтапном подходе: 1. Пользователи генерируют проект -> Пользователь нажимает «далее» (документ генерируется) 2. Пользователь загружает изображение -> Изображение сохраняется в хранилище со ссылкой на DocumentID только что созданного проекта.
Цель состоит в том, чтобы просто связать изображение с идентификатором документа проекта.
Может кто-нибудь подсказать, как решить эту проблему? Вот мои коды:
Для деталей проекта:
// MARK: Store the Project Infos in Database
// Check the fields and validate that the data is correct. If everything is correct, this method returns nil. Otherwise, it returns the error message
func validateFields() -> String? {
// Check that all fields are filled in
if txtLocation.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" ||
txtProjectTitle.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" ||
txtProjectDescription.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" ||
endDate.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" ||
beginnDate.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" {
return "Please fill in all fields."
}
return nil
}
@IBAction func saveProject(_ sender: Any) {
let user = Auth.auth().currentUser
if let user = user {
let uid = user.uid
// Validate the fields
let error = validateFields()
if error != nil {
// There is something wrong with the fields, show error message
showError(error!)
} else {
// Create cleaned versions of the data
let projectTitle = txtProjectTitle.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let projectLocation = txtLocation.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let projectDescription = txtProjectDescription.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let projectBeginn = beginnDate.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let projectEnd = endDate.text!.trimmingCharacters(in: .whitespacesAndNewlines)
// Save stuff
let db = Firestore.firestore()
db.collection("Projects").addDocument(data: ["Project Title": projectTitle, "Project Location": projectLocation, "Project Description": projectDescription, "Project Start": projectBeginn, "Project Finish": projectEnd, "uid": uid]) { (error) in
if error != nil {
// Show error message
self.showError("Error saving user data")
}
}
}
} else { self.showError("Please log out and log in again")}
}
// Error Handling for save
func showError(_ message:String) {
errorLabel.text = message
errorLabel.alpha = 1
}
И для загрузки изображения
//MARK: Imagepicker
// Image Picker functions
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage
newImage.image = image
picker.dismiss(animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
// MARK: - Actions
// Image Picker
@IBAction func addImage(_ sender: Any) {
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
let actionSheet = UIAlertController(title: "Photo Source", message: "Choose a source", preferredStyle: .actionSheet)
actionSheet.addAction(UIAlertAction(title: "Camera", style: .default, handler: { (action: UIAlertAction) in imagePickerController.sourceType = .camera
self.present(imagePickerController, animated: true, completion: nil)
}))
actionSheet.addAction(UIAlertAction(title: "Photo Library", style: .default, handler: { (action: UIAlertAction) in imagePickerController.sourceType = .photoLibrary
self.present(imagePickerController, animated: true, completion: nil)
}))
actionSheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
self.present(actionSheet, animated: true, completion: nil)
}
//MARK: Upload Image
@IBAction func uploadImage(_ sender: Any) {
guard let image = newImage.image, let data = image.jpegData(compressionQuality: 1.0) else {
self.showError("Something went wrong")
return
}
let imageName = UUID().uuidString
let imageReference = Storage.storage().reference()
.child("imagesFolder")
.child(imageName)
imageReference.putData(data, metadata: nil) {(metadata, err) in
if let err = err {
self.showError("Something went wrong")
return
}
imageReference.downloadURL(completion: { (url, err) in
if let err = err {
self.showError("Something went wrong")
return
}
guard let url = url else {
self.showError("Something went wrong")
return
}
let dataReference = Firestore.firestore().collection("imageReferences").document()
let documentUid = dataReference.documentID
let urlString = url.absoluteString
let imageUID = documentUid
let data = ["Image UID": imageUID, "Image URL": urlString]
dataReference.setData(data, completion: {(err) in
if let err = err {
self.showError("Something went wrong")
return
}
UserDefaults.standard.set(documentUid, forKey: imageUID)
})
})
}
}
// Error Handling for save
func showError(_ message:String) {
errorLabel.text = message
errorLabel.alpha = 1
}
Так что в лучшем случае я мог бы сделать это даже в одном View Controller без необходимости двухэтапного подхода. Если это невозможно, я бы хотел поместить сгенерированный идентификатор документа в
let data = ["Image UID": imageUID, "Image URL": urlString]
из
let dataReference = Firestore.firestore().collection("imageReferences").document()
let documentUid = dataReference.documentID
let urlString = url.absoluteString
let imageUID = documentUid
let data = ["Image UID": imageUID, "Image URL": urlString]
dataReference.setData(data, completion: {(err) in
if let err = err {
self.showError("Something went wrong")
return
}
. Я был бы очень рад, если бы кто-нибудь мог мне помочь. :)