0

I have a switch statement that gets how many post a user has and I name the var numberOfPosts to = posts.count. But I would like to return the Int value from numberOfPosts in the UICollectionView func numberOfItemsInSection but it always returns zero. How do I go about fixing this?

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        userSubID = AWSMobileClient.default().userSub!
        let post = uploads.keys
        let predicate = post.userSub == userSubID
        _ = Amplify.API.query(request: .list(uploads.self, where: predicate)) { event in
            switch event {
            case .success(let result):
                switch result {
                case .success(let posts):
                    self.numberOfPosts = posts.count 
                  print(numberOfPosts) // It prints the num of posts
                case .failure(let error):
                    print("Got failed result with \(error.errorDescription)")
                }
            case .failure(let error):
                print("Got failed event with error \(error)")
            }
        }
        print(numberOfPosts)
        return numberOfPosts //The variable returns 0 
    }

GBMR
  • 594
  • 1
  • 7
  • 16
  • Does this answer your question? [Returning data from async call in Swift function](https://stackoverflow.com/questions/25203556/returning-data-from-async-call-in-swift-function) – John Montgomery Jun 19 '20 at 22:12

1 Answers1

1

When the collectionView(_:,numberOfItemsInSection:) function is called, the numberOfPosts variable will be 0 and it will remain the same at the point where this function returns. This is because you don't actually change the numberOfPosts variable in this function, but rather you trigger another function that will change this variable later. Having this said, you won't be able to trigger the query function from within collectionView(_:,numberOfItemsInSection:) and make use of its results (i.e. changing the numberOfPosts variable) in the same function.

Moreover, collectionView(_:,numberOfItemsInSection:) is generally (meaning always) a bad place to start making API calls. They should be performed in functions like viewDidLoad or viewDidAppear.

What you actually want to achieve is to display an empty collection view initially, perform the API call, and when you have the result, you need to update the collection view and populate it with the fetched data.

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        userSubID = AWSMobileClient.default().userSub!
        let post = uploads.keys
        let predicate = post.userSub == userSubID
        _ = Amplify.API.query(request: .list(uploads.self, where: predicate)) { event in
            switch event {
            case .success(let result):
                switch result {
                case .success(let posts):
                    self.numberOfPosts = posts.count 
                    print(numberOfPosts) // It prints the num of posts

                    self.collectionView.reloadData() // Reload the collection view here

                case .failure(let error):
                    print("Got failed result with \(error.errorDescription)")
                }
            case .failure(let error):
                print("Got failed event with error \(error)")
            }
        }
    }
}

extension ViewController: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return self.numberOfPosts
    } 
}

Further, you will most probably need to make use of the actual array to populate the collection view with data, so maybe storing just posts.count won't help you very much. Instead you'll need to store the whole array of posts. But the general idea of making the API call somewhere outside the collection view's function and calling collectionView.reloadData() will remain exactly the same.

Vlad Rusu
  • 1,414
  • 12
  • 17