I have a tableviewController with 3 cells one for getting image and text from the server and the second for getting only text and the third one for implementing pagination with activity indicator like below in this image the 3 cells image
and this is the response of pagination:
{
"statusCode": 200,
"message": "Success",
"data": {
"result": [
{
"id": 28,
"profileId": 12,
"creatorId": 8,
"postText": "اهلا وسهلا",
"commentsCount": 0,
"interactionsCount": 0,
"createdAt": "2021-03-06T15:45:24.756Z",
"updatedAt": "2021-03-06T15:45:24.756Z",
"profile": {
"id": 12,
"logo": "https://onebusinessqrcode.s3.us-east-2.amazonaws.com/b562b93c-e278-5027-b615-edd399878c1a.jpg",
"name": "abdallah eslah",
"category": "Ecommerce",
"subCategory": "ElectronicMarket"
},
"creator": {
"id": 8,
"name": "abdallah eslah",
"image": "https://onebusinessqrcode.s3.us-east-2.amazonaws.com/0d362ee3-78e3-584a-8c34-6a91afa9dbda.png",
"email": "abdallaheslah@yahoo.com",
"mobile": "201094339599"
},
"media": [
{
"id": 396,
"postId": 28,
"media": "https://onebusinessqrcode.s3.us-east-2.amazonaws.com/2ad0ce30-a387-5c73-846a-eb414108fb72.jpg",
"createdAt": "2021-03-06T15:45:25.438Z",
"updatedAt": "2021-03-06T15:45:25.438Z"
}
]
},
{
"id": 5,
"profileId": 12,
"creatorId": 8,
"postText": "My new product",
"commentsCount": 2,
"interactionsCount": 0,
"createdAt": "2021-03-01T07:13:39.400Z",
"updatedAt": "2021-03-01T07:17:15.905Z",
"profile": {
"id": 12,
"logo": "https://onebusinessqrcode.s3.us-east-2.amazonaws.com/b562b93c-e278-5027-b615-edd399878c1a.jpg",
"name": "abdallah eslah",
"category": "Ecommerce",
"subCategory": "ElectronicMarket"
},
"creator": {
"id": 8,
"name": "abdallah eslah",
"image": "https://onebusinessqrcode.s3.us-east-2.amazonaws.com/0d362ee3-78e3-584a-8c34-6a91afa9dbda.png",
"email": "abdallaheslah@yahoo.com",
"mobile": "201094339599"
},
"media": [
{
"id": 395,
"postId": 5,
"media": "https://onebusinessqrcode.s3.us-east-2.amazonaws.com/74c28cd0-47be-5053-85ca-c887cc36c781.jpg",
"createdAt": "2021-03-01T07:13:40.377Z",
"updatedAt": "2021-03-01T07:13:40.377Z"
}
]
}
],
"thisPage": 1,
"allPages": 1,
"count": 2
}
}
so I used them in request below to get data and implement pagination :
//Used Variables in the request
var posts = [Posts]()
var pictures = [UIImage]()
//Pagination Vars
var allPages = 1
var thisPage = 1
override func viewDidLoad() {
super.viewDidLoad()
self.refreshControl = UIRefreshControl()
self.refreshControl?.addTarget(self, action: #selector(refreshData), for: .valueChanged)
self.refreshData()
}
// MARK: - List All Posts
@objc func refreshData(){
thisPage = 1
loadPosts(page: 1, refresh: true)
}
@objc func loadPosts(page: Int,refresh: Bool = false) {
if refresh {
refreshControl?.beginRefreshing()
}
let profileId = UserDefaults.standard.value(forKey: "id") as? Int ?? 0
var urlBuilder?.queryItems = [
URLQueryItem(name: "profileId", value:"\(profileId)"), URLQueryItem(name: "page", value:"\(page)")
]
guard let url = urlBuilder?.url else { return }
var request = URLRequest(url: url)
let token = UserDefaults.standard.value(forKey: "token") as? String ?? ""
request.httpMethod = "GET"
request.setValue(token, forHTTPHeaderField: "x-auth-token")
// send request
URLSession.shared.dataTask(with: request) { (data, response, error) in
DispatchQueue.main.async {
if refresh {
self.posts.removeAll()
self.refreshControl?.endRefreshing()
}
// error occured
if error != nil {
Helper().showAlert(title: "Server Error", message: error!.localizedDescription, in: self)
return
}
do {
// access data - safe mode
guard let data = data else {
Helper().showAlert(title: "Data Error", message: error!.localizedDescription, in: self)
return
}
// converting data to JSON
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? NSDictionary
guard let parsedJSON = json else {
print("Parsing Error")
return
}
if let data = parsedJSON["data"] as? NSDictionary {
self.allPages = data["allPages"] as? Int ?? 1
let object = Posts()
object.allPages = self.allPages
if let posts = data["result"] as? [NSDictionary] {
for item in posts {
if let interactionsCount = item["interactionsCount"] as? Int {
object.interactionsCount = interactionsCount
}
if let commentCounts = item["commentsCount"] as? Int {
object.commentCounts = commentCounts
}
if let postMedia = item["media"] as? [NSDictionary] {
if postMedia.count > 0 {
let icon_images = postMedia
object.multiImageIcon = icon_images
// self.multiImages_Icon.isHidden = false
if let media = postMedia[0]["media"] as? String {
object.image = media
}
}
}
if let profile = item["profile"] as? NSDictionary {
if profile.count > 0 {
if let name = profile["name"] as? String {
object.name = name
}
if let logo = profile["logo"] as? String {
object.ava = logo
}
}
}
object.text = item["postText"] as? String
object.name = item["name"] as? String
object.date = item["createdAt"] as? String
object.id = item["id"] as? Int
object.ava = item["logo"] as? String
object.commentCounts = item["commentsCount"] as? Int
object.interactionsCount = item["interactionsCount"] as? Int
object.allPages = item["allPages"] as? Int
self.posts.append(object)
self.tableView.reloadData()
}
}
}
} catch {
Helper().showAlert(title: "JSON Error", message: error.localizedDescription, in: self)
return
}
}
}.resume()
}
finally the custom data source:
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if thisPage < allPages && indexPath.row == posts.count - 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: "loading")
return cell!
}else {
let pictureUrl = posts[indexPath.row].image ?? ""
if pictureUrl.isEmpty == true {
//5)=> accessing the text cell from main.storyboard
let cell = tableView.dequeueReusableCell(withIdentifier: "NoPicCell", for: indexPath) as! NoPicCell
cell.fullNameLabel.text = posts[indexPath.row].name?.capitalized ??
UserDefaults.standard.value(forKey: "name") as? String
cell.fullNameLabel.textColor = .label
let postText = posts[indexPath.row].text
cell.postTextLabel.text = postText
cell.postTextLabel.textColor = .label
let dateString = posts[indexPath.row].date
let formatterGet = DateFormatter()
formatterGet.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
let date = formatterGet.date(from: dateString ?? "")
let formatterShow = DateFormatter()
formatterShow.dateFormat = "MMMM dd yyyy - HH:mm"
cell.dateLabel.text = formatterShow.string(from: date ?? Date())
let postStars = posts[indexPath.row].interactionsCount ?? 0
cell.starCountTwo.text = "\(postStars )"
cell.starCountTwo.textColor = .label
let postComments = posts[indexPath.row].commentCounts ?? 0
cell.commentCountOne.text = "\(postComments)"
cell.commentCountOne.textColor = .label
let avaPath = UserDefaults.standard.value(forKey: "logo") as? String
let ava = posts[indexPath.row].ava
Helper().downloadImage(from: (ava ?? avaPath)! , showIn: cell.avaImageViewNoPic, orShow: "user.png")
// Rounded corners
cell.avaImageViewNoPic.layer.cornerRadius = cell.avaImageViewNoPic.frame.width / 2
cell.avaImageViewNoPic.clipsToBounds = true
cell.commentsButton.tag = indexPath.row
cell.starButtonTwo.tag = indexPath.row
cell.optionButton.tag = indexPath.row
pictures.append(UIImage())
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "PicCell", for: indexPath) as! PicCell
let postText = posts[indexPath.row].text
cell.postTextLabel.text = postText
cell.postTextLabel.textColor = .label
cell.fullNameLabel.text = posts[indexPath.row].name?.capitalized ?? UserDefaults.standard.value(forKey: "name") as? String
cell.fullNameLabel.textColor = .label
let dateString = posts[indexPath.row].date
let formatterGet = DateFormatter()
formatterGet.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
let date = formatterGet.date(from: dateString!)
let formatterShow = DateFormatter()
formatterShow.dateFormat = "MMMM dd yyyy - HH:mm"
cell.dateLabel.text = formatterShow.string(from: date!)
let postStars = posts[indexPath.row].interactionsCount ?? 0
cell.starCountPic.text = "\(postStars )"
cell.starCountPic.textColor = .label
let postComments = posts[indexPath.row].commentCounts ?? 0
cell.commentCountOne.text = "\(postComments)"
cell.commentCountOne.textColor = .label
let ava = posts[indexPath.row].ava
let avaPath = UserDefaults.standard.value(forKey: "logo") as? String
Helper().downloadImage(from: (ava ?? avaPath)! , showIn: cell.avaImageViewPic, orShow: "user.png")
// Rounded corners
cell.avaImageViewPic.layer.cornerRadius = cell.avaImageViewPic.frame.width / 2
cell.avaImageViewPic.clipsToBounds = true
cell.commentsButton.tag = indexPath.row
cell.starButtonTwo.tag = indexPath.row
cell.optionButton.tag = indexPath.row
let pictureString = posts[indexPath.row].image
let pictureURL = URL(string: pictureString ?? "")
cell.pictureImageView.kf.setImage(with: pictureURL)
if timelinePosts.count != pictures.count {
}else{
print("Pic cashed")
DispatchQueue.main.async {
}
}
cell.commentsButton.tag = indexPath.row
cell.starButtonTwo.tag = indexPath.row
cell.optionButton.tag = indexPath.row
return cell
}
}
}
the willDisplay method :
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if thisPage < allPages && indexPath.row == posts.count - 1 {
thisPage = thisPage + 1
loadPosts(page: thisPage,refresh: false)
}
}