I'm trying to retrieve an item from a table (TheUserIds2018) of Amazon DynamoDB, and I would like to pass the item to be the numberOfItemsInSection of the UICollectionViewCell, here is the table TheUserIds2018 looks like:
Here are the codes:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
let dynamoDbObjectMapper = AWSDynamoDBObjectMapper.default()
dynamoDbObjectMapper.load(TheUserIds2018.self, hashKey: "TheUserIds2018", rangeKey: nil, completionHandler: { (objectModel: AWSDynamoDBObjectModel?, error: Error?) -> Void in
if let error = error {
print("Amazon DynamoDB Read Error: \(error)")
return
}
if let count = objectModel?.dictionaryValue["_articleCounters"] {
self.counters = count as! Int
}
self.collectionView?.reloadData()
})
}
here is the numberOfItemsInSection:
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.counters
}
But there is no collectionViewCell displaying in the screen when I build and run the app, it's blank:
I know the reason is that the collectionViewCell launches before than viewWillAppear. So I tried the following way, but sometimes it will crash (with the error: Thread 1: Fatal error: Index out of range
):
Here are the working codes:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
self.view.addSubview(activityView)
activityView.hidesWhenStopped = true
activityView.center = self.view.center
activityView.startAnimating()
let dynamoDbObjectMapper = AWSDynamoDBObjectMapper.default()
dynamoDbObjectMapper.load(TheUserIds2018.self, hashKey: "TheUserIds2018", rangeKey: nil, completionHandler: { (objectModel: AWSDynamoDBObjectModel?, error: Error?) -> Void in
if let error = error {
print("Amazon DynamoDB Read Error: \(error)")
return
}
DispatchQueue.main.async {
if let count = objectModel?.dictionaryValue["_articleCounters"] {
print("Count: \(count)")
self.counters = count as! Int
self.collectionView?.reloadData()
if self.counters > 10 {
self.updateItems()
} else {
self.getItems()
}
self.activityView.stopAnimating()
}
}
})
}
func getItems() {
let dynamoDbObjectMapper = AWSDynamoDBObjectMapper.default()
var tasksList = Array<AWSTask<AnyObject>>()
for i in 1...10 {
tasksList.append(dynamoDbObjectMapper.load(RecommendArticles.self, hashKey: "userId" + String(11 - i), rangeKey: nil))
}
AWSTask<AnyObject>.init(forCompletionOfAllTasksWithResults: tasksList).continueWith { (task) -> Any? in
if let cards = task.result as? [RecommendArticles] {
self.card = cards
print("cards counter: \(cards.count)")
} else if let error = task.error {
print(error.localizedDescription)
}
return nil
}
}
func updateItems() {
let dynamoDbObjectMapper = AWSDynamoDBObjectMapper.default()
var tasksList = Array<AWSTask<AnyObject>>()
for i in 1...self.counters {
tasksList.append(dynamoDbObjectMapper.load(RecommendArticles.self, hashKey: "userId" + String(self.counters + 1 - i), rangeKey: nil))
}
AWSTask<AnyObject>.init(forCompletionOfAllTasksWithResults: tasksList).continueWith { (task) -> Any? in
if let cards = task.result as? [RecommendArticles] {
self.card = cards
print("Real cards counter: \(cards.count)")
} else if let error = task.error {
print(error.localizedDescription)
}
return nil
}
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.counters
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: verticalCellId, for: indexPath) as! VerticalCellId
if let link = self.card?[indexPath.item]._imageURL {
let url = URL(string: link)
cell.photoImageView.kf.setImage(with: url)
}
}
PS: There are two different tables in my AWS DynamoDB: TheUserIds2018 and RecommendArticles. Here is what the RecommendArticles looks like:
Any other way to retrieve the item from the table (TheUserIds2018), and then pass it to be the numberOfItemsInSection?
Update: after adding self.collectionView?.reloadDate()
to main thread, it works well in most cases, but it sometimes crashes if try to scroll down immediately after the app launches, especially when in a bad internet connection. Same error: Thread 1: Fatal error: Index out of range
. Any way to fix this?
Final Update: Finally, with the help of @Rohi, it works now. I have updated the codes to date.
Call reloadData() after you assign to self.counters in main thread it will work. Not before assigning self.counters.