[Swift 4] Đổ dữ liệu vào tableView từ API
Bài đăng này đã không được cập nhật trong 6 năm
Xin chào các bạn.
Trong phần trước mình đã giới thiệu cách autolayout một tableView bằng code, và ở phần này mình sẽ pass data từ API vào từng cell trong tableView đã tạo nhé.
Mình sử dụng free API này: https://jsonplaceholder.typicode.com/photos Gồm có các trường:
albumId:
id:
title:
url:
thumbnailUrl:
Và mình sẽ tạo Model tương ứng,
struct ImageModel: Decodable {
var albumId: Int?
var id: Int?
var title: String?
var url: String?
var thumbnailUrl: String?
}
Sau đó tạo function fetchImage() tại ViewController để lấy data về.
func fetchImage(completion: @escaping ([ImageModel]) -> ()) {
let urlSring = "https://jsonplaceholder.typicode.com/photos"
guard let url = URL(string: urlSring) else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
let decoder = JSONDecoder()
do {
guard let data = data else { return }
let dataArray = try decoder.decode([ImageModel].self, from: data)
DispatchQueue.main.async {
completion(dataArray)
}
} catch {
print(error)
}
}.resume()
}
Trong function trên mình có sử dụng closure completion và đưa data lấy được vào main thread để đổ ra view.
Các bạn tham khảo thêm closure tại đây nhé.
Vì mình truyền 1 array [ImageModel] vào tableView nên phải khai báo [ImageModel] trong tableView.
var images: [ImageModel]?
Và mỗi cell sẽ có một ImageModel nên mình cũng khai báo luôn trong CustomCell.
var img: ImageModel?
Sau đó sử dụng func fetchImage() tại viewDidLoad() trong ViewController và truyền toàn bộ data vào mainTableView.
fetchImage { (images) in
self.mainTableView.images = images
self.mainTableView.reloadData()
}
Khi này mainTableView sẽ có số row tương ứng với số item nhận được.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let images = self.images {
return images.count
}
return 0
}
Và mỗi cell sẽ tương ứng với 1 phần tử trong array có index tương ứng là indexPath.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellID", for: indexPath) as! CustomCell
if let images = self.images {
cell.img = images[indexPath.item]
}
return cell
}
Sau đó trong file CustomCell mình sẽ update layout. Đầu tiên thử với title trước nhé. Sau khi biến img nhận được dữ liệu hàm didSet sẽ thực thi. cụ thể về didSet tại đây.
var img: ImageModel? {
didSet {
cellLabel.text = img?.title
}
}
Kết quả Rât kinh. Và mình cần sửa 1 chút layout cho Label. Đầu tiên trong ViewController mình để mainTableView Full màn hình bằng cách bỏ toàn bộ constant trong constraint
self.view.addSubview(mainTableView)
mainTableView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
mainTableView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
mainTableView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
mainTableView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
Tiếp theo trong file CustomCell mình bỏ backgroundColor của Label đi vì màu da cam thấy gớm =.=
Sau đó sửa lại constraint của label như sau. Cạnh trái của label cách cạnh phải của image 5px. Cạnh trên của label cách cạnh trên của cell contentView 5px. Tương tự vậy cạnh phải và cạnh đáy của label cách cạnh phải và cạnh đáy của cell contentView 5px.
contentView.addSubview(cellLabel)
cellLabel.leadingAnchor.constraint(equalTo: cellImage.trailingAnchor, constant: 5).isActive = true
cellLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -5).isActive = true
cellLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 5).isActive = true
cellLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -5).isActive = true
Kết quả
Phần label vừa sửa có vẻ có học hơn rồi.
Tiếp theo mình sẽ đổ ảnh vào từng cell.
Image từ API trả về có dạng như sau.
url: "http://placehold.it/600/92c952",
thumbnailUrl: "http://placehold.it/150/92c952"
url: là link fullsize của image.
thumbnailUrl: là ảnh thumbnail. Mình sẽ đổ ảnh thumbnail vào từng cell trong tableView.
Trong file CustomCell
var img: ImageModel? {
didSet {
guard let img = img else { return }
guard let thumbnailString = img.thumbnailUrl else { return }
cellLabel.text = img.title
if let thumbnailUrl = URL(string: thumbnailString) {
let data = try! Data(contentsOf: thumbnailUrl)
cellImage.image = UIImage(data: data)
}
}
}
Kết quả
Hôm nay mình dừng ở đây nhé. Bài tới mình sẽ khắc phục hiện tượng load lâu, cell bị chồng chéo nhé các bạn.
Source: https://gitlab.com/nguyentienhoang810/Viblo-TableView
All rights reserved