Issue with passing proper image to tableviewcell - ios

This is my struct...
struct ProductImage {
let id : String
let url : URL
let isDefault : Bool
}
struct Product {
let name : String
let id : String
var images = [ProductImage]()
init(name : String, id: String) {
self.name = name
self.id = id
}
mutating func add(image: ProductImage) {
images.append(image)
}
}
Now I have an image loaded on the collectionview and on the click of a button, I want to pass this image to a tableviewcell. The collectionview does have a couple of labels with name and id which is passed successfully...But how the image can be passed that I'm not able to figure out. Below is what happens so far on the click of the sell button...
func SellBtnTapped(_ sender: UIButton) {
let indexPath = collectionView?.indexPath(for: ((sender.superview?.superview) as! RecipeCollectionViewCell))
let myVC = storyboard?.instantiateViewController(withIdentifier: "productSellIdentifier") as! sellTableViewController
let productObject = productData1[(indexPath?.row)!]
if selectedItems == nil {
//selectedItems is an array which will hold all struct items.
selectedItems = [Product(name:productObject.name, id: productObject.id)]
} else {
selectedItems?.append(productObject)
}
myVC.arrProduct = selectedItems
navigationController?.pushViewController(myVC, animated: true)
}
This is how I'm assigning the images and other data in the tableviewcell. This is the code of cellForRow..(of the tableview from where the cells are loaded..)
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: sellTableViewCell = tableView.dequeueReusableCell(withIdentifier: "sellProductIdentifier") as! sellTableViewCell
//cell.prdImgView?.image =.... by doing this, the images are displayed in the tableviewcell in the same order as they are displayed in the collectionview cells irresoective of which cell was clicked. i.e clicking on btn on 1st collection view item shows the image on that collection view item on the tableviewcell.And when I click on the btn on the 4th collectionview item the image shown on the tableview cell will be that of the 2nd collectionview item...
cell.prdImgView?.image = self.appDelegate.commonArrayForURLImages[indexPath.row]
let product = arrProduct?[indexPath.row]
cell.produvtNameLabel.text = product?.name
cell.rateTextField.text = product?.theRate
return cell
}
This is how the array(which is passed to the tableview cell) gets the images...
var theProduct = Product(name: name, id: id, theRate: rate, quantity: qty, sku: skuCode, prdCateg: prodCat, prodDescr: description)
if let images1 = anItem["product_images"] as? [[String:String]] {
for image in images1 {
guard let imageId = image["id"],
let url1 = image["image"],
let isDefault = image["is_default"] else { continue }
let productImage = ProductImage(id: imageId, url: URL(string: url1)!, isDefault: isDefault == "1")
theProduct.add(image: productImage)
self.productData1.append(theProduct)
self.imgData.append(productImage)
let url = URL(string: url1)
if let data = try? Data(contentsOf: url!) {
let img = UIImage(data: data)
print(img!)
self.arrayOfURLImages.append(img!)
}
self.appDelegate.commonArrayForURLImages = self.arrayOfURLImages
}
}

