Home Async Closure Issue Solve in Swift not working?
Reply: 2

Async Closure Issue Solve in Swift not working?

zackkkkkkk
1#
zackkkkkkk Published in 2018-01-12 21:12:45Z

I Have boiled down the problem to this

this closure :

  override func viewDidLoad() {
    super.viewDidLoad()
    let data = homeDataSource()
    getPrivatePosts { (posts) in
        print("postsCOUNT" , posts!.count)
        data.posts = posts!
    }
    self.datasource = data
    collectionView?.reloadData()

}

prints out "postCOUNT 1 postCOUNT 3"

then when I print the count of data.posts I get 0... whats going on with that?? here is the full code

this is a custom UICollectionView:

import LBTAComponents
import Firebase
class homeView: DatasourceController {

override func viewDidLoad() {
    super.viewDidLoad()
    let data = homeDataSource()
    getPrivatePosts { (posts) in
        print("postsCOUNT" , posts!.count)
        data.posts = posts!
    }
    self.datasource = data
    collectionView?.reloadData()

}

override func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    return CGSize(width: view.frame.width , height: 150)
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
    return CGSize(width: view.frame.width, height: 0   )
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
    return CGSize(width: view.frame.width, height: 0)
}
// just to test
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    performSegue(withIdentifier: "goToNewPost", sender: self)
}


func getPrivatePosts(completion : @escaping (_ privatePosts : [Post]?) ->()){
    // fill posts array with posts from all buddys "privataPosts only"


    var ret = [Post]()
    staticValuesForData.instance.dataBaseUserref.child((Auth.auth().currentUser?.uid)!).child("contacts").observe( .value , with: { (snapshot) in

        let dict = snapshot.children.allObjects as! [DataSnapshot]
        for d in dict{
            if let contactUid = d.childSnapshot(forPath: "uid").value as? String{


                staticValuesForData.instance.dataBaseUserref.child(contactUid).child("privatePosts").observe( .value, with: { (snapshot) in

                    let posts = snapshot.children.allObjects as! [DataSnapshot]
                    print("postval" , posts)

                    for post in posts{

                        if let dict = post.value as? [String : AnyObject]{
                            let fullname = dict["fullname"] as! String
                            let picUrl = dict["picUrl"] as! String
                            let postContent = dict["postContent"] as! String
                            let time = dict["time"] as! Int
                            let uid = dict["uid"] as! String
                            let username = dict["username"] as! String

                            print("first name of person who did the post" , fullname)

                            let reposts = dict["reposts"] as! [String]

                            let downs = dict["downs"] as! [String]
                            // possible issue
                            var comments = [Comment]()

                            let commentArr = snapshot.childSnapshot(forPath: "comments").children.allObjects as! [DataSnapshot]

                            for c in commentArr{
                                if let dict = c.value as? [String : AnyObject]{

                                    let cuid = dict["uid"] as! String
                                    let ccommentText = dict["commentText"] as! String
                                    let cpicUrl = dict["picUrl"] as! String
                                    let cusername = dict["username"] as! String
                                    let ctime = dict["time"] as! Int

                                    let com = Comment(uid: cuid, commentText: ccommentText, time: ctime, picUrl: cpicUrl, username: cusername)

                                    comments.append(com)

                                }

                            }

                            print("HERE : post content\(postContent) username : \(username) commentArr \(comments)")

                            let postToAdd = Post(postContent: postContent, picUrl: picUrl, userName: username, fullName: fullname, postID: uid, postTime: time, downs: downs, reposts: reposts, comments: comments)

                            print("LOOK AT MEE   \(postToAdd.userName) is the username of the post object \(postToAdd.postContent) is the contetn")

                            ret.append(postToAdd)
                            print("RET" , ret)
                        }
                    }
                    completion(ret) // this is where the completion block should be called
                })

            }
        }
    })
}

}

This is a datasource object :

