1

I'm using a refreshcontrol, but while my code compiles, the current code has an issue where it removes all the data first and then pulls in the table data causing a brief moment where it isn't showing any data. Is there a quick fix for this? Should I use a completion handler for this by calling removeAll once the posts are loaded...

Edit: I've added the relevant portion of fetchNetworkPost below.

override func viewDidLoad() {
super.viewDidLoad()

    let refreshControl = UIRefreshControl()
    refreshControl.addTarget(self, action: #selector(requestData), for: .valueChanged)

    self.refreshControl = refreshControl

    requestData()
}

@objc
func requestData() {

    self.postArray.removeAll()
    fetchNetworkPosts() //populates data

    refresh()

}

func refresh() {

  self.refreshControl?.endRefreshing()

  self.tableView.reloadData()

}

func fetchNetworkPosts() {

        for personId in networkArray {

    let currentUserRef = 
Database.database().reference().child("posts").queryOrdered(byChild: 
"userId").queryEqual(toValue: personId)
            currentUserRef.observeSingleEvent(of: .value, with: { 
(snapshot) in

                for childSnapshot in snapshot.children {

                    let test = Post(snapshot: childSnapshot as! DataSnapshot)

                    self.postArray.append(test)

                }

                self.postArray.sort { $0.postDate > $1.postDate } //sort

                self.tableView.reloadData()

            })

        }
}
ml2008
  • 33
  • 5

3 Answers3

1

override func viewDidLoad() {
    super.viewDidLoad()

    let refreshControl = UIRefreshControl()
    refreshControl.addTarget(self, action: #selector(requestData), for: .valueChanged)

    self.refreshControl = refreshControl

    requestData()
}
@objc func requestData() {
    fetchNetworkPosts() //populates data
}

func refresh() {

    self.refreshControl?.endRefreshing()

    self.tableView.reloadData()

}

func fetchNetworkPosts() {

    for personId in networkArray {

        let currentUserRef =
            Database.database().reference().child("posts").queryOrdered(byChild:
                "userId").queryEqual(toValue: personId)
        currentUserRef.observeSingleEvent(of: .value, with: {
            (snapshot) in

            self.postArray.removeAll()
            for childSnapshot in snapshot.children {

                let test = Post(snapshot: childSnapshot as! DataSnapshot)

                self.postArray.append(test)

            }

            self.postArray.sort { $0.postDate > $1.postDate } //sort

            self.refresh()

        })

    }
}

inside fetchNetworkPosts() method when you receive the new data self.postArray.removeAll() remove old data there and then assign new value at that time. then call refresh(). Hope this will work for you.

Shabbir
  • 289
  • 2
  • 6
  • I'm sure this will do. – Osman Tüfekçi Jan 03 '20 at 06:52
  • For some reason, when I just pull down and keep refreshing the data, it doesn't maintain the previous posts. I found another solution which said to use this function instead but I dont know how to use. func getData() { fetchPostsWithCompletion() { if let tempPosts = dataFromNetwork { self.posts = tempPosts } else { self.posts.removeAll() } self.refresh() } } https://stackoverflow.com/questions/40698224/fatal-error-index-out-of-range-when-refreshing-table-view?noredirect=1&lq=1 – ml2008 Jan 03 '20 at 07:26
1

Call your refresh() after the completion of fetchNetworkPosts() like below. Check the code below.

@objc func requestData() {
    fetchNetworkPosts() //populates data
}

func refresh() {

  self.refreshControl?.endRefreshing()
  self.tableView.reloadData()

}

func fetchNetworkPosts() {

         self.postArray.removeAll() // remove your array data here

        for personId in networkArray {

        let currentUserRef =
Database.database().reference().child("posts").queryOrdered(byChild:
"userId").queryEqual(toValue: personId)
            currentUserRef.observeSingleEvent(of: .value, with: {
(snapshot) in

                for childSnapshot in snapshot.children {

                    let test = Post(snapshot: childSnapshot as! DataSnapshot)

                    self.postArray.append(test)

                }

                self.postArray.sort { $0.postDate > $1.postDate } //sort

                self.refresh()

            })

        }
}
Keshu R.
  • 5,045
  • 1
  • 18
  • 38
  • For some reason, when I just pull down and keep refreshing the data, it doesn't maintain the previous posts. I found another solution which said to use this function instead but I dont know how to use. func getData() { fetchPostsWithCompletion() { if let tempPosts = dataFromNetwork { self.posts = tempPosts } else { self.posts.removeAll() } self.refresh() } } https://stackoverflow.com/questions/40698224/fatal-error-index-out-of-range-when-refreshing-table-view?noredirect=1&lq=1 – ml2008 Jan 03 '20 at 07:25
  • what do you mean by **it doesn't maintain the previous posts.** ? – Keshu R. Jan 03 '20 at 07:29
  • When I run the program, there are 5 posts. But when I refresh it without doing anything to the dataset, it only shows 1 post. I'm not sure where the other 4 posts went. I wonder if it has to do with the position of the removeAll function? – ml2008 Jan 03 '20 at 07:33
  • I've tried that along with many other areas for self.postArray.removeAll(), but for some reason, the old posts keep changing. Is there a rule where the removeAll should be located? – ml2008 Jan 03 '20 at 07:45
  • thats because of the for loop you have placed your code in. `for personId in networkArray { ` you want posts of a single person or all persons ? – Keshu R. Jan 03 '20 at 07:48
  • Basically networkArray holds a list of friend id's. For each of those id's, I'm pulling all of their posts and showing them in a tableview. – ml2008 Jan 03 '20 at 07:52
  • is there a way to use a completion handler for this? Basically removeAll once the posts are loaded – ml2008 Jan 04 '20 at 07:20
0

maybe changing order will fix your problem.

override func viewDidLoad() {
super.viewDidLoad()

    let refreshControl = UIRefreshControl()
    refreshControl.addTarget(self, action: #selector(requestData), for: .valueChanged)

    self.refreshControl = refreshControl

    requestData()
}

@objc
func requestData() {


    fetchNetworkPosts() //populates data

    refresh()

}

func refresh() {
  self.postArray.removeAll()
  self.refreshControl?.endRefreshing()

  self.tableView.reloadData()

}

You are removing your data before fetch it. So, fetch data first then remove your tableView. You'll see your old data for brief time, not empty tableView.

  • unfortunately this did not work - it just ended up removing all my data so nothing shows – ml2008 Jan 03 '20 at 06:24
  • then hold two different arrays. postArray and let's say postArray2. add variable observer, when postArray2 set with your response from fetchNetworkPosts(), remove postArray then reload your tableView with postArray2 you can add variable observer like this var postArray:[String]() { didSet{ print(self.postArray2) } } – Osman Tüfekçi Jan 03 '20 at 06:39
  • @OsmanTüfekçi network calls are asynchronous. `refresh()` will get called before `fetchNetworkPosts()` completes. and also i wont suggest property observer for array data change, that will reload the table on every data append. – Keshu R. Jan 03 '20 at 06:43
  • he wont refresh tableView when data is changed. he will set his second array when data is set. – Osman Tüfekçi Jan 03 '20 at 06:51
  • 1
    why to even use anotherArray when this can be done using same dataSource. you are saying every time user refresh, he needs to switch arrays or else add a new array and make that as data source. This doesn't make sense.. There are better ways :) – Keshu R. Jan 03 '20 at 06:59