Structs provide you with member wise initialiser, so in most cases you don't need one of your own.In your code your product initialiser is only holding name and id, and not array of productImage, You seem to be having a separate function for holding that data, which i think is not needed here.So what I did is just created a array type for [ProductImages] and sticked with default initialiser.
import Foundation
struct ProductImage {
let id : String?
let url : String? // Keep this string
let isDefault : Bool?
}
struct Product {
let name : String?
let id. : String?
var images : [ProductImage]?
}
ControllerClass(with collection view getting initial data)-:
In your controller class I created 2 arrays -:
1) That holds data for images .
2) That holds data for entire product information.
For saving data I am just passing constant values for now. In viewDidLoad I called initialiser for each object -:
1) Holding images object data.
2) ProductObject data .
3) Append both object to appropriate arrays.
import UIKit
class MyViewController: UIViewController {
#IBOutlet weak var mainCollectionView: UICollectionView!
// ARRAY OBJECT OF TYPE PRODUCT AND PRODUCT IMAGE
var imageData = [ProductImage]()
var productData = [Product]()
//viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
modelDataForCollectionView()
}
func modelDataForCollectionView(){
// GET IMAGE DATA
let imageObject = ProductImage(id: "1", url: "your url", isDefault: true)
imageData.append(imageObject)
// MODEL FOR PRODUCTS
let productObject = Product(name: "", id: "", images: imageData)
productData.append(productObject)
}
//didReceiveMemoryWarning
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
// MyViewController extending collection view
extension MyViewController :UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout{
//numberOfItemsInSection
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int{
return productData.count
}
//dequeueReusableCell
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionCell
cell.sendButton.addTarget(self, action: #selector(sendDataToTable), for: UIControlEvents.touchUpInside)
return cell
}
//numberOfSections
func numberOfSections(in collectionView: UICollectionView) -> Int{
return 1
}
// sizeForItemAt for each row
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize{
return CGSize(width: view.frame.width, height: 200)
}
func sendDataToTable(sender:UIButton){
let index = mainCollectionView.indexPath(for: sender.superview?.superview as! CollectionCell)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let Controller = storyboard.instantiateViewController(withIdentifier: "tableData") as! ViewController1
Controller.dataForTableView = productData[(index?.row)!].images
self.navigationController?.pushViewController(Controller, animated: true)
}
}
Now when you tap on a button in UICollectionViewCell , get the tapped index , and read product object present at that index from Product array.After that you can easily pass required data to table view(Second class).
Second controller class-:
import UIKit
class ViewController1: UIViewController {
// ARRAY TO HOLD IMAGE DATA FOR TAPPED COLLECTION CELL
var dataForTableView:[ProductImage]?
var name : String?
var id : String?
#IBOutlet weak var secondTable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
// CHECK FOR DATA
print(dataForTableView?[0].url as Any) // Optional("your url")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension ViewController1 : UITableViewDelegate,UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell1") as! testingCell2
return cell
}
// Number of sections in table
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}// Default is 1 if not implemented
public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat{
return 50
}
}
Once you get image URL and any other required information in second class, you can present that on table easily. To get images make api call to server. I hope that helps you.
Code for parsing-:
var imageUrl:String?
var imageId:String?
var isDefaults:String?
var productId:String?
var productIdTitle:String?
var productIdImageWithPath:String?
//MARK : Call Back Delegate Methods
func apiSuccessResponse(_ response: Dictionary<String, AnyObject>) {
print(response)
if let actualStyleData = response["Productdata"] as? [Dictionary<String, AnyObject>]{
for object in actualStyleData{
if let id = object["product_id"] as? String{
productId = id
}else{
productId = ""
}
if let title = object["product_name"] as? String{
productIdTitle = title
}
if let imageDetails = object["product_images"] as? [Dictionary<String, AnyObject>]{
for details in imageDetails{
if let id = details["id"] as? String{
imageId = id
}
if let url = details["image"] as? String{
imageUrl = url
}
if let isDefault = details["is_default"] as? String{
isDefaults = isDefault
}
let saveImageObject = ProductImage(id: imageId, url: imageUrl, isDefault: isDefaults)
imageData.append(saveImageObject)
}
}
let saveProductObject = Product(name: productIdTitle, id: productId, images: imageData)
productData.append(saveProductObject)
}
}
}

Related

Delete cell from tableView and data from Firestore iOS

