Passing array of data from collection view to table view - ios

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

Related

Swift - Sort different arrays accordingly to date array

I have 3 user input fields which each create a different array. These arrays are being used to fill a UITableViewCell. My intention is to sort the added cells by date.
One of the input fields contains a date which shall be used to sort this table. To also display the date, the array is of type String, hence the dates are formatted to String.
Let's say I would not directly format it to String and sort it before I do. Is there a way to sort the other arrays according to the Date array?
import UIKit
class NotificationViewController: UIViewController {
let defaults = UserDefaults.standard
#IBOutlet weak var toolbar: UIToolbar!
#IBOutlet weak var notificationView: UITableView!
var isVisible = false
var descArray: [String] = []
var titleArray: [String] = []
var dateArray: [String] = []
var typeArray: [Int] = []
override func viewDidLoad() {
super.viewDidLoad()
declareArrays()
print(dateArray)
self.toolbar.setBackgroundImage(UIImage(),
forToolbarPosition: .any,
barMetrics: .default)
self.toolbar.setShadowImage(UIImage(), forToolbarPosition: .any)
notificationView.delegate = self
notificationView.dataSource = self
}
func declareArrays() {
descArray = getDesc()
titleArray = getTitle()
dateArray = getDate()
typeArray = getType()
}
func getDesc() -> [String] {
return descNotificationArray
}
func getTitle() -> [String] {
return titleNotificationArray
}
func getDate() -> [String] {
return dateNotificationArray
}
func getType() -> [Int] {
return notificationTypeArray
}
#IBAction func goBack(_ sender: Any) {
performSegue(withIdentifier: "goBackToMain", sender: self)
}
#IBAction func addNotification(_ sender: Any) {
performSegue(withIdentifier: "goToType", sender: self)
}
}
extension NotificationViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dateArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let date = dateArray[indexPath.row]
let title = titleArray[indexPath.row]
let desc = descArray[indexPath.row]
let notType = typeArray[indexPath.row]
if notType == 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: "TuvTableViewCell") as! TuvTableViewCell
cell.setTitle(title: title)
cell.setDesc(desc: desc)
cell.setDate(date: date)
return cell
} else if notType == 2 {
let cell = tableView.dequeueReusableCell(withIdentifier: "ServiceNotTableViewCell") as! ServiceNotTableViewCell
cell.setTitle(title: title)
cell.setDesc(desc: desc)
cell.setDate(date: date)
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "NotificationViewCell") as! NotificationViewCell
cell.setTitle(title: title)
cell.setDesc(desc: desc)
cell.setDate(date: date)
return cell
}
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == .delete) {
dateArray.remove(at: indexPath.item)
titleArray.remove(at: indexPath.item)
descArray.remove(at: indexPath.item)
descNotificationArray.remove(at: indexPath.item)
dateNotificationArray.remove(at: indexPath.item)
titleNotificationArray.remove(at: indexPath.item)
defaults.set(descNotificationArray, forKey: "descNotificationArray")
defaults.set(dateNotificationArray, forKey: "dateNotificationArray")
defaults.set(titleNotificationArray, forKey: "titleNotificationArray")
tableView.deleteRows(at: [indexPath], with: .automatic)
}
}
}
Edit:
Ok, I've added an struct and a func which appends the input to the array and sorts it:
struct not {
var title: String
var desc: String
var Date: Date
}
func appendToStructArray() {
let notificationData: not = not(title: notifTitle.text!, desc: notifDescribtion.text!, Date: datePicker.date)
notStructArray.append(notificationData)
notStructArray.sort(by: { $0.Date < $1.Date })
}
Now in the TableViewController: How do I manage to get the data from one struct inside of the array and add it to a cell just like I did it previously with my arrays?
The proper solution is to have one array, not four. Create a struct with 4 properties. Then have one array of that struct. Then it becomes trivial to add, remove, sort, and filter the array as needed to populate your table view.
Instead using all those arrays, you might consider using another type that comprises all of those, something like:
struct Foo {
let date: Date
let desc: String
let type: String
let title: String
}
Then you would have an array of foos that you could sort by date. That way everything would be sorted without the need of handling different arrays.

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 {.

Pass array from tableview to tableview [duplicate]

This question already has answers here:
Passing Data between View Controllers in Swift
(7 answers)
Closed 5 years ago.
Objective: Pass an array of information from tableview to another tableview using the data created.
Problem: Couldn't access the array information from TableViewController in preparingForSegue
Result: TableViewController contains employee names, and when click on each of the employee, it goes to the details of showing arrays of information.
1) Employee.swift (model for data)
struct Employee {
var name: String
var food: [String]
var ingredients: [String]
init(name: String, food: [String], ingredients: [String]) {
self.name = name
self.food = food
self.ingredients = ingredients
}
}
2) TableViewController.swift (shows the name of the employee)
Everything is working well here with the codes, the only thing that I am struggling here is passing the information to the next viewcontroller. In the comment section is where I tried typing destination.food = lists[indexPath.row].food. This didn't work as expected. I am trying to retrieve the array information.
class VillageTableViewController: UITableViewController {
var lists : [Employee] = [
Employee(name: "Adam" , food: ["Fried Rice","Fried Noodles"], ingredients: ["Insert oil, cook","Insert oil, cook"])]
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showVillages" {
if let indexPath = self.tableView.indexPathsForSelectedRows {
let destination = segue.destination as? DetailsViewController
// pass array of information to the next controller
}
}
}
3) DetailsTableViewController.swift (shows an array of information)
Code is working fine. I have the idea of creating an empty array and the information will be passed from TableViewController. In the comment section, I will then write cell.textLabel?.text = food[indexPath.row] and cell.subtitle?.text = ingredients[indexPath.row]
class DetailsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var food:[String] = []
var ingredients:[String] = []
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! DetailsTableViewCell
//this is where I will get the information passed from the array
return cell
}
Please advise. I've been researching for the past few hours and couldn't figure it out yet. Bear in mind that all the code works fine here and I've only struggling in accessing the array information.
Edit: I am looking for arrays to be accessed and to be displayed on DetailsTableViewController.
According to your question you are going to pass one item (the employee) to the detail view controller, not an array.
Do that:
In VillageTableViewController replace prepare(for with
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showVillages",
let indexPath = self.tableView.indexPathForSelectedRow {
let employee = lists[indexPath.row]
let destination = segue.destination as! DetailsViewController
destination.employee = employee
}
}
In DetailsViewController create a property employee
var employee : Employee!
Now you can access all properties of the employee in the detail view controller, for example using its food array as data source
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return employee.food.count
}
and
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! DetailsTableViewCell
cell.textLabel.text = employee.food[indexPath.row]
return cell
}
PS: Rather than separate arrays for food (names) and ingredients I recommend to use a second struct (in this case you don't need to write any initializers in both structs)
struct Food {
let name : String
let ingredients: [String]
}
struct Employee {
let name: String
let food: [Food]
}
var lists : [Employee] = [
Employee(name: "Adam" , food: [Food(name: "Fried Rice", ingredients:["Insert oil, cook"]),
Food(name: "Fried Noodles", ingredients: ["Insert oil, cook"])])
The benefit is you can easily use sections in the detail view controller.
func numberOfSections(in tableView: UITableView) -> Int {
return return employee.food.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let food = employee.food[section]
return return food.name
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let food = employee.food[section]
return food.ingredients.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! DetailsTableViewCell
let food = employee.food[indexPath.section]
cell.textLabel.text = food.ingredients[indexPath.row]
return cell
}
Having a closer look self.tableView.indexPathsForSelectedRows is an array of IndexPaths. Why don't you try
destination.food = lists[indexPath[0].row].food
In prepare set food according to selected employee from lists
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showVillages" {
guard let indexPath = tableView.indexPathsForSelectedRow,
let destinationVC = segue.destination as? DetailsViewController else {
return
}
destinationVC.food = lists[indexPath.row].food
}
}

Issue with passing proper image to tableviewcell

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)
}
}
}

table view drill down succession

I need to create a drill down effect with my table views that will expand four table views deep for each of my original cells in my master table view. So far i was successful in populating the master view, and second table view accordingly with this Object Oriented Method, here is the code in my master table view:
class FirstTableViewController: UITableViewController {
let aSport:[Sport] = {
var basketball = Sport()
basketball.name = "Basketball"
basketball.sportCategories = {
var temp = ["International Basketball","Wheelchair Basketball","Beach Basketball","Deaf Basketball","Dwarf Basketball"]
temp.sort(<)
return temp
}()
var golf = Sport()
golf.name = "Golf"
golf.sportCategories = {
var temp = ["Miniature Golf","Dart Golf","Sholf","Disc Golf","Footgolf"]
temp.sort(<)
return temp
}()
var football = Sport()
football.name = "Football"
football.sportCategories = {
var temp = ["Flag Football","Indoor Football","Arena Football","Non-Tackle Football","Paper Football"]
temp.sort(<)
return temp
}()
var swimming = Sport()
swimming.name = "Swimming"
swimming.sportCategories = {
var temp = ["Competitive Swimming","Synchronized Swimming","Duo Swimming","Relay Swimming"]
temp.sort(<)
return temp
}()
return [basketball,golf,football,swimming]
}()
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return aSport.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
cell.textLabel?.text = aSport[indexPath.row].name
return cell
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let cell = sender as! UITableViewCell
let row = tableView.indexPathForCell(cell)?.row
let detail = segue.destinationViewController as! SecondTableViewController
detail.selectedSport = aSport[row!]
}
}
class Sport {
var name: String = "sport name"
var sportCategories: NSArray = ["variations of selected sport"]
var detailText: NSArray = ["little description of sport"]
}
here is the code in my second table view controller:
class SecondTableViewController: UITableViewController {
var selectedSport = Sport();
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return selectedSport.sportCategories.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Custom", forIndexPath: indexPath) as! UITableViewCell
cell.textLabel!.text = selectedSport.sportCategories[indexPath.row] as? String
cell.detailTextLabel!.text = selectedSport.detailText[indexPath.row] as? String
return cell
}
}
here are screenshots from my simulator so you get a visual:
https://40.media.tumblr.com/6ee47f49c2b223b514f8067c68ac6af1/tumblr_nqbe74HYGo1tupbydo1_500.png
when basketball is selected:
https://41.media.tumblr.com/ced0ee2ff111a557ec3c21f1fb765adf/tumblr_nqbe74HYGo1tupbydo2_500.png
Now as you can see, i was able to populate the first two views by creating a custom class, creating custom objects of that class and using the properties within the class. Now my dilemma is, each of the "sportCategories" properties have their OWN table views to expand to which will consist of a whole list of names of players in that respective sport. Now what method should i go about doing this? should i create a whole new class in my second table view controller to give the sportsCategories their own properties? or is there a way i can already expand off the work I've already done? a more efficient way?

Resources