import LBTAComponents
class homeDataSource: Datasource {

var posts = [Post]()



override func numberOfItems(_ section: Int) -> Int {
    print("COUNT " , posts.count)
    return posts.count

}

override func headerClasses() -> [DatasourceCell.Type]? {
    return [userHeader.self]
}

override func footerClasses() -> [DatasourceCell.Type]? {
    return [userFooter.self]
}

override func cellClasses() -> [DatasourceCell.Type] {
    return [userCell.self]
}

override func item(_ indexPath: IndexPath) -> Any? {
    return posts[indexPath.item]
}

}

The frame work can be used here :

pod 'LBTAComponents'

Upholder Of Truth
2#
Upholder Of Truth Reply to 2018-01-12 21:28:17Z

You have the same basic misunderstanding twice.

In the second code section you create your ret variable initially empty and then fire of some async tasks. However you call the completion(ret) outside of the async task so it will fire immediately before the async tasks have finished and therefore return your initial empty value.

The fist code also will suffer the same problem in that you create your postArray initially empty then call your getPrivatePosts function supplying a completion handler but that completion handler will be called in an async task so there could be a delay but you use the value immediately and therefore will return the empty initial value.

naturaln0va
3#
naturaln0va Reply to 2018-01-12 21:41:00Z

You shouldn't create your posts array in that way. You should create the a mutable array:

var posts = [Post]()

Then in the viewDidLoad of your view controller you should then populate the array from your service (Firebase).

override func viewDidLoad() {
    super.viewDidLoad()

    getPrivatePosts() { posts in
        self.posts = posts ?? []
    }
}

You posts function also is never going to return the data you want from the service since your calling your completion block outside of the scope of the service request. Move the completion block to the bottom of the for loop in the staticValuesForData.instance.dataBaseUserref.child part of the getPrivatePosts function like so:

class func getPrivatePosts(completion : (_ privatePosts : [Post]?) ->.   ()){
    // fill posts array with posts from all buddys "privataPosts only"


    var ret = [Post]()
    staticValuesForData.instance.dataBaseUserref.child((Auth.auth().currentUser?.uid)!).child("contacts").observe( .value , with: { (snapshot) in

        let dict = snapshot.children.allObjects as! [DataSnapshot]
        for d in dict{
            if let contactUid = d.childSnapshot(forPath: "uid").value as? String{


                staticValuesForData.instance.dataBaseUserref.child(contactUid).child("privatePosts").observe( .value, with: { (snapshot) in

                    let posts = snapshot.children.allObjects as! [DataSnapshot]
                    print("postval" , posts)

                    for post in posts{

                        if let dict = post.value as? [String : AnyObject]{
                            let fullname = dict["fullname"] as! String
                            let picUrl = dict["picUrl"] as! String
                            let postContent = dict["postContent"] as! String
                            let time = dict["time"] as! Int
                            let uid = dict["uid"] as! String
                            let username = dict["username"] as! String

                            print("first name of person who did the post" , fullname)

                            let reposts = dict["reposts"] as! [String]

                            let downs = dict["downs"] as! [String]
                            // possible issue
                            var comments = [Comment]()

                            let commentArr = snapshot.childSnapshot(forPath: "comments").children.allObjects as! [DataSnapshot]

                            for c in commentArr{
                                if let dict = c.value as? [String : AnyObject]{

                                    let cuid = dict["uid"] as! String
                                    let ccommentText = dict["commentText"] as! String
                                    let cpicUrl = dict["picUrl"] as! String
                                    let cusername = dict["username"] as! String
                                    let ctime = dict["time"] as! Int

                                    let com = Comment(uid: cuid, commentText: ccommentText, time: ctime, picUrl: cpicUrl, username: cusername)

                                    comments.append(com)

                                }

                            }

                            print("HERE : post content\(postContent) username : \(username) commentArr \(comments)")

                            let postToAdd = Post(postContent: postContent, picUrl: picUrl, userName: username, fullName: fullname, postID: uid, postTime: time, downs: downs, reposts: reposts, comments: comments)

                            print("LOOK AT MEE   \(postToAdd.userName) is the username of the post object \(postToAdd.postContent) is the contetn")

                            ret.append(postToAdd)
                            print("RET" , ret)
                        }
                    }
                    completion(ret) // this is where the completion block should be called
                })

            }
        }

    })
}

I hope this helps.

You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.349147 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO