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

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

ただいまの
回答率

87.35%

画面遷移に伴うFirebaseのバグ【iOS】

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,084

score 25

やりたいこと

FirstViewからSecondViewへ画面遷移した時に,Firebaseの値を更新し,その値をFirebaseから読み取ってSecondViewで表示する.

これまでの流れ

  1. 新しいプロジェクトを作成する.
  2. Firebaseとアプリを接続する.
  3. 写真1のようにオブジェクトを配置する.
  4. コード1コード2を記述する.
  5. 写真3のようにRealtime Databaseを構成する.
  6. プロジェクトを実行するとFirestViewではprint(Array)が実行されるが,SecondViewへ画面遷移を行うと,SecondViewではprint("error")が実行される.

コード1

ViewController.swift

import UIKit
import Firebase

class ViewController: UIViewController {

    var ref: DatabaseReference!
    var value: Int = 0



    override func viewDidLoad() {
        super.viewDidLoad()

        self.ref = Database.database().reference()
        self.ref.observeSingleEvent(of: .value) { (DataSnapshot) in
            guard let Array = DataSnapshot.value as? [String: Int] else {
                print("error")
                return
            }
            print(Array) //["値": 3]
        }
    }



    @IBAction func increment(_ sender: UIButton) {
        self.value += 1
    }



    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        self.ref.child("値").runTransactionBlock { (MutableData) -> TransactionResult in
            if let value = MutableData.value as? Int {
                MutableData.value = value + self.value
                self.value = 0
            }
            return TransactionResult.success(withValue: MutableData)
        }
    }
}

コード2

SecondViewController.swift

import UIKit
import Firebase

class SecondViewController: UIViewController {

    var ref: DatabaseReference!

    @IBOutlet weak var label: UILabel!



    override func viewDidLoad() {
        super.viewDidLoad()
    }



    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        self.ref = Database.database().reference()
        self.ref.observeSingleEvent(of: .value) { (DataSnapshot) in
            guard let Array = DataSnapshot.value as? [String: Int] else {
                print("error") //error
                self.label.text = "error"
                return
            }
            print(Array)
            if let value = Array["値"] {
                self.label.text = String(value)
            }
        }
    }
}

写真1

Main.storyboard
イメージ説明

写真2

構成
イメージ説明

写真3

Firebase
イメージ説明

写真4

デバイス上
イメージ説明

写真5

実際のアプリに近づけた構成
detailで値を増やし,detailからSecondへ画面遷移をした際にFirebaseへの書き込みと書き出しを行う.
その際に問題が発生する.
イメージ説明

環境

xcode : ver11.0
Swift : ver5.1
iOS : ver13.1.2

最後に

お力をお貸しください.宜しくお願い致します.
(分かり難所があれば言ってください)

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 4

+1

そもそも質問のタイトルに「Firebaseのバグ」と書いているのが
この質問の心証を悪くしていると思います。
「Firebaseのバグ」だというのは、Firebaseが悪いと言っています。
そうじゃなくて、Firebaseを正しく使うことができないあなたのコードのバグでしょ。
Firebaseに責任をなすりつけるなよと思います。

それで、今回の件ですが、SecondViewControllerのviewDidAppearの
タイミングでobserveSingleEventを使ってデータ取得するのではなくて、
SecondViewControllerのviewDidLoadで、observeメソッドを使って
データの更新を常に監視するようあらかじめ仕掛けておけば、
別の場所で実施したトランザクション更新が確定したタイミングで
適宜最新データを取得してラベルを更新できると思います。

import UIKit
import Firebase

class SecondViewController: UIViewController {

    var ref: DatabaseReference!

    @IBOutlet weak var label: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        self.ref = Database.database().reference()
        self.ref.observe(.value) { (DataSnapshot) in
            guard let Array = DataSnapshot.value as? [String: Int] else {
                print("error") //error
                return
            }
            print(Array)
            if let value = Array["値"] {
                self.label.text = String(value)
            }
        }
    }
}

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/10/27 21:15

    ではどのようにしたら画面表示中だけ監視できるのでしょうか

    キャンセル

  • 2019/10/27 23:31 編集

    「viewWillAppearのタイミングで監視を開始してviewWillDisappearで監視を停止させることで画面表示中だけ監視する」って具体的に書いてるのに、全く読んでないか、意味がわからないんでしょうね。「解決ならず」であきらめたみたいだからどうでもいいですけど。

    キャンセル

  • 2019/10/28 23:03

    ですから,「viewWillAppearのタイミングで監視を開始してviewWillDisappearで監視を停止させることで画面表示中だけ監視する」にはどのようにしたらいいのかわからないので質問しているのですが.

    キャンセル

0

まず、問題は切り分けましょう。
今回の問題点は、「TableViewに1月が表示されない」ということでいいですか?

tableViewfirebaseからの取得を下記のようにprintしてみてはどうですか?

self.ref.observeSingleEvent(of: .value) { (DataSnapshot) in
    let namesArray = DataSnapshot.value as! [String: Int]
    // 下記を追加
    print(namesArray)
    self.rank = namesArray.sorted {$0.value > $1.value}
    self.list.reloadData()
}

もし、それでも1月が取得できていないのでしたら、取得の方法(self.ref)がおかしいということで、
再度googleの公式ドキュメントを見てみる必要があると思います。

以下、2019/10/26修正

よくわかりませんが、どうしてもそのようなタイミングがいいということみたいですね。
TabBarをクリックした時にしたいということなので、
TabBarをcustom classでラップして、
その条件の時に値を書き換えるようにする必要があります。

ここを参考に書いて見ました。

タイミングの取得はバッチしできることをサンプルを作成して確認しております。

import UIKit

class CustomTabBarController: UITabBarController, UITabBarControllerDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        self.delegate = self
    }

    func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
        let naviCon = tabBarController.viewControllers![0] as! UINavigationController
        let presentView = naviCon.visibleViewController
        if presentView is ADetailViewController {
            switch viewController {
            case is BViewController:
                print("From ADetail, show B")
                // ここに値を書き換えるトランザクションを記入し、トランザクションがかえってきたら、tableViewにreloadをかけること
                return true
            default:
                print("From else, show B")
                return true
            }
        }
        return true
    }
}

イメージ説明

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/10/20 23:47

    >>しかし、根本問題として、
    viewcontrollerを表示し、tableViewに遷移せずに
    アプリを終了した場合はどうするつもりでしょうか?

    その問題についても考えていて,アプリが強制終了する際に実行するメソッド等がないかも探しているところです.また,userdefaultsなどを使っても解決できるのではないかと考えています.

    キャンセル

  • 2019/10/21 00:40

    >>transactionが返ってくるとこで、
    tableviewにreloadをかける必要があります。
    observerを使う、delegateを使う
    もしくは直接指定
    (storyboard idからviewを取得して、tableviewにreloadをかける)
    でもも行えると思います。

    実際のアプリに近い構成は写真5のような感じになっているのですが,FirestViewのButtonを押すとDetailViewに遷移し,DetailViewからタブの切り替えでSecondViewに遷移した際に上記の問題が発生します.
    DetailViewからの遷移先が,BackボタンでFirestViewへ行くか,タブの切り替えでSecondViewに行くかの2通りあるので,タブの切り替えでSecondViewへ遷移した時だけtransactionやobserverを使って通知するにはどのようにしたら良いのか考えている次第です.
    具体的な方法やコードを知っていましたらご教授願います.

    キャンセル

  • 2019/11/17 20:32

    2019/10/26修正につきましてはありがとうございます.
    特定の画面遷移を判断できる方法があるのですね.
    そこでなのですが

    // ここに値を書き換えるトランザクションを記入し、トランザクションがかえってきたら、tableViewにreloadをかけること

    の部分をどのように書けばいいのかわからない次第です.
    教えていただけますでしょうか.

    キャンセル

0

画面遷移に伴うFirebaseのバグ【iOS】

Bug Report から Google へバグ報告をしてください。

ただ、質問内容からは以下が不明なので、適切に追記して報告すると良いです。
・どの仕様に対してどのようにおかしな挙動をしているか?(該当する Document の箇所を示すのが良いかと)
・再現のための最小限のコードの提示

あと、興味本位ですが、上記が整理できれば、質問に追記をしていただけると知的好奇心が満たされます。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/10/21 22:33

    返信遅くなりました.
    質問をもう少しわかりやすくしてみました.
    実際に実装してみていただけると幸いです.
    わかりにくい箇所があれば言ってください.

    キャンセル

check解決した方法

-1

解決ならずでした.
一旦ここでお開きとします.

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

  • ただいまの回答率 87.35%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

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