LoginSignup
1
2

More than 3 years have passed since last update.

【Fire base+swift】学習記録(4)ログイン機能のあるTODOアプリを作る

Last updated at Posted at 2019-11-23

【Swift】リアルタイムチャットを実現するFirebaseでCRUD(データ作成、読み込み、更新、削除)をやってみる

こちらを参考にログイン機能ありのTODOアプリを作成しました。
今回学んだのはユーザー情報と投稿情報の紐付け方です。

自分なりの理解をコメントに入れています。

ユーザー情報と投稿情報の紐付け方

viewcontroller.swift
func create() {
        //textFieldになにも書かれてない場合は、その後の処理をしない
        guard let text = textField.text else { return }

        //ロートからログインしているユーザーのIDをchildにしてデータを作成
        //childByAutoId()でユーザーIDの下に、IDを自動生成してその中にデータを入れる
        //setValueでデータを送信する。第一引数に送信したいデータを辞書型で入れる
        //今回は記入内容と一緒にユーザーIDと時間を入れる
        //FIRServerValue.timestamp()で現在時間を取る
        self.ref.child((Auth.auth().currentUser?.uid)!).childByAutoId().setValue(["user": (Auth.auth().currentUser?.uid)!,"content": text, "date": ServerValue.timestamp()])

        //テスト表示
        print("user\((Auth.auth().currentUser?.uid)!)content\(text)date\(ServerValue.timestamp())")

    }

一般的にFirebaseでデータを保存するときは、setValueで行いますが、今回はunique-post-idなどを生成するためにchildByAutoIdを使いました。おそらく。

メソッド 一般的な使用例
setValue users/user-id/username など、定義済みのパスへのデータの書き込みや、データの置換を行います。
childByAutoId データのリストに追加します。childByAutoId を呼び出すたびに、user-posts/user-id/unique-post-idのような一意の識別子としても使用できる一意のキーが生成されます。
updateChildValues データのすべてを置換することなく、定義済みのパスのキーの一部を更新します。
runTransactionBlock 同時更新によって破損する可能性がある複合データを更新します。

iOS でのデータの保存より

データの表示の方法

Java および Node.js では、コールバック関数は DataSnapshot を受け取ります。これはデータのスナップショットです。スナップショットとは、ある時点における特定のデータベース参照にあるデータの全体像を写し取ったものです。スナップショットの val() / getValue() を呼び出すと、データの言語固有のオブジェクト表現が返されます。参照先の場所にデータが存在しない場合、スナップショットの値が null になります。

Listviewcontroller.swift
 //Fetchしたデータを入れておく配列、この配列をTableViewで表示
    var contentArray: [DataSnapshot] = []
    //FetchしたSnapshotsを格納する変数
    var snap: DataSnapshot!
    //Firebaseのルートを宣言しておく
    let ref = Database.database().reference()

xibファイルを使わずに表示する方法

参考にした記事ではxibファイルなどを使ってセル内にcontentを表示してましたが、自分はまだxibファイルの使い方側からなっか他ため、以下のように少し変更して実装しました。

Listviewcontroller.swift

class ListViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    @IBOutlet weak var table: UITableView! //送信したデータを表示するTableView

    var contentArray: [DataSnapshot] = [] //Fetchしたデータを入れておく配列、この配列をTableViewで表示
    var snap: DataSnapshot! //FetchしたSnapshotsを格納する変数
    let ref = Database.database().reference() //Firebaseのルートを宣言しておく

    override func viewDidLoad() {
        super.viewDidLoad()
        //データを読み込むためのメソッド
        self.read()
        table.delegate = self //デリゲートをセット
        table.dataSource = self //デリゲートをセット

        // Do any additional setup after loading the view.

    }

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

        //Cellの高さを調節
        table.estimatedRowHeight = 56
        table.rowHeight = UITableView.automaticDimension
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        //画面が消えたときに、Firebaseのデータ読み取りのObserverを削除しておく
        ref.removeAllObservers()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    //ViewControllerへの遷移
    func transition() {
        self.performSegue(withIdentifier: "toView", sender: self)
    }

    //セルの数
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return contentArray.count
    }

    //返すセルを決める
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell (
            withIdentifier: "Cell",
            for: indexPath as IndexPath)
        //contetnArrayにitemを代入
        let item = contentArray[indexPath.row]
        //cell内に代入するものをfirebaseから持ってくる
        let textlabel = item.value as! Dictionary<String, AnyObject>
        //cell内に代入するものを決める
        cell.textLabel?.text = String(describing: textlabel["content"]!)
        return cell
    }

    func read()  {
        //FIRDataEventTypeを.Valueにすることにより、なにかしらの変化があった時に、実行
        //今回は、childでユーザーIDを指定することで、ユーザーが投稿したデータの一つ上のchildまで指定することになる
        ref.child((Auth.auth().currentUser?.uid)!).observe(.value, with: {(snapShots) in
            if snapShots.children.allObjects is [DataSnapshot] {
                print("snapShots.children...\(snapShots.childrenCount)") //いくつのデータがあるかプリント

                print("snapShot...\(snapShots)") //読み込んだデータをプリント

                self.snap = snapShots

            }
            self.reload(snap: self.snap)
        })
    }

    //読み込んだデータは最初すべてのデータが一つにまとまっているので、それらを分割して、配列に入れる
    func reload(snap: DataSnapshot) {
        if snap.exists() {
            print(snap)
            //FIRDataSnapshotが存在するか確認
            contentArray.removeAll()
            //1つになっているFIRDataSnapshotを分割し、配列に入れる
            for item in snap.children {
                contentArray.append(item as! DataSnapshot)
            }
            // ローカルのデータベースを更新
            ref.child((Auth.auth().currentUser?.uid)!).keepSynced(true)
            //テーブルビューをリロード
            table.reloadData()
        }
    }

}

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2