Reputation: 158
I have a tableview cell that does not load properly. when it loads it is supposed to load the title and the image at the same time, like any normal page. as of now it only loads the images when you click on the cell. and when you click the image it is larger than it's supposed to be. not sure why. it's similar code used in another part of the project and I don't have that issue there. so there it is. not sure if what's going on is related to all those constraints I haven't set yet.
the project is an Amazon clone. the data is called from an api and the images are given as url strings. so I'm loading images from urls and placing them into my image views.
here's a video of what is going on. in the video I wait a few seconds before clicking on the cell to give it a chance to load on its own. in the code where the image is processed from the url there is a print statement that fires around the same time the title is generated so I know the image is created. it's just waiting until it is clicked to appear. not sure why. https://gfycat.com/talkativebackhornet
the page where the code is loaded. this code performs a search and uses the results to form the ProductsDetails struct where the data is displayed. this is basically just the Amazon page you get when you select a product. the image view will later be converted into a horizontal scrolling view once the code is working.
class ProductViewController: UITableViewController {
var asinForSearch: String = ""
var resultsManager = ResultsManager()
var productsDetails = Array<Products>()
{
didSet {
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
resultsManager.detailsDelegate = self
tableView.dataSource = self
tableView.register(UINib(nibName: "ImagesCell", bundle: nil), forCellReuseIdentifier: "imagesCell")
tableView.rowHeight = 750
populateDetailsPage()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return productsDetails.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let productResults = productsDetails[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "imagesCell", for: indexPath) as! ImagesCell
let url = URL(string: productResults.mainImage)
cell.imagioView.kf.setImage(with: url)
cell.title.text = productResults.title
return cell
}
func populateDetailsPage(){
resultsManager.getDetails(asinForSearch)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
extension ProductViewController: ResultsDetailDelegate {
func updateDetails(_ resultsManager: ResultsManager, products: Products){
self.productsDetails.append(products)
}
}
here's the code that creates the cell. not sure if this is necessary.
class ImagesCell: UITableViewCell, UIScrollViewDelegate {
@IBOutlet weak var imageScrollView: UIScrollView!
@IBOutlet weak var title: UILabel!
@IBOutlet weak var imagioView: UIImageView!
@IBOutlet weak var view: UIView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
imageScrollView.delegate = self
imageScrollView.contentSize = CGSize(width: imagioView.frame.width, height: imagioView.frame.height)
self.imageScrollView.addSubview(imagioView)
view.addSubview(imageScrollView)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
func getDetails(_ asin: String){
let search = "\(detailRequest)\(asin)&country=US"
var request = URLRequest(url: URL(string: search)!)
request.httpMethod = "GET"
request.allHTTPHeaderFields = params
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let session = URLSession.shared
let task = session.dataTask(with: request) { data, response, error -> Void in
if let jsonData = data {
do {
let root = try JSONDecoder().decode(ProductDetail.self, from: jsonData)
if let productDetails = self.parseJSONDetails(root.product) {
self.detailsDelegate?.updateDetails(self, products: productDetails)
}
} catch {
print(error)
}
}
}
task.resume()
}
func parseJSONDetails(_ safeData: Products) -> Products? {
do {
let products = Products(asin: safeData.asin, deliveryMessage: safeData.deliveryMessage, productDescription: safeData.productDescription, featureBullets: safeData.featureBullets, images: safeData.images, mainImage: safeData.mainImage, price: safeData.price, productInformation: safeData.productInformation, title: safeData.title, totalImages: safeData.totalImages, totalVideos: safeData.totalVideos, url: safeData.url)
return products
} catch {
print()
}
}
let me know if there's any other code you need to see
Upvotes: 0
Views: 669
Reputation: 2028
You need to let your tableView know that there is new data and it needs to update its cells.
Call self.tableView.reloadData()
when the delegate announces that it finished getting products.
extension ProductViewController: ResultsDetailDelegate {
func updateDetails(_ resultsManager: ResultsManager, products: Products){
self.productsDetails.append(products)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
Remove the reloading from here:
func populateDetailsPage(){
resultsManager.getDetails(asinForSearch)
}
This whole function is useless. It doesn't do anything:
func parseJSONDetails(_ safeData: Products) -> Products? {
do {
let products = Products(asin: safeData.asin, deliveryMessage: safeData.deliveryMessage, productDescription: safeData.productDescription, featureBullets: safeData.featureBullets, images: safeData.images, mainImage: safeData.mainImage, price: safeData.price, productInformation: safeData.productInformation, title: safeData.title, totalImages: safeData.totalImages, totalVideos: safeData.totalVideos, url: safeData.url)
return products
} catch {
print()
}
}
There is no reason why you would instantiate a Products
object from another Products
. At least, I can't understand why it is needed.
You have this ProductDetail
object after you make the network request, then just pass its parameter .products
to the delegate:
func getDetails(_ asin: String){
let search = "\(detailRequest)\(asin)&country=US"
var request = URLRequest(url: URL(string: search)!)
request.httpMethod = "GET"
request.allHTTPHeaderFields = params
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let session = URLSession.shared
let task = session.dataTask(with: request) { [weak self] data, response, error -> Void in
guard let self = self else { return }
if let jsonData = data {
do {
let productDetail = try JSONDecoder().decode(ProductDetail.self, from: jsonData)
let products = productDetail.products
self.detailsDelegate?.updateDetails(self, products: products)
} catch {
print(error)
}
}
}
task.resume()
}
Also, make sure your detailsDelegate
is declared as weak var
, otherwise you risk creating a retain cycle.
Upvotes: 2