Displaying a users post on iOS

[亡魂溺海] 提交于 2019-12-24 18:23:01

问题


I am trying to display a users "post" in a table view on iOS. When a users writes a post and hits the post button in my app, the post is saved to my firebase real time data base but it is not displaying in the tableview on the viewcontroller on which the code is written in. I'm not sure if its my code or something to do with firebase not responding and showing the data. Here is my code:

import Foundation
import UIKit
import Firebase

class HomeViewController:UIViewController, UITableViewDelegate, UITableViewDataSource {

    var tableView:UITableView!

    var posts = [Post] ()

    override func viewDidLoad() {
        super.viewDidLoad()
        self.observePosts()

        tableView = UITableView(frame: view.bounds, style: .plain)

        let cellNib = UINib(nibName: "PostTableViewCell", bundle: nil)
        tableView.register(cellNib, forCellReuseIdentifier: "postCell")
        view.addSubview(tableView)


        tableView.delegate = self
        tableView.dataSource = self
        tableView.tableFooterView = UIView()
        tableView.reloadData()

    }

    func observePosts() {
        let postsRef = Database.database().reference().child("posts")

        postsRef.observe(.childAdded, with: { snapshot in


            print(snapshot.value)

            var tempPosts = [Post]()


            for child in snapshot.children {
                if let childSnapshot = child as? DataSnapshot,
                    let dict = childSnapshot.value as? [String:Any],
                    let author = dict["author"] as? [String:Any],
                    let uid = author["uid"] as? String,
                    let fullname = author["username"] as? String,
                    let photoURL = author["photoURL"] as? String,
                    let url = URL (string:photoURL),
                    let text = dict["text"] as? String,
                    let timestamp = dict["timestamp"] as? Double {

                    let userProfile = UserProfile(uid: uid, fullname: fullname, photoURL: url)
                    let post = Post(id: childSnapshot.key, author: userProfile, text: text, timestamp: timestamp)
                    tempPosts.append(post)
            }
        }
            self.posts = tempPosts
            self.tableView.reloadData()
        })
    }


    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return posts.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as! PostTableViewCell
        cell.set(post: posts[indexPath.row])
        return cell
    }
}

Also is this helps, here are my database rules:

{
 "rules" :{
        "posts" : {
            ".write" : true, 
            ".read": true

       },
        "users" : {
            ".write" : true,  
            ".read" : true
       }
     } 
  }

Here are examples of my PostTableViewCell, Post Class and my PostTableViewCell.xib: Post Class PostTableViewCell PostTableViewCell.xib

Also This is what it my code looks like when entering plain data.

import Foundation
import UIKit
import Firebase

class HomeViewController:UIViewController, UITableViewDelegate, UITableViewDataSource {

    var tableView:UITableView!

    var posts = ["This is a text"]

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView = UITableView(frame: view.bounds, style: .plain)

        let cellNib = UINib(nibName: "PostTableViewCell", bundle: nil)
        tableView.register(cellNib, forCellReuseIdentifier: "postCell")
        view.addSubview(tableView)


        tableView.delegate = self
        tableView.dataSource = self
        tableView.tableFooterView = UIView()
        tableView.reloadData()

    }


    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return posts.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as! PostTableViewCell
        return cell
    }
}

And this is what it looks like when I run my app. TableView Loadout With Sample Data


回答1:


You should change postRef.observe(.value, with: in your code to postRef.observe(.childAdded, with: , this way observe function will be called every time new child is added to posts reference.




回答2:


Your rules are denying permission to read that node: they are set to the default which requires an authenticated user to read/write any data. You app needs to have authentication, so you would add something along these lines to the top of your main viewController

import UIKit
import Firebase
import FirebaseAuth

class ViewController: UIViewController,

and then add in authentication code. You will need to have a User set up in your Firebase Console and call this function in viewDidLoad

func authUser() {
     Auth.auth().signIn(withEmail: "users email", password: "password", completion: { (auth, error) in
        if let x = error { //example error checking
            let err = x as NSError
            switch err.code {
            case AuthErrorCode.wrongPassword.rawValue:
                print("wrong password")
            case AuthErrorCode.invalidEmail.rawValue:
                print("invalued email")
            default:
                print("unknown error")
            }
        } else { //no error, user is authed
            if let user = auth?.user {
                print("uid: \(user.uid)") //print their uid
            }
        }
    })
}

OR

for testing you can allow anyone read/write access by changing the rules

{
  "rules": {
    ".read": true,
    ".write": true
  }
}

but that's very insecure so don't leave it that way.

EDIT

The other issue is in how your working with the read data from Firebase. The if statement will totally bail if anything is wrong - for example a specified child is not in one of the nodes being read.

To correct that evaluate each child separately and provide a default value in case the child is missing.

Assume a struture like this

posts
   post_0
      author
         uid: "uid_0"
         username: "uid 0 username"
      url: "www.someurl.com"
      post_text: "My post about posting"

and then the code to read all of the posts (and the child data) and output it to console.

func readPosts() {
    let postsRef = self.ref.child("posts") //self.ref points to my firebase
    postsRef.observeSingleEvent(of: .value, with: { snapshot in
        print("inside the observe closure")
        let allPosts = snapshot.children.allObjects as! [DataSnapshot]
        for postSnap in allPosts {
            let authorSnap = postSnap.childSnapshot(forPath: "author")
            let uid = authorSnap.childSnapshot(forPath: "uid").value as? String ?? "NO UID!"
            let username = authorSnap.childSnapshot(forPath: "username").value as? String ?? "NO USERNAME!"
            let postTitle = postSnap.childSnapshot(forPath: "post_title").value as? String ?? "NO POST TITLE!"
            let url = postSnap.childSnapshot(forPath: "url").value as? String ?? "NO URL!"
            print(uid, username, postTitle, url)
        }
    }, withCancel: { error in
        let err = error as NSError
        print(err.localizedDescription)
    })
}

and the output looks like this

uid_0 uid 0 username My post about posting www.someurl.com
uid_1 uid 1 username Things about posting www.anotherurl.com



回答3:


I am adding this as a separate answer since my first answer addressed a possible issue reading from Firebase. Now there's an issue with the tableView.

The attached code is a complete and runnable project - soup to nuts, other than a PostTableViewCell xib which is literally a UITableViewCell subclass and matching xib - no other code.

I hope you can use this as a template to compare against your code.

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    class PostClass {
        var post_text = ""
    }

    var tableView:UITableView!

    var posts = [PostClass]()

    override func viewDidLoad() {
        super.viewDidLoad()
        self.setupTableView()

        //create two posts just to test the tableView
        let p0 = PostClass()
        p0.post_text = "Hello Row 0"
        let p1 = PostClass()
        p1.post_text = "And Row 1"
        self.posts.append(contentsOf: [p0, p1])
    }

    func setupTableView() {

        tableView = UITableView(frame: view.bounds, style: .plain)

        let cellNib = UINib(nibName: "PostTableViewCell", bundle: nil)
        tableView.register(cellNib, forCellReuseIdentifier: "postCell")
        view.addSubview(tableView)

        var layoutGuide:UILayoutGuide!
        layoutGuide = view.safeAreaLayoutGuide

        tableView.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor).isActive = true
        tableView.topAnchor.constraint(equalTo: layoutGuide.topAnchor).isActive = true
        tableView.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor).isActive = true
        tableView.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor).isActive = true

        tableView.delegate = self
        tableView.dataSource = self
        tableView.reloadData()
    }

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return posts.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as! PostTableViewCell
        let post = self.posts[indexPath.row]
        cell.textLabel!.text = post.post_text
        return cell
    }
}

and an image of the result



来源:https://stackoverflow.com/questions/59091483/displaying-a-users-post-on-ios

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!