1

I'm now able to sort posts and users by time.

My data structure looks like that:

posts
 -postId
     imageRatio: 
     imageUrl: 
     postText: 
     postTime: 
     uId:
users
 -UserId
    email: 
    profileImageURL: 
    radius: 
    uid: 
    username: 
    username_lowercase: 

UPDATE

Now, I created a new class with all datas for the user and the posts:

class UserPostModel {
    var post: PostModel?
    var user: UserModel?

    init(post: PostModel, user: UserModel) {
        self.post = post
        self.user = user
    }
}

Declaration of my post array:

var postArray = [UserPostModel]()

Here, Im loading the datas into the new class:

self.observeRadius(completion: { (radius) in
                let currentRadius = radius
            // Üperprüfe, welche Posts im Umkreis erstellt wurden
                let circleQuery = geoRef.query(at: location!, withRadius: Double(currentRadius)!)

            circleQuery.observe(.keyEntered, with: { (postIds, location) in

                self.observePost(withPostId: postIds, completion: { (posts) in
                    guard let userUid = posts.uid else { return }
                    self.observeUser(uid: userUid, completion: { (users) in
                        let postArray = UserPostModel(post: posts, user: users)
                        self.postArray.append(postArray)
                        print(postArray.post!.postText!, postArray.user!.username!)
                        self.postArray.sort(by: {$0.post!.secondsFrom1970! > $1.post!.secondsFrom1970!})

                    })
                })

Here I'm loading the datas into the table view cells:

    extension DiscoveryViewController: UITableViewDataSource {
    // wie viele Zellen
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        print(postArray.count)
        return postArray.count
    }

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

        cell.user = postArray[indexPath.row]
        cell.post = postArray[indexPath.row]
        //cell.delegate = self

        return cell
    }
}

Thanks in advance for your help!

jo1995
  • 410
  • 1
  • 5
  • 12
  • 1
    It wouldn't make sense to *sort the users by date* so it's a little unclear what you're trying to do. I assume your intention is to display posts, sorted by date, and each associated users info displayed with each most? If so it might be easier to create a class in code, stored in an array, that stores the postclass data and associated user data and then use that as your tableView datasource. So you would get your posts as you are now and for each post get the user and store both in a single class. That way the user stays 'attached' to the post through sorting, deleting, filtering etc. – Jay Dec 01 '18 at 13:06
  • Yes I want to sort the posts by date and attach the user to the post. Whats the best way to do? Sorting users by date and posts by date is exactly not the right way. – jo1995 Dec 01 '18 at 13:17
  • There is no best way but I posed an option in my comment; use a class to hold both the PostClass and UserClass and use that as your dataSource. – Jay Dec 01 '18 at 13:19
  • 1
    okay updated the question. I created a new class and I already get the posts and they are sorted by time. But I have problems to observe the users. Thats still not working. Thanks for your help! – jo1995 Dec 01 '18 at 15:10

1 Answers1

2

There's a lot of code in the question and sometimes, simpler is better. So let's take a Post class, load the posts, get the associated user name and store it in an array. Then when complete, sort and print the posts in reverse chronological order.

A class to hold the post data and the user name

class PostClass {
    var post = ""
    var timestamp: Int! //using an int for simplicity in this answer
    var user_name = ""

    init(aPost: String, aUserName: String, aTimestamp: Int) {
        self.post = aPost
        self.user_name = aUserName
        self.timestamp = aTimestamp
    }
}

Note that if we want to have have both post data and user data we could do this

class PostUserClass {
   var post: PostClass()
   var user: UserClass()
}

but we're keeping it simple for this answer.

Then an array to store the posts

var postArray = [PostClass]()

and finally the code to load in all of the posts, get the associated user name (or user object in a full example).

let postsRef = self.ref.child("posts")
let usersRef = self.ref.child("users")
postsRef.observeSingleEvent(of: .value, with: { snapshot in
    let lastSnapIndex = snapshot.childrenCount
    var index = 0
    for child in snapshot.children {
        let childSnap = child as! DataSnapshot
        let uid = childSnap.childSnapshot(forPath: "uid").value as! String
        let post = childSnap.childSnapshot(forPath: "post").value as! String
        let timestamp = childSnap.childSnapshot(forPath: "timestamp").value as! Int
        let thisUserRef = usersRef.child(uid)

        thisUserRef.observeSingleEvent(of: .value, with: { userSnap in
            index += 1
            //for simplicity, I am grabbing only the user name from the user
            //  data. You could just as easily create a user object and
            //  populate it with user data and store that in PostClass
            //  that would tie a user to a post as in the PostUserClass shown above
            let userName = userSnap.childSnapshot(forPath: "Name").value as! String
            let aPost = PostClass(aPost: post, aUserName: userName, aTimestamp: timestamp)
            self.postArray.append(aPost) //or use self.postUserArray to store
                                         //  PostUserClass objects in an array.
            if index == lastSnapIndex {
                self.sortArrayAndDisplay() //or reload your tableView
            }
        })
    }
})

and then the little function to sort and print to console

func sortArrayAndDisplay() {
    self.postArray.sort(by: {$0.timestamp > $1.timestamp})

    for post in postArray {
        print(post.user_name, post.post, post.timestamp)
    }
}

Note that Firebase is asynchronous so before sorting/printing we need to know we are done loading in all of the data. This is handled via the lastSnapIndex and index. The index is only incremented once each user is loaded and when all of the posts and users have been loaded we then sort and print as the data is complete.

This example avoids messy callbacks and completion handlers which may be contributing to the issue in the question - this piece of code is suspect and probably should be avoided due to the asynchronous nature of Firebase; the sort function is going to be called well before all of the users are loaded.

UserApi.shared.observeUserToPost(uid: userUid) { (user) in
    self.postUser.append(user)
}
self.postUser.sort(by: {$0.postDate! > $1.postDate!})

*please add error checking.

Jay
  • 29,230
  • 15
  • 46
  • 73
  • Thank you so much for your help! It really helps me by finding a solution for this problem. I edited my question again and now I created a class with a UserModel and a PostModel as in your answer. I'm loading the datas (user datas and post datas) into the PostUserModel. Is it a solution for this problem? Many thanks again!! – jo1995 Dec 02 '18 at 11:13
  • @jo1995 In your update, you've created a PostUserClass but that then stores an array of posts and and array of users which doesn't really help. If you look at my answer the PostUserClass is what you store in an array of PostUsers i.e. *let myPostUserArray = [PostUserClass]()* so each PostUser object has one post and one user. That way, when populating a tableView from your datasource, for each row, it will retrieve one PostUser object from that array and can pull out the post info and then the corresponding user info. – Jay Dec 02 '18 at 14:33
  • @jo1995 I added a few comments to my answer as well to hopefully provide a bit more detail. – Jay Dec 02 '18 at 14:40
  • perfect. I really appreciate your help! I added your code in my code. Later on, I can extend them to all datas I need for my post. One last question. How do I load the table view cells in your example? – jo1995 Dec 02 '18 at 14:56
  • Be sure to accept the answer if it helped so it can also help others. Tableviews are populated from a datasource and in this case the datasource is the array used store posts, the postArray, or the posts and users, the postUserArray. There are dozens of tutorials available for working with tableViews [Ray Wenderlich](https://www.raywenderlich.com) and also from weheartswift [tableView tutorial](https://www.weheartswift.com/how-to-make-a-simple-table-view-with-ios-8-and-swift/). [This one](https://stackoverflow.com/questions/33234180/uitableview-example-for-swift) on SO is good as well. – Jay Dec 02 '18 at 15:05