Reputation: 25
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'
Upvotes: 1
Views: 312
Reputation: 763
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.
Upvotes: 0
Reputation: 4721
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.
Upvotes: 2