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

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

ただいまの
回答率

90.34%

  • Swift

    7719questions

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

  • iOS

    4197questions

    iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Firebaseで複数画像をStorageに保存した後、Databaseに同じディレクトリに保存したい。

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 288

yuga

score 5

現在SNSっぽいアプリの開発を行なっており、投稿画面でつまづいています。
Firebaseで複数画像をStorageとDatabaseに保存し、Databaseで1投稿に複数画像を同じ階層に保存するという処理を書きたいです。

ImagePickerを使って、複数画像を取得し、それをFirebaseに送る処理を書いています。以下がコードです。

import UIKit
import ImagePicker
import ProgressHUD
import Firebase
class PostTableViewController: UITableViewController, UITextFieldDelegate {

    var pageCount = 0
    @IBOutlet weak var selectedimageView: UIImageView!
    @IBOutlet weak var noteNameTextField: UITextField!
    @IBOutlet weak var noteDetailTextView: UITextView!
    @IBOutlet weak var categoryTextField: UITextField!
    @IBOutlet weak var post_Btn: UIButton!
    @IBOutlet weak var goPage_Btn: UIButton!
    @IBOutlet weak var backPage_Btn: UIButton!

    var selectedImages = [UIImage]()


    override func viewDidLoad() {
        super.viewDidLoad()
        selectedimageView.image = selectedImages[pageCount]
        print("selectedImages1: \(selectedImages)")

        post_Btn.setTitleColor(UIColor.lightText, for: UIControlState.normal)
        post_Btn.isEnabled = false
        handleTextDidChanged()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        handlePhotoChanged()
        handlePhotoChanged2()
    }


        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

            self.view.endEditing(true)
            if (noteNameTextField.isFirstResponder) || (categoryTextField.isFirstResponder){

                noteNameTextField.resignFirstResponder()
                categoryTextField.resignFirstResponder()
            }

        }


    func handlePhotoChanged(){
        guard selectedimageView.image != selectedImages[0] else{
           return backPage_Btn.isEnabled = false
        }
        backPage_Btn.isEnabled = true
    }

    func handlePhotoChanged2(){
        guard selectedimageView.image != selectedImages.last else{
            return goPage_Btn.isEnabled = false
        }
        goPage_Btn.isEnabled = true
    }

    func handleTextDidChanged(){
        noteNameTextField.addTarget(self, action: #selector(self.textFieldDidChange), for: UIControlEvents.editingChanged)
        categoryTextField.addTarget(self, action: #selector(self.textFieldDidChange), for: UIControlEvents.editingChanged)
    }

    @objc func textFieldDidChange(){
        guard let noteName = noteNameTextField.text, !noteName.isEmpty, let category = categoryTextField.text, !category.isEmpty else{

            post_Btn.setTitleColor(UIColor.lightText, for: UIControlState.normal)
            post_Btn.isEnabled = false
            return
        }
        post_Btn.setTitleColor(.white, for: UIControlState.normal)
        post_Btn.isEnabled = true
    }


    @IBAction func canel_touchUpInside(_ sender: Any) {

        dismiss(animated: true, completion: nil)
    }


    @IBAction func goPage_touchUpInside(_ sender: Any) {
        pageCount += 1
        selectedimageView.image = selectedImages[pageCount]
        handlePhotoChanged()
        handlePhotoChanged2()
    }

    @IBAction func backPage_touchUpInside(_ sender: Any) {
        pageCount -= 1
        selectedimageView.image = selectedImages[pageCount]
        handlePhotoChanged()
        handlePhotoChanged2()
    }


    var photoStringDelegate:String?

    @IBAction func post_touchUpInside(_ sender: Any) {
        //データをまとめてデータベースに投げる処理
        ProgressHUD.show("Waiting...", interaction: false)
        for selectedImage in selectedImages {
              print("selectedImage times: \(selectedImage)")

            if selectedImage == selectedImages.first{
                if  let imageData = UIImageJPEGRepresentation(selectedImage, 0.1) {
                    print("selectedImage[0]: \(selectedImage)")
                    let photoIdString = NSUUID().uuidString
                     print("photoIdString[0]: \(photoIdString)")
                    photoStringDelegate = photoIdString
                    let storageRef = Storage.storage().reference(forURL: Config.STORAGE_ROOF_REF).child("posts").child("\(photoIdString)").child(photoIdString)
               sendDataTostorage(storageRef: storageRef, imageData: imageData)

                }
            }

            if selectedImage != selectedImages.first{
                if  let imageData = UIImageJPEGRepresentation(selectedImage, 0.1) {
                    print("selectedImage[other]: \(selectedImage)")
                    let photoIdString = NSUUID().uuidString
                    let storageRef = Storage.storage().reference(forURL: Config.STORAGE_ROOF_REF).child("posts").child(photoStringDelegate!).child(photoIdString)
                    print("photoStringDelegate: \(photoStringDelegate)")
               sendDataTostorage2(storageRef: storageRef, imageData: imageData)
            }

       }

    }

  }

    func sendDataTostorage(storageRef:StorageReference,imageData:Data){
        storageRef.putData(imageData, metadata: nil) { (metadata, error) in
            if error != nil{
                return
            }
            storageRef.downloadURL(completion: { (url, error) in
                if error != nil{
                    ProgressHUD.showError(error!.localizedDescription)
                    return
                }
                if let mainPhotoUrl = url?.absoluteString {
                   sendToDatabase(mainPhotoUrl:mainPhotoUrl,subPhotoUrl:nil)
                }

            })
        }
    }

    func sendDataTostorage2(storageRef:StorageReference,imageData:Data){
        storageRef.putData(imageData, metadata: nil) { (metadata, error) in
            if error != nil{
                return
            }
            storageRef.downloadURL(completion: { (url, error) in
                if error != nil{
                    ProgressHUD.showError(error!.localizedDescription)
                    return
                }
                if let subPhotoUrl = url?.absoluteString {

                   sendToDatabase(mainPhotoUrl:nil,subPhotoUrl:subPhotoUrl)
                }
            })
        }
    }



  func sendToDatabase(mainPhotoUrl:String? = nil,subPhotoUrl:String? = nil){
        let newPostId = Api.Post.REF_POSTS.childByAutoId().key
        let newPostReference = Api.Post.REF_POSTS.child(newPostId)

          var dict = [:] as [String:Any]
        if let mainPhotoUrl = mainPhotoUrl {
            dict["mainPhotoUrl"] = mainPhotoUrl
        }
        if let subPhotoUrl = subPhotoUrl{
            dict["subPhotoUrl"] = subPhotoUrl
        }

        newPostReference.setValue(dict, withCompletionBlock: {
            (error, ref) in
            if error != nil {
                ProgressHUD.showError(error!.localizedDescription)
                return
            }
            ProgressHUD.showSuccess("Success")
    })
    }

}


for文を用いて、selectedImages配列に入っている画像を一づつstorage保存しています。現在のコードだとStorageに1投稿ごとの画像を保存することはできています。
以下が三つの画像を保存した際のStorageの画面です。
イメージ説明

しかし、Databaseを見ると一つの画像IDごとに1投稿IDが生成されてしまいます。以下がその画像です。

イメージ説明

理想は以下の構造で保存したいです。

イメージ説明

原因としてはfor文でsendToDatabaseを一回一回呼んでいるため、その度にpostIdが呼ばれてしまっていることが原因だとわかっているのですが、どうしたらpostIdを一回一回呼ばずに複数の画像をDatabaseに保存できるかわかりません。分かる方いらっしゃいましたら教えていただけるとありがたいです。。よろしくお願いします。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

check解決した方法

0

解決できませんでした。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

原因としてはfor文でsendToDatabaseを一回一回呼んでいるため、その度にpostIdが呼ばれてしまっていることが原因だとわかっているのですが、どうしたらpostIdを一回一回呼ばずに複数の画像をDatabaseに保存できるかわかりません。

とのことですが、貼り付けられたコードはsendToDatabaseを呼び出している箇所がどこにもありません。
sendToDatabaseメソッドの内容を見る限り、mainPhotoUrlsubPhotoUrlの2つの引数にURLを入れて呼び出せば、1つの投稿IDの中にmainPhotoUrlsubPhotoUrlの2つのキーが格納される形で保存できていると思います。
(Api.Post.REF_POSTSがなんなのか見えていませんが、おそらくDatabase.database().reference().child("posts")を意味するのだろうと推測しました。)

手書きで書かれている理想の構造は、PostIdの下にsubPhotoUrlという同じキーが2つ存在するようになっていますが、1つのPostIdの中に同じキーを2つ作ることはできません。
1つのフォルダの中に同じ名前のファイルやフォルダを2つ作ることはできないのと同じです。

もうちょっとちゃんと質問しないと、何がしたくてどう困っているのかよくわかりませんが、sendToDatabaseを何回呼び出しても同じ場所に保存できるようにしたいのであれば、

 let newPostId = Api.Post.REF_POSTS.childByAutoId().key


sendToDatabaseの呼び出し元で実施し、それをプロパティに覚えるなり、sendToDatabaseの引数で渡せるようにするなりして、sendToDatabaseの中の処理は、あらかじめ指定された投稿IDに保存する形にしたらいいと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

同じタグがついた質問を見る

  • Swift

    7719questions

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

  • iOS

    4197questions

    iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。