質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

1回答

2959閲覧

Storageで生成されたURLのFireStoreへの保存

sam3457

総合スコア52

Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

1クリップ

投稿2018/09/19 12:19

Firebase Auth/Storage/FireStore を使った新規登録の処理を作っています。

以下は新規登録(まずAuthで認証し、帰ってきたUserをFireStoreに登録、画像があるならばそのURLも一緒に保存する)処理です。

swift

1static func signUp(name: String, email: String, password: String, image: UIImage?, onSuccess: @escaping () -> Void, onError: @escaping (_ errorMessage: String?) -> Void) { 2 Auth.auth().createUser(withEmail: email, password: password, completion: { user, error in 3 if error != nil { 4 onError(error) 5 return 6 } 7 guard let uid = user?.user.uid else { return } 8 var dict: [String: Any] = [ 9 "name": name, 10 "email": email 11 ] 12 // If Image is Set 13 if let image = image { 14 StorageService.storage(image: image, path: .icon, id: uid) { (imageUrl) in 15 dict["iconUrl"] = imageUrl 16 } 17 } 18 Firestore.firestore().collection("users").document(uid).setData(dict) { (error) in 19 if let error = error { 20 print(error) 21 return 22 } 23 } 24 onSuccess() 25 }) 26 }

以下はStorageのUIImageを引数にとり、URLを返す処理を関数にしたものです

swift

1class StorageService { 2 3 // Upload Image to Storage 4 static func storage(image: UIImage?, path: PathType, id: String, completion: @escaping (_ imageUrl: String?) -> ()) { 5 guard let image = image, let imageData = UIImageJPEGRepresentation(image, 0.1) else { 6 print("Non Image") 7 completion(nil) 8 return 9 } 10 let storageRef = Storage.storage().reference().child(path.rawValue).child(id) 11 storageRef.putData(imageData, metadata: nil, completion: { (metaData, error) in 12 if let error = error { 13 print("Fail to Put Data in Storage : (error)") 14 completion(nil) 15 return 16 } 17 storageRef.downloadURL { (imageUrl, error) in 18 if let error = error { 19 print("Fail to Download Url : (error)") 20 completion(nil) 21 return 22 } 23 if let imageUrl = imageUrl?.absoluteString { 24 completion(imageUrl) 25 } 26 } 27 }) 28 } 29} 30

Authの登録と、FireStoreへの保存は成功するのですが、画像がある時、
Storageには保存されているのに、FireStoreには画像のURlが保存されません。

storage()クロージャの書き方などに問題があるのでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

非同期処理とコールバックが呼ばれるタイミングについて意識してコードを書くようにしてみましょう。

swift

1if let image = image { 2 StorageService.storage(image: image, path: .icon, id: uid) { (imageUrl) in 3 dict["iconUrl"] = imageUrl 4 } 5} 6Firestore.firestore().collection("users").document(uid).setData(dict) { (error) in 7 if let error = error { 8 print(error) 9 return 10 } 11}

こちらの処理ですが、StorageService.storageに渡しているコールバックの中身は画像のアップロードが終わった時点で呼ばれるように実装されていますね。つまり、下のsetDataの処理のほうが先に呼ばれてしまうので、画像のURLが含まれない状態でFirestoreに保存されてしまいます。

以下のように、アップロードが終わった時点でFirestoreに保存するよう修正しましょう。imageがnilの場合の処理はstorageメソッド内で完結していますので、 if let image = image { } による場合分けは不要です。

swift

1StorageService.storage(image: image, path: .icon, id: uid) { (imageUrl) in 2 // 画像のアップロードが終わったらURLをセット 3 // (画像がなかったりエラーの場合はnilが渡されるので何も設定しない) 4 dict["iconUrl"] = imageUrl 5 6 // Firestoreに保存する 7 Firestore.firestore().collection("users").document(uid).setData(dict) { (error) in 8 ... 9 } 10}

投稿2018/09/23 05:13

kakajika

総合スコア3131

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問