I'm making an restaurant app where I have restaurant which contains food. I have the following problem. From each restaurant, I can add food into my shopping cart, but when im trying to swipe left to delete a cell, close the cart and re-enter in the cart, is deleting all the cart, not the cell I have selected for swipping
This is my model :
struct Cart
{
var photoKeyCart: String
var foodCart: String
var priceCart: Int
}
This is the function im using for retrieving the data from Firestore and displaying it into the cart. This function is called in the viewdidload() .
func getCartProducts() {
let db = Firestore.firestore()
let userID = (Auth.auth().currentUser?.uid)!
db.collection("CartDatabase").document(userID).collection("CartItems").getDocuments { (document, error) in
if let error = error {
print(error)
return
} else {
for document in document!.documents {
let data = document.data()
let newEntry = Cart(photoKeyCart: data["photoKeyCart"] as! String, foodCart: data["foodCart"] as! String , priceCart: data["priceCart"] as! Int
)
self.cart.append(newEntry)
}
}
DispatchQueue.main.async {
// self.datas = self.filteredData
self.cartTableView.reloadData()
}
}
}
Viewdidload function :
override func viewDidLoad() {
super.viewDidLoad()
getCartProducts()
let nib = UINib(nibName: "CartTableViewCell", bundle: nil)
cartTableView.register(nib, forCellReuseIdentifier: "CartTableViewCell")
cartTableView.delegate = self
cartTableView.dataSource = self
}
Table view extension :
extension CartViewController: UITableViewDelegate, UITableViewDataSource
{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var sum = 0
for item in cart{
sum += item.priceCart
}
priceTotalLabel.text = "\(sum) lei"
return cart.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = cartTableView.dequeueReusableCell(withIdentifier: "CartTableViewCell", for: indexPath) as! CartTableViewCell
let carts = cart[indexPath.row]
let storageRef = Storage.storage().reference()
let photoRef = storageRef.child(carts.photoKeyCart)
cell.foodInCartPrice.text = " \(carts.priceCart) lei "
cell.foodInCartName.text = carts.foodCart
cell.foodInCartImage.sd_setImage(with: photoRef)
cell.foodInCartImage.layer.borderWidth = 1
cell.foodInCartImage.layer.masksToBounds = false
cell.foodInCartImage.layer.borderColor = UIColor.black.cgColor
cell.foodInCartImage.layer.cornerRadius = cell.foodInCartImage.frame.height/2
cell.foodInCartImage.clipsToBounds = true
return cell
}
This is the function im using for swiping left and trying to delete the cell, but it deletes all my cells. I think the problem is that is deleting all the data from the database, and when the function is called, it have nothing to retrieve.
Database used : Tap here

Passing array of data from collection view to table view

