Can someone tell me which part of my code is not correct?
There two two files CompDftVC.swift and SelectDftVC.swift, when clock at tableview (CompDftVC) which segue to another tableview (SelectDftVC), which I make some selection and click 'Save' to segue back, then I got duplicate records at the initial tableview. Please see my code and screen shots as attached. Thank you for your help.
// CompDftVC.swift
import UIKit
import Firebase
class CompDftVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return compNDftLst.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = compDftTV.dequeueReusableCell(withIdentifier: "compDftTVCell", for: indexPath)
cell.textLabel?.text = compNDftLst[indexPath.row].compName
if indexPath.row % 2 == 0 {
cell.contentView.backgroundColor = .white
} else {
cell.contentView.backgroundColor = .white
}
return cell
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// pass compID to destination
tmpComponentId = compNDftLst[indexPath.row].compId!
// animate effect
compDftTV.deselectRow(at: indexPath, animated: true)
// segue triggered
performSegue(withIdentifier: "segueToSelectDft", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "segueToSelectDft" {
let svc = segue.destination as! SelectDftVC
svc.passInCompId = tmpComponentId
svc.passInParentEmpty = tmpParentEmpty
}
}
#IBOutlet weak var compDftTV: UITableView!
let node = currCompID+"CompDft"
let compNode = currCompID+"Comp"
let dftNode = currCompID+"Dft"
var compNDftLst = [CompNDft]()
var databaseHandle: DatabaseHandle?
var compRef: DatabaseReference!
var tmpComponentId = String()
var tmpParentEmpty = Int()
override func viewDidLoad() {
super.viewDidLoad()
compDftTV.delegate = self
compDftTV.dataSource = self
self.compNDftLst.removeAll()
// check whether the compDft table is empty
// if empty only return component with section (one row)
// if not, prepare tmp Array to display on tableview
compRef = Database.database().reference().child(node)
compRef.observe(DataEventType.value, with: { (snapshot) in
// need to consider the workshop is still empty or not?
if snapshot.childrenCount > 0 {
// CompDft table is not empty. need to retrieve comp/defect list and present them at an expandable tableview
// self.compNDftLst.removeAll()
// component already has defects. prepare the tablewview with defect list
self.tmpParentEmpty = 0
self.compRef = Database.database().reference().child(self.compNode)
self.compRef.observeSingleEvent(of: DataEventType.value, with: { (snapshot) in
if snapshot.childrenCount > 0 {
for comp in snapshot.children.allObjects as! [DataSnapshot] {
let compObj = comp.value as? [String: AnyObject]
self.tmpComponentId = comp.key
let componentName = compObj?["name"]
let component = CompNDft(compId: self.tmpComponentId as String?, compName: componentName as! String?, dftList: [""])
self.compNDftLst.append(component)
}
self.compDftTV.reloadData()
}
})
} else {
// CompDft table is empty. Only need to get componment list from Comp table
self.tmpParentEmpty = 1
self.compRef = Database.database().reference().child(self.compNode)
self.compRef.observeSingleEvent(of: DataEventType.value, with: { (snapshot) in
if snapshot.childrenCount > 0 {
// self.compNDftLst.removeAll()
for comp in snapshot.children.allObjects as! [DataSnapshot] {
let compObj = comp.value as? [String: AnyObject]
self.tmpComponentId = comp.key
let componentName = compObj?["name"]
let component = CompNDft(compId: self.tmpComponentId as String?, compName: componentName as! String?, dftList: [""])
self.compNDftLst.append(component)
}
self.compDftTV.reloadData()
}
})
}
})
} // ViewDidLoad
} // class
// SelectDftVC.swift
import UIKit
import Firebase
class SelectDftVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tmpDisplayDefectNameList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = selectDftTV.dequeueReusableCell(withIdentifier: "dftListTVCell", for: indexPath)
cell.textLabel?.text = tmpDisplayDefectNameList[indexPath.row]
// get the componet ID and check which defect was selected and then mark them .checkmark
if tmpDefectSelected[indexPath.row] == 1 {
cell.accessoryType = .checkmark
}
if indexPath.row % 2 == 0 {
cell.contentView.backgroundColor = .white
} else {
cell.contentView.backgroundColor = .white
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableView.cellForRow(at: indexPath)?.accessoryType == UITableViewCell.AccessoryType.checkmark {
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCell.AccessoryType.none
tmpDefectSelected[indexPath.row] = 0
} else {
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCell.AccessoryType.checkmark
tmpDefectSelected[indexPath.row] = 1
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
let node = currCompID+"CompDft"
let compNode = currCompID+"Comp"
let dftNode = currCompID+"Dft"
var passInCompId = String()
var passInParentEmpty = Int()
var ref: DatabaseReference!
var ref2: DatabaseReference!
var ref3: DatabaseReference!
var ref4: DatabaseReference!
var ref5: DatabaseReference!
var ref6: DatabaseReference!
var refDft: DatabaseReference!
var selectedDft: DatabaseReference!
var selectedDftId = [String]()
var tmpDefectSelected = [Int]()
var initialTmpDefectSelected = [Int]()
var tmpDisplayDefectIdList = [String]()
var tmpDisplayDefectNameList = [String]()
var tmpSelectedDftID = [String]()
var tmpSelectedDftName = [String]()
var hasData = Int()
#IBOutlet weak var selectDftTV: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
selectDftTV.delegate = self
selectDftTV.dataSource = self
tmpDisplayDefectIdList.removeAll() // defect ID
tmpDisplayDefectNameList.removeAll() // defect Name
selectedDftId.removeAll() // Selected defect ID
tmpDefectSelected.removeAll() // Integer array for checkmark
initialTmpDefectSelected.removeAll() // Initial Integer array for checkmark (to be updated when populating tableview
if passInParentEmpty == 1 {
// component doesn't contain any defect
ref = Database.database().reference().child(dftNode)
ref.observe(DataEventType.value, with: { (snapshot) in
// need to consider the workshop is still empty or not?
if snapshot.childrenCount > 0 {
// get defect list
for defect in snapshot.children.allObjects as! [DataSnapshot] {
let defectObj = defect.value as? [String: AnyObject]
let defectId = defect.key
let defectName = defectObj?["name"]
self.tmpDisplayDefectIdList.append(defectId)
self.tmpDisplayDefectNameList.append(defectName as! String)
self.tmpDefectSelected.append(0)
self.initialTmpDefectSelected.append(0)
}
self.prepareSelectedDftList()
}
})
} else {
// the component already contain defect
ref = Database.database().reference().child(dftNode)
ref.observe(DataEventType.value, with: { (snapshot) in
// need to consider the workshop is still empty or not?
if snapshot.childrenCount > 0 {
// get defect list
for defect in snapshot.children.allObjects as! [DataSnapshot] {
let defectObj = defect.value as? [String: AnyObject]
let defectId = defect.key
let defectName = defectObj?["name"]
self.tmpDisplayDefectIdList.append(defectId)
self.tmpDisplayDefectNameList.append(defectName as! String)
self.tmpDefectSelected.append(0)
self.initialTmpDefectSelected.append(0)
}
}
self.ref2 = Database.database().reference().child(self.node)
self.ref2.queryOrderedByKey().queryEqual(toValue: self.passInCompId).observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.childrenCount > 0 {
self.hasData = 1
} else {
self.hasData = 0
}
if self.hasData == 1 {
self.ref3 = Database.database().reference().child(self.node)
self.ref3.queryOrderedByKey().queryEqual(toValue: self.passInCompId).observe(.childAdded, with: { (snapshot) in
if snapshot.childrenCount > 0 {
// selected component has defects
for child in snapshot.children {
let snap = child as! DataSnapshot
let tmpkey = snap.key as String?
self.selectedDftId.append(tmpkey!)
}
}
self.prepareSelectedDftList()
})
} else {
self.prepareSelectedDftList()
}
})
// self.ref2.removeAllObservers()
}) // first DBquery
// self.ref.removeAllObservers()
}
} // viewDidLoad
#IBAction func saveSelectedDft(_ sender: Any) {
// prepare the array of defects to be marked for component which can override the current one
if tmpDisplayDefectNameList.count > 0 {
for i in 0...tmpDisplayDefectNameList.count - 1 {
if tmpDefectSelected[i] == 1 {
// prepare selected defect ID and name array
tmpSelectedDftID.append(tmpDisplayDefectIdList[i])
tmpSelectedDftName.append(tmpDisplayDefectNameList[i])
}
}
markUsed4CompNDft()
// refDft.removeAllObservers()
}
// segue back and refresh tmp array (may be) and tableview
self.navigationController?.popViewController(animated: true)
} // saveSelectedDftBtn
func prepareSelectedDftList() {
if selectedDftId.count == 0 {
selectDftTV.reloadData()
} else if selectedDftId.count == 1 {
for i in 0...tmpDisplayDefectIdList.count - 1 {
if tmpDisplayDefectIdList[i] == selectedDftId[0] {
tmpDefectSelected[i] = 1
initialTmpDefectSelected[i] = 1
}
}
selectDftTV.reloadData()
} else if selectedDftId.count > 1 {
for i in 0...tmpDisplayDefectIdList.count - 1 {
for j in 0...selectedDftId.count - 1 {
if tmpDisplayDefectIdList[i] == selectedDftId[j] {
tmpDefectSelected[i] = 1
initialTmpDefectSelected[i] = 1
}
}
}
// self.ref.removeAllObservers()
selectDftTV.reloadData()
}
} // prepareSelectedDftList
func resetComponentUsedToZero() {
var clearCompId = String()
var clearCompName = String()
ref5 = Database.database().reference()
ref5.child(compNode).queryOrderedByKey().queryEqual(toValue: passInCompId).observe(.childAdded, with: { (snapshot) in
for child in snapshot.children {
let snap = child as! DataSnapshot
let key = snap.key
if key == "id" {
clearCompId = snap.value as! String
}
if key == "name" {
clearCompName = snap.value as! String
}
}
let updatedComponent = [
"id" : clearCompId,
"name" : clearCompName,
"date" : utcDate(),
"time" : utcTime(),
"updated" : currUID,
"used" : 0
] as [String: Any]
self.ref5.child(self.compNode).child(self.passInCompId).setValue(updatedComponent)
})
ref5.removeAllObservers()
}
func setComponentUsedToOne() {
var clearCompId = String()
var clearCompName = String()
ref5 = Database.database().reference()
ref5.child(compNode).queryOrderedByKey().queryEqual(toValue: passInCompId).observe(.childAdded, with: { (snapshot) in
for child in snapshot.children {
let snap = child as! DataSnapshot
let key = snap.key
if key == "id" {
clearCompId = snap.value as! String
}
if key == "name" {
clearCompName = snap.value as! String
}
}
let updatedComponent = [
"id" : clearCompId,
"name" : clearCompName,
"date" : utcDate(),
"time" : utcTime(),
"updated" : currUID,
"used" : 1
] as [String: Any]
self.ref5.child(self.compNode).child(self.passInCompId).setValue(updatedComponent)
})
ref5.removeAllObservers()
}
func markUsed4CompNDft() {
ref6 = Database.database().reference()
// check any changes made
if initialTmpDefectSelected != tmpDefectSelected {
if tmpSelectedDftID.count == 0 {
// clear all defect
ref6.child(node).child(passInCompId).setValue(nil)
// should change component 'used' to 0
resetComponentUsedToZero()
} else {
ref6.child(node).child(passInCompId).setValue(nil)
for i in 0...tmpSelectedDftID.count - 1 {
ref6.child(node).child(passInCompId).child(tmpSelectedDftID[i]).setValue(tmpSelectedDftName[i])
}
// mark component used = 1
setComponentUsedToOne()
// mark defect(s) used = 1
if tmpSelectedDftID.count > 0 {
// ref = Database.database().reference().child(dftNode)
ref4 = Database.database().reference().child(dftNode)
for i in 0...tmpSelectedDftID.count - 1 {
ref4.queryOrderedByKey().queryEqual(toValue: tmpSelectedDftID[i]).observe(.childAdded, with: { (sp) in
self.ref4.child(self.tmpSelectedDftID[i]).updateChildValues(["date" : utcDate()])
self.ref4.child(self.tmpSelectedDftID[i]).updateChildValues(["time" : utcTime()])
self.ref4.child(self.tmpSelectedDftID[i]).updateChildValues(["updated" : currUID])
self.ref4.child(self.tmpSelectedDftID[i]).updateChildValues(["used" : 1])
})
}
}
// ref4.removeAllObservers()
}
}
} // markUsed4CompNDft
} // class
Related
I have a problem with passing the data
To make it clear, I will explain the idea of what I worked on, and what is the problem.
The idea is in the first view controller the user will enter the title and description and then chooses from the options of the pop-up button, the options are (exchange, borrow, donation, sell). The data entered will be saved in the option chosen by the user. then the data will be displayed in the second view controller in the table view. If the user chooses the exchange option and enters the data, his data will be displayed in the table view in the exchange (index 0) and this works for me the data is displayed in the table view in the correct form as I want.
The problem I am experiencing is when I pass the data to the other view controller.
When the user clicks on any cell, it will pass the same data regardless of the difference in the index. If the user chooses the borrow (index 1) and clicks any cell, it'll display the exchange (index 0) data. No matter what indexes you choose and the cell you click on it will pass the same data!!!!!
first view controller
here I'm entering the data
it's shown in the table view in the right index of the segment no problem with that
after I click it pass the right data
look here if I change the index and click to any cell it will pass the same data!!
look here if I change the index and click to any cell it will pass the same data!!
Here's my code for the first vc
import UIKit
import FirebaseFirestore
class ViewController4: UIViewController {
#IBOutlet weak var mssglabel: UILabel!
#IBOutlet weak var selectservice: UIButton!
#IBOutlet weak var titleTextField: UITextField!
#IBOutlet weak var descriptionTextField: UITextView!
#IBOutlet weak var custombtun: UIButton!
let db = Firestore.firestore()
var chooseOption = ""
override func viewDidLoad() {
super.viewDidLoad()
setpopupbutn()
selectservice.layer.cornerRadius = 25
descriptionTextField.layer.cornerRadius = 25
custombtun.layer.cornerRadius = 25
}
#IBAction func containbutn(_ sender: Any) {
let vc = (storyboard?.instantiateViewController(withIdentifier: "vc3"))!
navigationController?.pushViewController(vc, animated: true)
spcificOption()
}
func saveDataDonation() {
if let description = descriptionTextField.text,
let tittle = titleTextField.text{
// Save Data to Database
db.collection("userDonationDatabase")
.addDocument(data: [
"description" : description,
"BookTitle": tittle ]) {
(error) in
if let err = error {
print(err.localizedDescription)
}else {
print("تم حفظ البيانات بنجاح")
print(description)
print(tittle)
}
} // end of closure
}
}
func saveDataSale() {
if let description = descriptionTextField.text,
let tittle = titleTextField.text{
// Save Data to Database
db.collection("userSaleDatabase")
.addDocument(data: [
"description" : description,
"BookTitle": tittle ]) {
(error) in
if let err = error {
print(err.localizedDescription)
}else {
print("تم حفظ البيانات بنجاح")
print(description)
print(tittle) }
}
}
}
func saveDataExchange() {
if let description = descriptionTextField.text,
let tittle = titleTextField.text {
// Save Data to Database
db.collection("userExchangeDatabase")
.addDocument(data: [
"description" : description,
"BookTitle": tittle ]) {
(error) in
if let err = error {
print(err.localizedDescription)
}else {
print("تم حفظ البيانات بنجاح")
print(description)
print(tittle) }
}
}
}
func saveDataBorrow() {
if let description = descriptionTextField.text,
let tittle = titleTextField.text {
// Save Data to Database
db.collection("userBorrowDatabase")
.addDocument(data: [
"description" : description,
"BookTitle": tittle]) {
(error) in
if let err = error {
print(err.localizedDescription)
}else {
print("تم حفظ البيانات بنجاح")
print(description)
print(tittle) }
}
}
}
func setpopupbutn () {
let option = {( ACTION : UIAction ) in
self.chooseOption = ACTION.title
print("حفظ الداتا في ",self.chooseOption)}
selectservice.menu = UIMenu (children : [
UIAction (title : "تبرع" , state: .on , handler: option),
UIAction (title : "بيع" , handler: option),
UIAction (title : "تبادل" , handler: option),
UIAction (title : "إستعارة" , handler: option),
])
saveDataDonation()
selectservice.showsMenuAsPrimaryAction = true
selectservice.changesSelectionAsPrimaryAction = true
}
func spcificOption() {
if chooseOption == ("تبرع") {
saveDataDonation()
} else if chooseOption == ("بيع") {
saveDataSale()
} else if chooseOption == ("تبادل") {
saveDataExchange()
} else if chooseOption == ("إستعارة") {
saveDataBorrow()
}
}
}
and this is the second vc (Table view)
import UIKit
import FirebaseFirestore
import Firebase
class ViewController3: UIViewController, UITableViewDataSource, UITableViewDelegate {
let db = Firestore.firestore()
var exchange : [exchange] = []
var borrow : [borrow] = []
var donation : [donation] = []
var sale : [sale] = []
#IBOutlet weak var segmentOutlet: UISegmentedControl!
#IBOutlet weak var userDataTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
userDataTableView.dataSource = self
userDataTableView.delegate = self
getDataDonation()
getDataSale()
getDataExchange()
getDataBorrow()
userDataTableView.reloadData()
}
#IBAction func serviceSeg(_ sender: UISegmentedControl) {
if sender.selectedSegmentIndex == 0 {
getDataExchange()
}
else if sender.selectedSegmentIndex == 1 {
getDataBorrow()
}
else if sender.selectedSegmentIndex == 2 {
getDataDonation()
}
else if sender.selectedSegmentIndex == 3 {
getDataSale()
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if segmentOutlet.selectedSegmentIndex == 0 {
return exchange.count
} else if segmentOutlet.selectedSegmentIndex == 1 {
return borrow.count
}else if segmentOutlet.selectedSegmentIndex == 2 {
return donation.count
} else if segmentOutlet.selectedSegmentIndex == 3 {
return sale.count
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if segmentOutlet.selectedSegmentIndex == 0 {
cell.textLabel?.text = exchange [indexPath.row].passTitle
} else if segmentOutlet.selectedSegmentIndex == 1 {
cell.textLabel?.text = borrow [indexPath.row].passTitle
} else if segmentOutlet.selectedSegmentIndex == 2 {
cell.textLabel?.text = donation [indexPath.row].passTitle
} else if segmentOutlet.selectedSegmentIndex == 3 {
cell.textLabel?.text = sale [indexPath.row].passTitle
}
return cell
}
func getDataDonation(){
donation.removeAll()
db.collection("userDonationDatabase")
.getDocuments { querySnapshot, error in
if let err = error { print(err.localizedDescription)}
else {
for document in querySnapshot!.documents {
let data = document.data()
print( data["BookTitle"] as! String )
self.donation.append(finalProject.donation(passTitle3:data["BookTitle"] as! String , passDes3: data["description"] as! String))
}
DispatchQueue.main.async {
self.userDataTableView.reloadData()
}
}
}
}
func getDataSale(){
sale.removeAll()
db.collection("userSaleDatabase")
.getDocuments { querySnapshot, error in
if let err = error { print(err.localizedDescription)}
else {
for document in querySnapshot!.documents {
let data = document.data()
print( data["BookTitle"] as! String )
self.sale.append(finalProject.sale(passTitle4:data["BookTitle"] as! String , passDes4: data["description"] as! String))
}
DispatchQueue.main.async {
self.userDataTableView.reloadData()
}
}
}
}
func getDataExchange(){
exchange.removeAll()
db.collection("userExchangeDatabase")
.getDocuments { querySnapshot, error in
if let err = error { print(err.localizedDescription)}
else {
for document in querySnapshot!.documents {
let data = document.data()
print( data["BookTitle"] as! String )
self.exchange.append(finalProject.exchange(passTitle1:data["BookTitle"] as! String , passDes1: data["description"] as! String))
}
DispatchQueue.main.async {
self.userDataTableView.reloadData()
}
}
}
}
func getDataBorrow(){
borrow.removeAll()
db.collection("userBorrowDatabase")
.getDocuments { querySnapshot, error in
if let err = error { print(err.localizedDescription)}
else {
for document in querySnapshot!.documents {
let data = document.data()
print( data["BookTitle"] as! String )
self.borrow.append(finalProject.borrow(passTitle2:data["BookTitle"] as! String , passDes2: data["description"] as! String))
}
DispatchQueue.main.async {
self.userDataTableView.reloadData()
}
}
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let vc = storyboard?.instantiateViewController(withIdentifier:"vc10") as? ViewController10 {
vc.recivedE = exchange[indexPath.row]
self.navigationController?.pushViewController(vc, animated: true)
}
}
}
Note... I tried to do this but it didn't work
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let vc = storyboard?.instantiateViewController(withIdentifier:"vc10") as? ViewController10 {
vc.recivedE = exchange[indexPath.row]
vc.recivedB = borrow[indexPath.row]
vc.recivedD = donation[indexPath.row]
vc.recivedS = sale[indexPath.row]
self.navigationController?.pushViewController(vc, animated: true)
}
}
This is the struct,
I created a struct for each index
public struct exchange {
var passTitle : String
var passDes : String
init (passTitle1:String, passDes1:String) {
self.passTitle = passTitle1
self.passDes = passDes1
}
}
public struct borrow {
var passTitle : String
var passDes : String
init (passTitle2:String, passDes2:String) {
self.passTitle = passTitle2
self.passDes = passDes2
}
}
public struct donation {
var passTitle : String
var passDes : String
init (passTitle3:String, passDes3:String) {
self.passTitle = passTitle3
self.passDes = passDes3
}
}
public struct sale {
var passTitle : String
var passDes : String
init (passTitle4:String, passDes4:String) {
self.passTitle = passTitle4
self.passDes = passDes4
}
}
this is the last vc
import UIKit
import FirebaseStorage
import Firebase
import FirebaseFirestore
import SDWebImage
class ViewController10: UIViewController {
#IBOutlet weak var userBookTitle: UILabel!
#IBOutlet weak var userBookDescription: UILabel!
var recivedE:exchange?
var recivedB:borrow?
var recivedD:donation?
var recivedS:sale?
override func viewDidLoad() {
super.viewDidLoad()
userBookTitle.text = recivedE?.passTitle
userBookDescription.text = recivedE?.passDes
}
}
Note... I tried to do this but it didn't work
override func viewDidLoad() {
super.viewDidLoad()
if let et = recivedE?.passTitle ,
let ed = recivedE?.passDes{
userBookTitle.text = et
userBookDescription.text = ed
}
else if let bt = recivedB?.passTitle ,
let bd = recivedB?.passDes {
userBookTitle.text = bt
userBookDescription.text = bd
}
else if let dt = recivedD?.passTitle ,
let dd = recivedD?.passDes {
userBookTitle.text = dt
userBookDescription.text = dd
}
else if let st = recivedS?.passTitle ,
let sd = recivedS?.passDes {
userBookTitle.text = st
userBookDescription.text = sd
}
}
and this also not working
override func viewDidLoad() {
super.viewDidLoad()
userBookTitle.text = recivedE?.passTitle
userBookDescription.text = recivedE?.passDes
userBookTitle.text = recivedB?.passTitle
userBookDescription.text = recivedB?.passDes
userBookTitle.text = recivedD?.passTitle
userBookDescription.text = recivedD?.passDes
userBookTitle.text = recivedS?.passTitle
userBookDescription.text = recivedS?.passDes
}
help me, please
In both of your numberOfRowsInSection and cellForRowAt functions, you are checking the selected segment index to determine which data to use:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if segmentOutlet.selectedSegmentIndex == 0 {
return exchange.count
} else if segmentOutlet.selectedSegmentIndex == 1 {
return borrow.count
}else if segmentOutlet.selectedSegmentIndex == 2 {
return donation.count
} else if segmentOutlet.selectedSegmentIndex == 3 {
return sale.count
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if segmentOutlet.selectedSegmentIndex == 0 {
cell.textLabel?.text = exchange [indexPath.row].passTitle
} else if segmentOutlet.selectedSegmentIndex == 1 {
cell.textLabel?.text = borrow [indexPath.row].passTitle
} else if segmentOutlet.selectedSegmentIndex == 2 {
cell.textLabel?.text = donation [indexPath.row].passTitle
} else if segmentOutlet.selectedSegmentIndex == 3 {
cell.textLabel?.text = sale [indexPath.row].passTitle
}
return cell
}
However, in didSelectRowAt, you only use the exchange data:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let vc = storyboard?.instantiateViewController(withIdentifier:"vc10") as? ViewController10 {
vc.recivedE = exchange[indexPath.row]
self.navigationController?.pushViewController(vc, animated: true)
}
}
If you implement the same if / else if structure in didSelectRowAt you should get the desired results.
Im retrieve data from firebese and show in tableView
In tavleViewCell I have butons : like, unLike
when I press like need to hide likeButton and show UnlikeButton
And store/remove data from firebase
Now I create metods and when I click Like -> data save to firebase and show unlikeButton BUT unlikeButton shows in another cell's(not in all cells- example if I click in 0 indexPath.row, unlikeButton shows in 0,6,12,17..) Maybe this may happen when I scroll tableView
in cell I have :
protocol TableThemeQuote {
func likeTap(_ sender: ThemesQuoteCell)
func unlikeTap(_ sender: ThemesQuoteCell)
}
class ThemesQuoteCell: UITableViewCell {
#IBOutlet weak var likeBtn: UIButton!
#IBOutlet weak var unlikeBtn: UIButton!
var themeDelegate: TableThemeQuote?
var index: indexPath?
#IBAction func likeBtn(_ sender: UIButton) {
sender.tag = index.row
themeDelegate?.likeTap(self)
}
#IBAction func unLikeBtn(_ sender: UIButton) {
sender.tag = index.row
themeDelegate?.unlikeTap(self)
}
}
In ViewController:
var userMarks: [String] = [String]()
override func viewDidLoad() {
super.viewDidLoad()
likeLike()
}
func likeLike() {
let userUID = Auth.auth().currentUser!.uid
let ref = Database.database().reference().child("users").child("\(userUID)")
ref.observeSingleEvent(of: .value, with: { (snapshot) in
if let properties = snapshot.value as? [String : AnyObject] {
if let peopleWhoLike = properties["userLikes"] as? [String : AnyObject] {
self.likeLikeL.append(peopleWhoLike)
for (id,person) in peopleWhoLike {
self.userLikeCheck.updateValue(person, forKey: id)
self.userMarks.append(person as! String)
}
}
}
})
}
In cellForRowAt indexPath:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "themesQuoteCell") as! ThemesQuoteCell
let index = indexPath.row
cell.index = index
cell.themeDelegate = self
let mark = "Темы/\(themeName)/\(quotenumber[index.row])"
if userMarks.contains(mark){
if cell.likeBtn.tag == index.row {
cell.likeBtn.isHidden = true
cell.unlikeBtn.isHidden = false
break
}
}
return cell
}
In TableThemeQuote extension:
extension ThemeQuoteVC: TableThemeQuote {
func likeTap(_ sender: ThemesQuoteCell) {
guard let tappedIndexPath = themeQuoteTableView.indexPath(for: sender) else { return }
let ref = Database.database().reference().child("Темы").child("\(self.themeName)").child("\(quotenumber[tappedIndexPath.row])")
let keyToPost = ref.childByAutoId().key!
let updateLikes: [String : Any] = ["peopleWhoLike/\(keyToPost)" : Auth.auth().currentUser!.uid]
ref.updateChildValues(updateLikes, withCompletionBlock: { (error, reff) in
if error == nil {
ref.observeSingleEvent(of: .value, with: { (snap) in
if let properties = snap.value as? [String : AnyObject] {
if let likes = properties["peopleWhoLike"] as? [String : AnyObject] {
let count = likes.count
sender.likeLbl.text = "\(count)"
let update = ["quant" : count]
ref.updateChildValues(update)
sender.likeBtn.isHidden = true
sender.unlikeBtn.isHidden = false
sender.likeBtn.isEnabled = true
}
}
})
}
})
ref.removeAllObservers()
}
func unlikeTap(_ sender: ThemesQuoteCell) {
sender.unlikeBtn.isEnabled = false
guard let uid = Auth.auth().currentUser?.uid else { return }
let ref = Database.database().reference().child("users").child("\(uid)")
guard let tappedIndexPath = themeQuoteTableView.indexPath(for: sender) else { return }
let mark = "Темы/\(themeName)/\(quotenumber[tappedIndexPath.row])"
unlikeCellBtn(index: tappedIndexPath.row, sender: sender)
if sender.unlikeBtn.tag == tappedIndexPath.row {
ref.observeSingleEvent(of: .value, with: { (snapshot) in
if let properties = snapshot.value as? [String : AnyObject] {
if let peopleWhoLike = properties["userLikes"] as? [String : AnyObject] {
for (id,person) in peopleWhoLike {
if person as! String == mark {
ref.child("userLikes").child(id).removeValue(completionBlock: { (error, reff) in
if error == nil {
ref.observeSingleEvent(of: .value, with: { (snap) in
if let prop = snap.value as? [String : AnyObject] {
if let likes = prop["userLikes"] as? [String : AnyObject] {
let count = likes.count
ref.updateChildValues(["quantLikes" : count])
}else {
ref.updateChildValues(["quantLikes" : 0])
}
}
})
}
})
sender.likeBtn.isHidden = false
sender.unlikeBtn.isHidden = true
sender.unlikeBtn.isEnabled = true
break
}
}
}
}
})
}
ref.removeAllObservers()
}
What Im doing wrong and how can I get current tap and show/hide only that button which I press?
Cells are reused. This part of the code
if userMarks.contains(mark){
if cell.likeBtn.tag == index.row {
cell.likeBtn.isHidden = true
cell.unlikeBtn.isHidden = false
break
}
}
sets the hidden properties depending on some conditions but keeps the hidden state unchanged if the conditions are not met.
What you have to do is to add an else clause to set default values (by the way, the break statement is pointless)
if userMarks.contains(mark) && cell.likeBtn.tag == index.row {
cell.likeBtn.isHidden = true
cell.unlikeBtn.isHidden = false
} else {
cell.likeBtn.isHidden = <default value>
cell.unlikeBtn.isHidden = <default value>
}
I have been trying to create multidimensional arrays and display each array under each section .. but I keep ending up with a fatal error index out of range . The code that i display below is how I access my firebase data and print each array from the database.. issue is I get the data I assign an array to it create it but can’t seem to display it due to the error . Hope someone helps for reference regarding the error I have attached a screenshot as well.
#IBOutlet weak var tableview: UITableView!
var yourArray = [String]()
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
var sundaycoursenamearray = [String]()
var sundaycoursecodearray = [String]()
var sundaycourselocationarray = [String]()
var sundayfromarray = [String]()
var sundaytoarray = [String]()
var mondaycoursenamearray = [String]()
var mondaycoursecodearray = [String]()
var mondaycourselocationarray = [String]()
var mondayfromarray = [String]()
var mondaytoarray = [String]()
var tuesdaycoursenamearray = [String]()
var tuesdaycoursecodearray = [String]()
var tuesdaycourselocationarray = [String]()
var tuesdayfromarray = [String]()
var tuesdaytoarray = [String]()
var wednesdaycoursenamearray = [String]()
var wednesdaycoursecodearray = [String]()
var wednesdaycourselocationarray = [String]()
var wednesdayfromarray = [String]()
var wednesdaytoarray = [String]()
var thursdaycoursenamearray = [String]()
var thursdaycoursecodearray = [String]()
var thursdaycourselocationarray = [String]()
var thursdayfromarray = [String]()
var thursdaytoarray = [String]()
var fridaycoursenamearray = [String]()
var fridaycoursecodearray = [String]()
var fridaycourselocationarray = [String]()
var fridayfromarray = [String]()
var fridaytoarray = [String]()
var saturdaycoursenamearray = [String]()
var saturdaycoursecodearray = [String]()
var saturdaycourselocationarray = [String]()
var saturdayfromarray = [String]()
var saturdaytoarray = [String]()
var coursecodes = [[String]]()
var coursenames = [[String]]()
var courselocations = [[String]]()
var fromtimes = [[String]]()
var totimes = [[String]]()
var days = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]
override func viewWillAppear(_ animated: Bool) {
let uid = Auth.auth().currentUser?.uid
if(uid == nil){
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let nextviewController = storyboard.instantiateViewController(withIdentifier: "loginscreen")
//self.present(profileViewController, animated: true, completion: nil)
self.present(nextviewController, animated: true, completion: nil)
}
for j in days {
for i in 1 ..< 10 {
let ref1 = Database.database().reference().child("users").child((uid)!).child("courses").child(j).child(String(i))
ref1.observeSingleEvent(of: .value, with: { snapshot in
if let dictionary = snapshot.value as? [String: AnyObject] {
// print(dictionary)
if j == "Sunday" {
if let points = dictionary["coursname"] as? String {
self.sundaycoursecodearray.append(points)
print(self.sundaycoursecodearray)
}
if let points1 = dictionary["coursecode"] as? String {
self.sundaycoursenamearray.append(points1)
print(self.sundaycoursenamearray)
}
if let points1 = dictionary["courseroomlocation"] as? String {
self.sundaycourselocationarray.append(points1)
print(self.sundaycourselocationarray)
}
if let points1 = dictionary["fromtime"] as? String {
self.sundayfromarray.append(points1)
print(self.sundayfromarray)
}
if let points1 = dictionary["totime"] as? String {
self.sundaytoarray.append(points1)
print(self.sundaytoarray)
}
}
if j == "Monday" {
if let points = dictionary["coursname"] as? String {
self.mondaycoursecodearray.append(points)
print(self.mondaycoursecodearray)
}
if let points1 = dictionary["coursecode"] as? String {
self.mondaycoursenamearray.append(points1)
print(self.mondaycoursenamearray)
}
if let points1 = dictionary["courseroomlocation"] as? String {
self.mondaycourselocationarray.append(points1)
print(self.mondaycourselocationarray)
}
if let points1 = dictionary["fromtime"] as? String {
self.mondayfromarray.append(points1)
print(self.mondayfromarray)
}
if let points1 = dictionary["totime"] as? String {
self.mondaytoarray.append(points1)
print(self.mondaytoarray)
}
}
if j == "Tuesday" {
if let points = dictionary["coursname"] as? String {
self.tuesdaycoursecodearray.append(points)
print(self.tuesdaycoursecodearray)
}
if let points1 = dictionary["coursecode"] as? String {
self.tuesdaycoursenamearray.append(points1)
print(self.tuesdaycoursenamearray)
}
if let points1 = dictionary["courseroomlocation"] as? String {
self.tuesdaycourselocationarray.append(points1)
print(self.tuesdaycourselocationarray)
}
if let points1 = dictionary["fromtime"] as? String {
self.tuesdayfromarray.append(points1)
print(self.tuesdayfromarray)
}
if let points1 = dictionary["totime"] as? String {
self.tuesdaytoarray.append(points1)
print(self.tuesdaytoarray)
}
}
if j == "Wednesday" {
if let points = dictionary["coursname"] as? String {
self.wednesdaycoursecodearray.append(points)
print(self.wednesdaycoursecodearray)
}
if let points1 = dictionary["coursecode"] as? String {
self.wednesdaycoursenamearray.append(points1)
print(self.wednesdaycoursenamearray)
}
if let points1 = dictionary["courseroomlocation"] as? String {
self.wednesdaycourselocationarray.append(points1)
print(self.wednesdaycourselocationarray)
}
if let points1 = dictionary["fromtime"] as? String {
self.wednesdayfromarray.append(points1)
print(self.wednesdayfromarray)
}
if let points1 = dictionary["totime"] as? String {
self.wednesdaytoarray.append(points1)
print(self.wednesdaytoarray)
}
}
if j == "Thursday" {
if let points = dictionary["coursname"] as? String {
self.thursdaycoursecodearray.append(points)
print(self.thursdaycoursecodearray)
}
if let points1 = dictionary["coursecode"] as? String {
self.thursdaycoursenamearray.append(points1)
print(self.thursdaycoursenamearray)
}
if let points1 = dictionary["courseroomlocation"] as? String {
self.thursdaycourselocationarray.append(points1)
print(self.thursdaycourselocationarray)
}
if let points1 = dictionary["fromtime"] as? String {
self.thursdayfromarray.append(points1)
print(self.thursdayfromarray)
}
if let points1 = dictionary["totime"] as? String {
self.thursdaytoarray.append(points1)
print(self.thursdaytoarray)
}
}
if j == "Friday" {
if let points = dictionary["coursname"] as? String {
self.fridaycoursecodearray.append(points)
print(self.fridaycoursecodearray)
}
if let points1 = dictionary["coursecode"] as? String {
self.fridaycoursenamearray.append(points1)
print(self.fridaycoursenamearray)
}
if let points1 = dictionary["courseroomlocation"] as? String {
self.fridaycourselocationarray.append(points1)
print(self.fridaycourselocationarray)
}
if let points1 = dictionary["fromtime"] as? String {
self.fridayfromarray.append(points1)
print(self.fridayfromarray)
}
if let points1 = dictionary["totime"] as? String {
self.fridaytoarray.append(points1)
print(self.fridaytoarray)
}
}
if j == "Saturday" {
if let points = dictionary["coursname"] as? String {
self.saturdaycoursecodearray.append(points)
print(self.saturdaycoursecodearray)
}
if let points1 = dictionary["coursecode"] as? String {
self.saturdaycoursenamearray.append(points1)
print(self.saturdaycoursenamearray)
}
if let points1 = dictionary["courseroomlocation"] as? String {
self.saturdaycourselocationarray.append(points1)
print(self.saturdaycourselocationarray)
}
if let points1 = dictionary["fromtime"] as? String {
self.saturdayfromarray.append(points1)
print(self.saturdayfromarray)
}
if let points1 = dictionary["totime"] as? String {
self.saturdaytoarray.append(points1)
print(self.saturdaytoarray)
}
}
self.coursecodes.append(self.sundaycoursenamearray)
self.coursecodes.append(self.mondaycoursenamearray)
self.coursecodes.append(self.tuesdaycoursenamearray)
self.coursecodes.append(self.wednesdaycoursenamearray)
self.coursecodes.append(self.thursdaycoursenamearray)
self.coursecodes.append(self.fridaycoursenamearray)
self.coursecodes.append(self.saturdaycoursenamearray)
self.coursenames.append(self.sundaycoursecodearray)
self.coursenames.append(self.mondaycoursecodearray)
self.coursenames.append(self.tuesdaycoursecodearray)
self.coursenames.append(self.wednesdaycoursecodearray)
self.coursenames.append(self.thursdaycoursecodearray)
self.coursenames.append(self.fridaycoursecodearray)
self.coursenames.append(self.saturdaycoursecodearray)
self.courselocations.append(self.sundaycourselocationarray)
self.courselocations.append(self.mondaycourselocationarray)
self.courselocations.append(self.tuesdaycourselocationarray)
self.courselocations.append(self.wednesdaycourselocationarray)
self.courselocations.append(self.thursdaycourselocationarray)
self.courselocations.append(self.fridaycourselocationarray)
self.courselocations.append(self.saturdaycourselocationarray)
self.fromtimes.append(self.sundayfromarray)
self.fromtimes.append(self.mondayfromarray)
self.fromtimes.append(self.tuesdayfromarray)
self.fromtimes.append(self.wednesdayfromarray)
self.fromtimes.append(self.thursdayfromarray)
self.fromtimes.append(self.fridayfromarray)
self.fromtimes.append(self.saturdayfromarray)
self.totimes.append(self.sundaytoarray)
self.totimes.append(self.mondaytoarray)
self.totimes.append(self.tuesdaytoarray)
self.totimes.append(self.wednesdaytoarray)
self.totimes.append(self.thursdaytoarray)
self.totimes.append(self.fridaytoarray)
self.totimes.append(self.saturdaytoarray)
self.tableview.reloadData()
}
})
} }
super.viewWillAppear(animated)
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return days[section]
}
func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return days.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return coursenames[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! homeTableViewCell
// Configure the cell...
// cell.classcode?.text = sundaycoursenamearray[indexPath.section]
cell.classcode?.text = coursenames[indexPath.section][indexPath.row]
return cell
}
/*
// Override to support conditional editing of the table view.
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
*/
/*
// Override to support editing the table view.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
// Delete the row from the data source
tableView.deleteRows(at: [indexPath], with: .fade)
} else if editingStyle == .insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
*/
/*
// Override to support rearranging the table view.
override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) {
}
*/
/*
// Override to support conditional rearranging of the table view.
override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the item to be re-orderable.
return true
}
*/
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
override func viewDidLoad() {
super.viewDidLoad()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}
You should create a model for your data then create arrays that include the model.
You can create a simple struct like so:
struct Course {
var name : String?
var code: String?
var location: String?
var toTime: String?
var fromTime: String?
}
After you create the model you can create an array that contains this type of struct.
Also for numberOfRowsInSection you don't have to use subscript. Just return:
return coursenames.count
That is why you get the error.
I am following this tutorial for expanding and collapsing my table view section. As this demo is done in swift 2.2 I have made all the changes according to swift 3.0 . I am stuck at the below function at if condition(currentSectionCells[row]["isVisible"]) which gives me error as "Type 'NSFastEnumerationIterator.Element' (aka 'Any' has no subscript members)'".
func getIndicesOfVisibleRows() {
visibleRowsPerSection.removeAll()
for currentSectionCells in cellDescriptors {
var visibleRows = [Int]()
for row in 0...((currentSectionCells as! [[String: AnyObject]]).count - 1) {
if currentSectionCells[row]["isVisible"] as! Bool == true {
visibleRows.append(row)
}
}
visibleRowsPerSection.append(visibleRows)
}
}
I have tried type casting it as below
func getIndicesOfVisibleRows() {
visibleRowsPerSection.removeAll()
for currentSectionCells in cellDescriptors {
var visibleRows = [Int]()
for row in 0...((((currentSectionCells) as? NSMutableArray)?.count)! - 1) {
let temp = [currentSectionCells][row] as? NSMutableDictionary
let temp2 = temp?["isVisible"] as! Bool
if temp2 == true {
visibleRows.append(row)
}
}
visibleRowsPerSection.append(visibleRows)
}
}
But this gives me a crash at runtime on this line "let temp2 = temp?["isVisible"] as! Bool"
Crash says "EXC_BAD_INSTRUCTION" and the temp shows as nil.
Please help guys. TIA
Table View Delegate and Data Source
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
if cellDescriptors != nil {
return cellDescriptors.count
}
else {
return 0
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return visibleRowsPerSection[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let currentCellDescriptor = getCellDescriptorForIndexPath(indexPath: indexPath as NSIndexPath)
let cell = tableView.dequeueReusableCell(withIdentifier: currentCellDescriptor["cellIdentifier"] as! String, for: indexPath) as! CustomCell
if currentCellDescriptor["cellIdentifier"] as! String == "sectionCellIdentifier" {
if let primaryTitle = currentCellDescriptor["secondaryTitle"]
{
cell.sectionTitleLabel.text = primaryTitle as? String
}
}
else if currentCellDescriptor["cellIdentifier"] as! String == "shortAnswerCell" {
cell.questionTitle.text = currentCellDescriptor["primaryTitle"] as? String
cell.questionTextView.text = currentCellDescriptor["secondaryTitle"] as? String
cell.answerTextView.text = currentCellDescriptor["answerTitle"] as? String
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let indexOfTappedRow = visibleRowsPerSection[indexPath.section][indexPath.row]
let temp = cellDescriptors[indexPath.section] as? NSArray
let temp2 = temp?[indexOfTappedRow ] as? NSDictionary
let temp3 = temp2?["isExpandable"] as! Bool
if temp3 == true {
var shouldExpandAndShowSubRows = false
if temp3 == false {
// In this case the cell should expand.
shouldExpandAndShowSubRows = true
}
temp2?.setValue(shouldExpandAndShowSubRows, forKey: "isExpanded")
for i in (indexOfTappedRow + 1)...(indexOfTappedRow + (temp2?["additionalRows"] as! Int)) {
(temp![i] as AnyObject).setValue(shouldExpandAndShowSubRows, forKey: "isVisible")
}
}
getIndicesOfVisibleRows()
tblExpandable.reloadSections(NSIndexSet(index: indexPath.section) as IndexSet, with: UITableViewRowAnimation.fade)
}
I worked on that tutorial as well and completed it successfully in swift3.Your solution is given below modify accordingly.
class yourClass: UIViewController
{
#IBOutlet weak var profileTableView: UITableView!
internal var visibleRowsPerSection = [[Int]]()
internal var cellDescriptors: NSMutableArray!
// VIEW DID LOAD
override func viewDidLoad() {
super.viewDidLoad()
profileTableView.showsVerticalScrollIndicator = false
loadProfileControllerData()
profileTableSetUp()
// Do any additional setup after loading the view.
}
func loadProfileControllerData(){
if let path = Bundle.main.path(forResource: "CellDescriptor", ofType: "plist") {
cellDescriptors = NSMutableArray(contentsOfFile: path)
}
getIndicesOfVisibleRows()
profileTableView.reloadData()
}
// SHOW PARENT VISIBLE ROWS AND SAVE THERE ROW INDEX IN ARRAY
func getIndicesOfVisibleRows() {
visibleRowsPerSection.removeAll()
for currentSectionCells in cellDescriptors.objectEnumerator().allObjects as! [[[String:Any]]]{
var visibleRows = [Int]()
for row in 0..<currentSectionCells.count {
if currentSectionCells[row]["isVisible"] as! Bool == true {
visibleRows.append(row)
}
}
visibleRowsPerSection.append(visibleRows)
print(visibleRowsPerSection)
}
}
// GET REQUIRED OBJECT OF TYPE [String: Any]
func getCellDescriptorForIndexPath(indexPath: NSIndexPath) -> [String: Any] {
let indexOfVisibleRow = visibleRowsPerSection[indexPath.section][indexPath.row]
let cellDescriptorss = cellDescriptors[indexPath.section] as! NSArray
let data = cellDescriptorss.object(at: indexOfVisibleRow) as! [String:Any]
return data
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
//----------------------
// EXTENSION TO OUR PROFILE CLASS THAT DETERMINE OUR CLASS CONFIRM 2 IMPORTANT DELEGATES
extension profileViewController : UITableViewDelegate,UITableViewDataSource{
//MARK-: TABLE VIEW DELEGATE FUNCTIONS
// RETURN NUMBER OF SECTION IN TABLE VIEW
public func numberOfSections(in tableView: UITableView) -> Int{
if cellDescriptors.count != 0{
return cellDescriptors.count
}
else{
return 0
}
}
// RETURN NUMBER OF ROWS IN EACH SECTION OF TABLE VIEWS
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return visibleRowsPerSection[section].count
}
/* Return object of UITableViewCell that contains table SECTON data and USER profile data */
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let currentCellDescriptor = getCellDescriptorForIndexPath(indexPath: indexPath as NSIndexPath)
let menuCell = tableView.dequeueReusableCell(withIdentifier: currentCellDescriptor["cellIdentifier"] as! String, for: indexPath) as! yourCellClass
if currentCellDescriptor["cellIdentifier"] as! String == "parent"{
}
else if currentCellDescriptor["cellIdentifier"] as! String == "child"{
menuCell.backgroundColor = UIColor.clear
}
return menuCell
}
public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
let indexOfTappedRow = visibleRowsPerSection[indexPath.section][indexPath.row]
let cellDescriptorss = cellDescriptors[indexPath.section] as! NSArray
var data = cellDescriptorss.object(at: indexOfTappedRow) as! [String:Any]
if data["isExpandable"] as! Bool == true{
var shouldExpandAndShowSubRows = false
if data["isExpanded"] as! Bool == true{
shouldExpandAndShowSubRows = false
(cellDescriptorss[indexOfTappedRow] as AnyObject).setValue(shouldExpandAndShowSubRows, forKey: "isExpanded")
}
for i in (indexOfTappedRow + 1)...(indexOfTappedRow + (data["additionalRows"] as! Int)) {
(cellDescriptorss[i] as AnyObject).setValue(shouldExpandAndShowSubRows, forKey: "isVisible")
}
}
getIndicesOfVisibleRows()
self.profileTableView.reloadSections(NSIndexSet(index: indexPath.section) as IndexSet, with: UITableViewRowAnimation.fade)
}
Thank You for helping me out, I was stuck at a point where the sections weren't expanding even after your help, so just made some changes in the syntax as Swift 3.0 is very specific about type casting hence the didSelectRowAt wasn't functioning properly. Here is the complete didSelectRowAt method. Happy coding.
public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
let indexOfTappedRow = visibleRowsPerSection[indexPath.section][indexPath.row]
if (cellDescriptors[indexPath.section] as! [[String: AnyObject]])[indexOfTappedRow] ["isExpandable"] as! Bool == true {
var shouldExpandAndShowSubRows = false
if (cellDescriptors[indexPath.section] as! [[String: AnyObject]])[indexOfTappedRow]["isExpanded"] as! Bool == false {
// In this case the cell should expand.
shouldExpandAndShowSubRows = true
}
((cellDescriptors[indexPath.section] as! NSMutableArray)[indexOfTappedRow] as AnyObject).setValue(shouldExpandAndShowSubRows, forKey: "isExpanded")
for i in (indexOfTappedRow + 1)...(indexOfTappedRow + ((cellDescriptors[indexPath.section] as! [[String: AnyObject]])[indexOfTappedRow]["additionalRows"] as! Int)) {
((cellDescriptors[indexPath.section] as! NSMutableArray)[i] as AnyObject).setValue(shouldExpandAndShowSubRows, forKey: "isVisible")
}
}
Swift 3/4 without use of NSMutable arrays based on the tutorial and all the code wrapped in a model.
class CellsDescriptorModel {
private var cellDescriptors: [[[String:Any]]]!
private var visibleRowsPerSection : [[Int]]
var CellDescriptors : [[[String:Any]]] { get { return cellDescriptors }}
var VisibleRowsPerSection : [[Int]] { get { return visibleRowsPerSection }}
init(plist:String) {
visibleRowsPerSection = [[Int]]()
if let url = Bundle.main.url(forResource:plist, withExtension: "plist") {
do {
let data = try Data(contentsOf:url)
cellDescriptors = try PropertyListSerialization.propertyList(from: data, options: [], format: nil) as! [[[String:Any]]]
} catch {
print(error)
}
}
getIndicesOfVisibleRows()
}
func getCellDescriptorForIndexPath(indexPath: IndexPath) -> [String: Any] {
let indexOfVisibleRow = visibleRowsPerSection[indexPath.section][indexPath.row]
return cellDescriptors[indexPath.section][indexOfVisibleRow]
}
func expandCell(indexPath:IndexPath) {
let indexOfTappedRow = visibleRowsPerSection[indexPath.section][indexPath.row]
if cellDescriptors[indexPath.section][indexOfTappedRow] ["isExpandable"] as! Bool == true {
var shouldExpandAndShowSubRows = false
if cellDescriptors[indexPath.section][indexOfTappedRow]["isExpanded"] as! Bool == false {
shouldExpandAndShowSubRows = true
}
cellDescriptors[indexPath.section][indexOfTappedRow]["isExpanded"] = shouldExpandAndShowSubRows
for i in (indexOfTappedRow + 1)...(indexOfTappedRow + (cellDescriptors[indexPath.section][indexOfTappedRow]["additionalRows"] as! Int)) {
cellDescriptors[indexPath.section][i]["isVisible"] = shouldExpandAndShowSubRows
}
}
else {
if cellDescriptors[indexPath.section][indexOfTappedRow]["cellIdentifier"] as! String == "DataPickerTableViewCell" {
var indexOfParentCell: Int!
for index in (0..<indexOfTappedRow).reversed() {
if cellDescriptors[indexPath.section][index]["isExpandable"] as! Bool == true {
indexOfParentCell = index
break
}
}
cellDescriptors[indexPath.section][indexOfParentCell]["secondaryTitle"] = ""
cellDescriptors[indexPath.section][indexOfParentCell]["isExpanded"] = false
for i in (indexOfParentCell + 1)...(indexOfParentCell + (cellDescriptors[indexPath.section][indexOfParentCell]["additionalRows"] as! Int)) {
cellDescriptors[indexPath.section][i]["isVisible"] = false
}
}
}
getIndicesOfVisibleRows()
}
private func getIndicesOfVisibleRows() {
visibleRowsPerSection.removeAll()
for currentSectionCells in cellDescriptors {
var visibleRows = [Int]()
for row in 0..<currentSectionCells.count {
if currentSectionCells[row]["isVisible"] as! Bool == true {
visibleRows.append(row)
}
}
visibleRowsPerSection.append(visibleRows)
}
}
}
I am following this tutorial from Jared Davidson to implement multiple CustomTableViewCells with XIB files in my app. I have these files in my Xcode project:.
I have a TextElement: and
I have an ImageElement:
I want to test this with offline data to implement Firebase after this is working. This is my Home.swift data struct:
import Foundation
import FirebaseDatabase
struct Home {
var key:String!
let itemRef:FIRDatabaseReference?
var userUID:String!
var user:String!
// Home Element Cell Content
var elementSortNumber:Int!
var elementCellType:String!
var referenceElementID:String!
var databaseVersion:String!
init (key:String = "",
uid:String,
user:String,
elementSortNumber:Int,
elementCellType:String,
referenceElementID:String,
databaseVersion:String) {
// General (Security tracking)
self.key = key
self.itemRef = nil
self.userUID = uid
self.user = user
// Home Element Cell Content
self.elementSortNumber = elementSortNumber
self.elementCellType = elementCellType
self.referenceElementID = referenceElementID
}
init (snapshot:FIRDataSnapshot) {
// General (Security tracking)
key = snapshot.key
itemRef = snapshot.ref
if let addedByUser = snapshot.value as? NSDictionary, let _temp = addedByUser["User"] as? String {
user = _temp
} else {
user = ""
}
// Home Element Cell Content
if let homeElementSortNumber = snapshot.value as? NSDictionary, let _temp = homeElementSortNumber["Title"] as? Int {
elementSortNumber = _temp
} else {
elementSortNumber = 50
}
if let homeElementCellType = snapshot.value as? NSDictionary, let _temp = homeElementCellType["Content"] as? String {
elementCellType = _temp
} else {
elementCellType = ""
}
if let homeElementID = snapshot.value as? NSDictionary, let _temp = homeElementID["Ref Element ID"] as? String {
referenceElementID = _temp
} else {
referenceElementID = ""
}
if let textDatabaseVersion = snapshot.value as? NSDictionary, let _temp = textDatabaseVersion["DB Version"] as? String {
databaseVersion = _temp
} else {
databaseVersion = ""
}
}
}
This is the code of my TableViewController:
import UIKit
class HomeTableViewController: UITableViewController {
var arrayOfCellData = [Home]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
arrayOfCellData =
[Home(key: "",
uid:"",
user:"",
elementSortNumber:1,
elementCellType:"TextElement",
referenceElementID:"123ABC",
databaseVersion:"1"),
Home(key: "",
uid:"",
user:"",
elementSortNumber:1,
elementCellType:"ImageElement",
referenceElementID:"QWERTZ",
databaseVersion:"1"),
Home(key: "",
uid:"",
user:"",
elementSortNumber:1,
elementCellType:"TextElement",
referenceElementID:"XYZ789",
databaseVersion:"1")]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// If I return 1 the app crashes and if I comment this function it also crashes.
return 0
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayOfCellData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if arrayOfCellData[indexPath.row].elementCellType == "TextElement" {
let textElementCell = Bundle.main.loadNibNamed("TextElementTableViewCell", owner: self, options: nil) as! TextElementTableViewCell
textElementCell.textElementTitleLabel.text = arrayOfCellData[indexPath.row].referenceElementID
return textElementCell
}
else if arrayOfCellData[indexPath.row].elementCellType == "ImageElement" {
let imageElementCell = Bundle.main.loadNibNamed("ImageElementTableViewCell", owner: self, options: nil) as! ImageElementTableViewCell
imageElementCell.imageElementImageView.image = UIImage(named: "placeholder")
return imageElementCell
}
else {
let textElementDefaultCell = Bundle.main.loadNibNamed("TextElementTableViewCell", owner: self, options: nil) as! TextElementTableViewCell
textElementDefaultCell.textElementTitleLabel.text = arrayOfCellData[indexPath.row].referenceElementID
return textElementDefaultCell
}
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if arrayOfCellData[indexPath.row].elementCellType == "TextElement" {
return 116
}
else if arrayOfCellData[indexPath.row].elementCellType == "ImageElement" {
return 275
}
else {
return 116
}
}
}
This is the problem: The simulator is empty as you can see in this image Why? How can I fix that?
I would really appreciate some help. Thank you.
Register the xib files as below in viewdidload:
tableView.register(UINib(nibName: "TextElementTableViewCell", bundle: Bundle.main), forCellReuseIdentifier: "TextElementTableViewCellIdentifier")
Then in cellForRowIndex path:Access cell using their identifier
let cell : UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "TextElementTableViewCellIdentifier", for: indexPath) as! TextElementTableViewCell