I need to pass my array of ProductNames, to ProductSelectionViewController(VCB) From HomeViewController(VCA)
The issue is that it will only pass the first item. Ex:
If I tap on the cell called "ITEM 1" it passes only "Alk1" rather than "Alk1", "Alk2", "Alk3"
I used print statements and it is passing the Parameter correctly, I can't grasp the reason it will not pass the entire array.
NOTE: segue is from the cell in storyboard to the second VC
The Data Model:
class Parameter {
var parameterName: String
var productName: [String]
init(parameterName: String, productName: [String] = []) {
self.parameterName = parameterName
self.productName = productName
}
}
Home View Controller (VCA):
var parameters: [Parameter] = [
Parameter(parameterName: "Item1", productName: ["Alk1", "Alk2", "Alk3"]),
Parameter(parameterName: "Item2", productName: ["Cal1", "Cal2", "Cal3"]),
Parameter(parameterName: "Item3", productName: ["mag1", "mag3", "mag2"])
]
// MARK: - View life cycle
override func viewDidLoad() {
super.viewDidLoad()
prepareCollectionView()
}
// MARK: - UICollectionViewDataSource
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return parameters.count
}
#objc override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ParameterCell.identifier, for: indexPath) as? ParameterCell
else { preconditionFailure("Failed to load collection view cell") }
cell.parameter = parameters[indexPath.row]
cell.backgroundColor = colors[indexPath.row]
return cell
}
// MARK: - UICollectionView Delegates
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let productViewController = segue.destination as? ProductSelectionViewController else {
fatalError()
}
if segue.identifier == HomeViewController.productSegueIdentifier {
if let indexPaths = collectionView.indexPathsForSelectedItems {
let indexPath = indexPaths[0]
print("\(String(describing: indexPath))")
let productList = parameters[indexPath.row] as Parameter
productViewController.products = [productList]
}
}
}
The ProductSelectionViewController (VCB)
class ProductSelectionViewController: UITableViewController {
var products = [Parameter]()
override func viewDidLoad() {
super.viewDidLoad()
// label.text = products?.parameterName
print("The sent data is: \(products)")
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("Amount of Product \(products.count)")
return products.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let productItem = products[indexPath.row].productName
cell.textLabel?.text = productItem![indexPath.row]
//let p = products.productNames
//ce/ll.textLabel?.text = p[indexPath.row]
return cell
}
I expect the table view to present an array of the items being sent. i.e if Item 1 is tapped, the table view should represent "Alk1, Alk2, Alk3" for a total of three cells.
I am only getting one cell for "Alk1"
in numberOfRowsInSection, I used a print statement to see how many object are counted with
print("There are \(products.count) items")
return output:
There are 1 items
There are 1 items
There are 1 items
Yes,
On your prepareForSegue you create an array with [productList] but product list is only one item, the one that got selected, not the names it has inside.
In your ProductSelectionViewController then use products.productName.count because thats the array you want and in cellForRow do let productItem = products[0].productName[indexPath.row] so you can get the correct one.
But you can improve your code way more if you pass the correct array of productNames instead of creating an array manually and inserting the one Parameter object instead of the productNames it contains
let productList = parameters[indexPath.row] as Parameter
let names: [String] = productList.productName
productViewController.products = names

Tapped cell in UITableView returns label text from last cell out of an array not the chosen one

I have fixed my earlier problem and have now worked out where the main problem is, I am pulling in a json array with alamofire but am not sure how to properly move the data from one viewcontroller to another. If I hardcode the array with var name = ["Hello", "Goodbye"] I can get it to work but am not sure how to do it with the json. Thank you to any and all help.
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let URL_GET_DATA = "http://www.localnewsplus.com.au/ios/service.php"
#IBOutlet weak var tableViewHeroes: UITableView!
var heroes = [Hero]()
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return heroes.count
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ViewControllerTableViewCell
let hero: Hero
hero = heroes[indexPath.row]
cell.labelName.text = hero.name
cell.labelTeam.text = hero.team
Alamofire.request(hero.imageUrl!).responseImage { response in
if let image = response.result.value {
cell.heroImage.image = image
}
}
//cell.labelName.text = name[indexPath.row]
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
Alamofire.request(URL_GET_DATA).responseJSON { response in
if let json = response.result.value {
let heroesArray : NSArray = json as! NSArray
for i in 0..<heroesArray.count{
self.heroes.append(Hero(
name: (heroesArray[i] as AnyObject).value(forKey: "st_heading") as? String,
team: (heroesArray[i] as AnyObject).value(forKey: "st_modified") as? String,
imageUrl: (heroesArray[i] as AnyObject).value(forKey: "imageurl") as? String
))
}
self.tableViewHeroes.reloadData()
}
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = storyboard?.instantiateViewController(withIdentifier: "articleViewController") as? articleViewController
vc?.article_st_heading = name[indexPath.row]
self.navigationController?.pushViewController(vc!, animated: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
There are 2 ways to do this
Try to get data from the array which you used in cellForRow to populate data
Let text = someArray[indexPath. Row]
Get the cell instead of the create new one in didSelect method
Let cell = table. CellForRowAt[indexPath ]
Let text = cell.text

How to compare the data from current cell with its previous cell inside TableView Swift 4?

I have a JSON is look some thing like this :
"product": [
{
"product_id": 471,
"info": "123456",
},
{
"product_id": 471,
"info": "356697456",
},
{
"product_id": 472,
"info": "1432",
},
{
"product_id": 473,
"info": "4321",
},
]
I want to set my TableView to look something like this image below :
what I want is:
If the first cell in the TableView I want the Product 1 (in Red color) shown.
If the second cell's product_id is same with it previous cell's product_id then Product 1 is no longer shown, it disappears.
Since the 3rd cell's product_id is not same with previous cell (second cell), so the red label Product 2 is shown up.
Same go to Product 3 and the rest of the cell in the TableView
What I already tried:
In order to achieve this,I need to get the indexPath inside cellAtRow delegate,so I compare each cell's product_id with the previous one,and then control the logic inside.
Here is my code
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! MyCell
let thisIndexPath = indexPath.row
if thisIndexPath - 1 > -1 {
let previousProductId = self.productItem[thisIndexPath - 1].productId
let thisProductId = self.productItem[thisIndexPath].productId
if previousProductId == thisProductId {
cell.productLabel.isHidden = true
cell.productHeight.constant = 0
cell.productnameTopContraint.constant = 0
cell.productnameBottomContraints.constant = 0
}else {
cell.productnameLabel.isHidden = false
}
}else{
cell.productnameLabel.isHidden = false
}
cell.item = selfProductItem[indexPath.row]
return cell
}
}
But now the problem is:
-- When the TableView first launch,the UI display like that I shown above,but when I start scrolling,all the cell's Product label(in red color) is gone,although the product_id is not same with the previous cell's product_id.
-- When I scroll back to the first cell,the Product Label(In red color) is gone as well.Which means the UI is only right at first launch of the screen,which is not persistent.
So my question is:
What is the correct way to compare data from current cell to the previous cell?
Is it right to do the comparison inside cellForRowAt delegate method?If not,where should I do this?
I think that to solve your issue, you should think about how you will store your JSON data.
You could begin by creating a struct called 'Product' which will store the product information and then by making it Equatable you can add a function which will allow you to compare the productID's:
/// Structure Of A Product
struct Product: Equatable{
var productID: Int
var productInfo: Int
static func == (lhs: Product, rhs: Product) -> Bool {
return lhs.productID == rhs.productID
}
}
Now to use this your structure you can create an Array variable to store your Products:
//Array To Store Array Of Product
var products = [Product]()
In this example I am just manually inputting the product information but you should handle this in a better way. However, it does illustrate one way you could 'start' to handle this:
override func viewDidLoad() {
super.viewDidLoad()
//1. Create Products
let productOne = Product(productID: 471, productInfo: 123456)
let productTwo = Product(productID: 471, productInfo: 356697456)
let productThree = Product(productID: 472, productInfo: 1432)
let productFour = Product(productID: 473, productInfo: 4321)
//2. Add Them To The Products Array
addUnique(productOne)
addUnique(productTwo)
addUnique(productThree)
addUnique(productFour)
}
/// Checks That A Product Doesn't Exist
///
/// - Parameter product: Product
func addUnique(_ product: Product) {
if !products.contains(product) {
products.append(product)
}
}
In Step 1 we are manually creating the products.
In Step 2 we are calling the addUnique(_ product) function which will only allow unique Products to be stored.
After ensuring that there are no duplicate ProductID's, it should be easy for you to set the format as you like:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! MyCell
cell.productLabel.text = products[indexPath.row].productID
cell.productnameLabel.text = products[indexPath.row].productInfo
}
Of course you will need to fix any colouring of labels etc.
I tried and it is working fine. I make one dummy array for you. Please check bellow
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tblProduct: UITableView!
var arrProduct = NSMutableArray()
var arrForSection = NSMutableArray()
var arrForProductId = NSMutableArray()
override func viewDidLoad()
{
super.viewDidLoad()
let dict = NSMutableDictionary()
dict.setValue("471", forKey: "product_id")
dict.setValue("123456", forKey: "info")
arrProduct.add(dict)
let dict1 = NSMutableDictionary()
dict1.setValue("471", forKey: "product_id")
dict1.setValue("356697456", forKey: "info")
arrProduct.add(dict1)
let dict2 = NSMutableDictionary()
dict2.setValue("472", forKey: "product_id")
dict2.setValue("1432", forKey: "info")
arrProduct.add(dict2)
let dict3 = NSMutableDictionary()
dict3.setValue("472", forKey: "product_id")
dict3.setValue("4321", forKey: "info")
arrProduct.add(dict3)
print(arrProduct)
self.createSection()
}
//MARK:
//MARK: Create section
func createSection()
{
arrForSection.removeAllObjects()
let arrtemp = NSMutableArray()
arrtemp.addObjects(from: (self.arrProduct as NSArray) as! [Any])
for i in 0 ..< arrtemp.count
{
let dict = self.arrProduct[i] as! NSMutableDictionary
let strProductId = (dict["product_id"] as? String)!
if(!arrForProductId .contains(strProductId))
{
arrForProductId.add(strProductId)
}
}
for j in 0 ..< arrForProductId.count
{
let strTempDate:String = arrForProductId .object(at: j) as! String
let arr1 = NSMutableArray()
for i in 0 ..< arrtemp.count
{
let dict = arrtemp .object(at: i) as! NSMutableDictionary
let strProductId = (dict["product_id"] as? String)!
if(strProductId == strTempDate)
{
arr1.add(dict)
}
}
arrForSection.add(arr1)
}
self.tblProduct.reloadData()
}
//MARK:
//MARK: TableView Delegate
func numberOfSections(in tableView: UITableView) -> Int {
return self.arrForSection.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return (((arrForSection .object(at: section)) as! NSMutableArray).count)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell:UITableViewCell = self.tblProduct.dequeueReusableCell(withIdentifier: "cell")!
let dictData = ((arrForSection .object(at: indexPath.section)) as! NSMutableArray).object(at: indexPath.row) as! NSDictionary
cell.textLabel?.text = dictData["info"] as? String
return cell
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?
{
return arrForProductId[section] as? String
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Result see attach
Hope it helps!
I think in this case you can divide cells of your table view in sections and assign header (name of product) to each section. Please rever to official documentation for more information.
try setting the height constraints in else part too.
else part of this : if previousProductId == thisProductId { and this : if thisIndexPath - 1 > -1 {.

Trying to implement GCD and concurrency on a table view

Currently using Alamofire synchronously within cellForRowAtIndexPath that queries a JSON array from Heroku, and within a for loop, creates a struct from each JSON object within the JSON array with image and text properties and then appends each struct in an array property within the table view controller. Not surprising that this is really slow. On app launch, the initial VC is a container VC that either shows a navigation controller or page VC based on if the user is "logged in." The initial VC in the page VC is a container VC that holds the table VC in question.
I'm totally new to GCD and the concept of concurrency. Was wondering how I can populate my array that serves as the foundational data for each of the table view cells.
Here's my current code - changing some variable names because I signed an NDA for this project:
import UIKit
import Alamofire
import Alamofire_Synchronous
final class PopularPearsTableViewController: UITableViewController {
let screenSize: CGRect = UIScreen.main.bounds
var pears: [Pear] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(PopularPearTableViewCell.self, forCellReuseIdentifier: "popularPear")
tableView.rowHeight = (screenSize.height) * 0.3
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
// MARK: - Table View Data Source
extension PopularShopsTableViewController {
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// just a stub, will be replaced with dynamic code later on
return 5
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print(#function)
let cell = tableView.dequeueReusableCell(withIdentifier: "popularPear", for: indexPath) as! PopularPearTableViewCell
let userDefaults = UserDefaults.standard
guard let pearUUID = userDefaults.string(forKey: "pearUUID"),
let pearToken = userDefaults.string(forKey: "pearToken")
else {
return cell
}
if indexPath.row == 0 {
let header = createAuthenticatedHeader(user: pearUUID, password: pearToken)
let pearResponse = Alamofire.request("url", headers: header).responseJSON()
if let pearsFromResponse = (pearResponse.result.value! as! JSON)["data"] as? [JSON] {
for pear in pearsFromResponse {
let name = pear["name"] as! String
let pictureURL = pear["picture_url"] as! String
let imageURL = URL(string: pictureURL)
let imageData = NSData(contentsOf: imageURL!)
let image = UIImage(data: imageData as! Data)!
let newPear = Pear(name: name, image: image)
self.pears.append(newPear)
}
}
}
cell.giveCell(pearImage: pears[indexPath.row].image, pearName: pears[indexPath.row].name)
return cell
}
}

Resources