Swift UITableviewcell without reuse - ios

I create a tableView inside a tableView inside another tableView. The problem is that when the cell is reused, the tableView inside another tableView is corrupted
I usually get that error
Invalid update: invalid number of rows in section 0. The number of
rows contained in an existing section after the update (1) must be
equal to the number of rows contained in that section before the
update (2), plus or minus the number of rows inserted or deleted from
that section (1 inserted, 0 deleted) and plus or minus the number of
rows moved into or out of that section (0 moved in, 0 moved out).'
. How to create a cell in swift without the system of reuse ?
any help will be appreciated :)
private(set) let kNAME_CELL_FIRST = "Cell1"
private(set) let kNAME_CELL_SECOND = "Cell2"
private(set) let kNAME_CELL_THIRD = "Cell3"
private (set) var indexSelectedFirst : NSIndexPath!
weak var currentTableViewSecond : UITableView!
enum IDTableView : Int {
case kFIRST = 0
case kSECOND = 1
case kTHIRD = 2
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch tableView.tag {
case IDTableView.kFIRST.rawValue:
return self.categories.count
case IDTableView.kSECOND.rawValue:
return self.getItemSECOND()
case IDTableView.kTHIRD.rawValue:
return 1
default: return 0
}
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
switch tableView.tag {
case IDTableView.FIRST.rawValue :
if self.idSelectedSecond != -1 && self.indexSelectedFirst != nil && indexPath == self.indexSelectedFirst {
return HEIGHT_CELL_FIRST + (HEIGHT_CELL_SECOND * CGFloat(self.getItemSecond())) + HEIGHT_CELL_THIRD
}
else if self.indexSelectedCat != nil && indexPath == self.indexSelectedCat {
return HEIGHT_CELL_FIRST + (HEIGHT_CELL_SECOND * CGFloat(self.getItemSecond()))
}
return HEIGHT_CELL_FIRST
case IDTableView.SECOND.rawValue :
if self.indexSelectedSecond != nil && self.indexSelectedSecond == indexPath {
return HEIGHT_CELL_SECOND + HEIGHT_CELL_THIRD
} else {
return HEIGHT_CELL_SECOND
}
case IDTableView.THIRD.rawValue:
return HEIGHT_CELL_THIRD
default:
return 0
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
switch tableView.tag {
case IDTableView.FIRST.rawValue:
return self.tableViewFirst(tableView, cellForRowAtIndexPath: indexPath)
case IDTableView.Second.rawValue:
return self.tableViewSecond(tableView, cellForRowAtIndexPath: indexPath)
case IDTableView.THIRD.rawValue:
return self.tableViewThird(tableView, cellForRowAtIndexPath: indexPath)
default:
return UITableViewCell()
}
}
func tableViewFirst(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell : firstTableViewCell = tableView.dequeueReusableCellWithIdentifier(kNAME_CELL_CAT, forIndexPath: indexPath) as firstTableViewCell
let item = self.arrFirst[indexPath.row]
cell.labelName.text = item.name
cell.imageView_.image = UIImage(named: "test.jpg")
cell.imageView_.clipsToBounds = true
cell.selectionStyle = UITableViewCellSelectionStyle.None;
if self.indexSelectedFirst != nil && indexPath == self.indexSelectedFirst {
cell.labelName.textColor = UIColor(rgb: 0xf1d3b6)
cell.tableViewSecond.hidden = false
} else {
cell.labelName.textColor = UIColor(rgb: 0xf1d3b6)
cell.tableViewSecond.hidden = true
}
return cell
}
func tableViewSecond(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell : SecondTableViewCell = tableView.dequeueReusableCellWithIdentifier(kNAME_CELL_SECOND) as SecondTableViewCell
let itemParent = self.getSelectedItemFirstArray()!
let item = itemParent.arraySecond[indexPath.row]
cell.labelName.text = item.name
cell.selectionStyle = UITableViewCellSelectionStyle.None
return cell
}
func tableViewThird(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell : ThirdTableViewCell = tableView.dequeueReusableCellWithIdentifier(kNAME_CELL_THIRD) as ThirdTableViewCell
cell.labelKey.text = "test string"
cell.selectionStyle = UITableViewCellSelectionStyle.None
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
switch tableView.tag {
case IDTableView.FIRST.rawValue:
self.tableViewFirst(tableView, didSelectRowAtIndexPath: indexPath)
default:break
}
}
func tableViewFirst(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let lastIndexPath = self.indexSelectedFirst
self.closeCurrentSelectedItemK1 { (over: Bool) -> Void in
// JUST NEED TO CLOSE THE ITEM
if lastIndexPath != nil && lastIndexPath == indexPath { return }
let cell = tableView.cellForRowAtIndexPath(indexPath) as FirstTableViewCell
self.indexSelectedFirst = indexPath
self.currentTableSecond = cell.tableViewSecond
cell.tableViewSecond.hidden = false
UIView.animateWithDuration(0.6, animations: { () -> Void in
var indexPaths = [NSIndexPath]()
CATransaction.begin()
CATransaction.setCompletionBlock({ () -> Void in
self.tableViewFirst.beginUpdates()
self.tableViewFirst.endUpdates()
})
self.currentTableViewSecond.beginUpdates()
for i in 0...(self.getItemSecond()-1) {
indexPaths.append(NSIndexPath(forRow: i, inSection: 0))
}
self.currentTableViewSecond.insertRowsAtIndexPaths(indexPaths, withRowAnimation: UITableViewRowAnimation.Bottom)
self.currentTableViewSecond.endUpdates()
CATransaction.commit()
}, completion: { (over: Bool) -> Void in })
}
}
func closeCurrentSelectedItemK1(completion : ((Bool)-> Void)) -> Void{
if self.indexSelectedFirst != nil {
var indexPaths = [NSIndexPath]()
UIView.animateWithDuration(0.3, animations: { () -> Void in
let cell = self.tableViewFirst.cellForRowAtIndexPath(self.indexSelectedFirst) as FirstTableViewCell
CATransaction.begin()
self.currentTableViewSecond.beginUpdates()
self.currentTableViewSecond.hidden = true
for i in 0...self.currentTableViewSecond.numberOfRowsInSection(0)-1 {
indexPaths.append(NSIndexPath(forRow: i, inSection: 0))
}
self.indexSelectedFirst = nil
/* IF SOME TO REMOVE */
if indexPaths.count > 0 {
self.currentTableViewSecond.deleteRowsAtIndexPaths(indexPaths, withRowAnimation: UITableViewRowAnimation.Top)
}
self.currentTableViewSecond.endUpdates()
CATransaction.setCompletionBlock({ () -> Void in
self.tableViewFirst.beginUpdates()
self.tableViewFirst.endUpdates()
self.currentTableViewSecond = nil
self.indexSelectedFirst = nil
completion(true)
})
CATransaction.commit()
} else {
completion(true)
}
}

Related

Swift 5 UITableViewCell : Expand one section and collapse the expanded section

I have implemented the following code to add expand/collapse feature to UITableView sections. When user click each section1, it expands and when we click the same section1 it collapses. But, I want the section1 to collapse, if I am expanding section2. How can I implement this feature to my code added below.
struct FaqData{
var faqHead = String()
var faqImage = String()
var questionArray : [(question : String, answer : String, answerurl : String)] = [(String,String,String)]()
var openSection = Bool()
}
var supportArray = [FaqData]()
func numberOfSections(in tableView: UITableView) -> Int {
return supportArray.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0{
return 1
}
else{
if supportArray[section].openSection == true{
return supportArray[section].questionArray.count + 1
}else{
return 1
}
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
tableView.separatorStyle = UITableViewCell.SeparatorStyle.none
if indexPath.section == 0{
let cell = tableView.dequeueReusableCell(withIdentifier: "SupportCenterID", for: indexPath) as! SupportCenterTableViewCell
cell.selectionStyle = UITableViewCell.SelectionStyle.none
cell.faqCollection.reloadData()
return cell
}
else{
if indexPath.row == 0{
let cell = tableView.dequeueReusableCell(withIdentifier: "SupportFaqID") as! SupportCenterFaqTableViewCell
cell.selectionStyle = UITableViewCell.SelectionStyle.none
let faqHead = supportArray[indexPath.section].faqHead
cell.imageText.text = faqHead.capitalized
cell.imageButton.setImage(UIImage(named: supportArray[indexPath.section].faqImage), for: .normal)
return cell
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier: "QuestionID") as! SupportQuestionTableViewCell
cell.selectionStyle = UITableViewCell.SelectionStyle.none
cell.isSelected = true
cell.questionLabel.text = "Q.\(indexPath.row) " + supportArray[indexPath.section].questionArray[indexPath.row - 1].question
cell.answerLabel.text = supportArray[indexPath.section].questionArray[indexPath.row - 1].answer
print(supportArray[indexPath.section].questionArray[indexPath.row - 1].answerurl)
if supportArray[indexPath.section].questionArray[indexPath.row - 1].answerurl == ""{
cell.urlButton.isHidden = true
}
else{
cell.urlButton.isHidden = false
}
cell.urlButton.isHidden = true
cell.urlButton.tag = indexPath.row
UserDefaults.standard.set(indexPath.section, forKey: "SectionValue")
cell.urlButton.addTarget(self, action: #selector(urlButtonClicked(_:)), for: .touchUpInside)
cell.layoutMargins = UIEdgeInsets.zero
return cell
}
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if supportArray[indexPath.section].openSection == true{
if indexPath.section != 0{
if indexPath.row == 0{
let cell = tableView.cellForRow(at: indexPath) as! SupportCenterFaqTableViewCell
cell.faqView.backgroundColor = .white
cell.imageButton.tintColor = UIColor(hexString: "#D71B61")
cell.imageText.textColor = UIColor(hexString: "#D71B61")
}
}
supportArray[indexPath.section].openSection = false
let sections = IndexSet.init(integer: indexPath.section)
tableView.reloadSections(sections, with: .fade)
}
else{
supportArray[indexPath.section].openSection = true
let sections = IndexSet.init(integer: indexPath.section)
tableView.reloadSections(sections, with: .fade)
if indexPath.section != 0{
if indexPath.row == 0{
let cell = tableView.cellForRow(at: indexPath) as! SupportCenterFaqTableViewCell
cell.faqView.backgroundColor = UIColor(hexString: "#D71B61")
cell.imageButton.tintColor = .white
cell.imageText.textColor = .white
}
}
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
Can anyone provide a solution for this?
do this in didselecterow method. This is the else case of your condition
// You will need to reload multiple sections. So make an array.
var reloadSections = [Int]()
// find already opened array
if let alreadyOpenSection = supportArray.firstIndex(where: { (faq) -> Bool in
return faq.openSection
}) {
// if found, toggle the openSections bit
supportArray[alreadyOpenSection].openSection = false
// add it to reload sections array
reloadSections.append(alreadyOpenSection)
}
supportArray[indexPath.section].openSection = true
reloadSections.append(indexPath.section)
// create index set with reload sections array
let sections = IndexSet.init(reloadSections)
tableView.reloadSections(sections, with: .fade)
// below code is same
if indexPath.section != 0{
if indexPath.row == 0{
let cell = tableView.cellForRow(at: indexPath) as! SupportCenterFaqTableViewCell
cell.faqView.backgroundColor = UIColor(hexString: "#D71B61")
cell.imageButton.tintColor = .white
cell.imageText.textColor = .white
}
}

Issue deleting a single row from a table with multiple sections (Swift 4)

I'm trying to delete a row from a section in my table with multiple sections using commit editingStyle. However, it's deleting the proper indexPath.row from the section above.
How can I get it to delete from the proper section?
I followed a couple of examples on how to section a single array and index it for the tableView. I am unable to properly delete from the initial Array of custom class objects. I am also unable to find a way to transfer the IndexPath Section and Row to a second view controller to display the selected Code. It just transfers the indexPath.row but I can't get it to send the entire indexPath including the section.
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if tableView == firstTableView {
if editingStyle == .delete {
if inSearchMode == false {
codeArray.remove(at: [indexPath.section][indexPath.row])
userDefaults.setValue(NSKeyedArchiver.archivedData(withRootObject: codeArray), forKey: "codeArrayKey")
userDefaults.synchronize()
tableView.reloadData()
}
}
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let subArrayArray = codeArray.compactMap { $0.subArray as? String }
var dic = [String:[Code]]()
subArrayArray.forEach {
let subArrayKey = $0
let filterArray = codeArray.filter { $0.subArray as? String == subArrayKey }
dic[$0] = filterArray
}
let sectionTitle = sectionTitles[section]
let sectionCodes:[Code] = dic[sectionTitle]!
if tableView == firstTableView {
if inSearchMode == true {
return filteredCodeArray.count
} else {
return sectionCodes.count
}
} else if tableView == autoTableview {
return locationFilteredCodeArray.count
} else {
return 1
}
}
func numberOfSections(in tableView: UITableView) -> Int {
if tableView == firstTableView {
if inSearchMode == false {
indexCodes(enterArray: codeArray)
return sectionTitles.count
} else if inSearchMode == true {
return 1
}
}
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == firstTableView {
if let cell = tableView.dequeueReusableCell(withIdentifier: "newCodesProtoCell") as? NewCodesViewCell {
let code: Code!
if inSearchMode == true {
code = filteredCodeArray[indexPath.row]
cell.configureCell(code: code)
} else {
let subArrayArray = codeArray.compactMap { $0.subArray }
var dic = [String:[Code]]()
subArrayArray.forEach {
let subArrayKey = $0
let filterArray = codeArray.filter { $0.subArray == subArrayKey }
dic[$0] = filterArray
}
let sectionTitle = sectionTitles[indexPath.section]
let sectionCodes:[Code] = dic[sectionTitle]!
code = sectionCodes[indexPath.row]
cell.configureCell(code: code)
}
return cell
}
}
if let cell = tableView.dequeueReusableCell(withIdentifier: "secondNewCodesProtoCell") as? SecondNewCodesProtoCell {
let code: Code!
if locationFilteredCodeArray.count != 0 {
locationAuthStatus()
code = locationFilteredCodeArray[indexPath.row]
cell.configureSecondCell(code: code)
}
return cell
}
return UITableViewCell()
}
This is how I'm getting the array of index names (headers) as this may be causing some of the issues.
This is written to index the [Code] by the second letter in the .location.
func indexCodes(enterArray: [Code]) {
var codeValues = [String]()
for code in enterArray {
var initCodeKey = String(code.location.prefix(2))
initCodeKey.remove(at: initCodeKey.startIndex)
let codeKey = initCodeKey.capitalized
codeValues.append(codeKey)
}
var encountered = Set<String>()
var result: [String] = []
for value in codeValues {
if encountered.contains(value) {
} else {
encountered.insert(value)
result.append(value)
}
}
sectionTitles = result.sorted(by: <)
}
You need to do 2 steps.
1. From your codeArray, get the dictionary from indexPath.section and then your Code object from [Code] saved in that dictionary. Remove code at indexPath.row and then reserve it to dictionary and replace dictionary object in CodeArray
2. self.tableView.reloadRows(at: [IndexPath(row: 0, section: 0)], with: .fade)
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if tableView == firstTableView {
if editingStyle == .delete {
if inSearchMode == false {
codeArray.remove(at: [indexPath.section][indexPath.row])
var dict = codeArray[indexPath.section]
let key = dict.allKeys.first
var codes = dict[key]
//remove code from [Code]
codes.remove(at: indexPath.row)
dict[key] = codes
codeArray[indexPath.section] = dict
userDefaults.setValue(NSKeyedArchiver.archivedData(withRootObject: codeArray), forKey: "codeArrayKey")
userDefaults.synchronize()
self.tableView.reloadRows(at: [IndexPath(row: indexPath.row, section: indexPath.section)], with: .fade)
}
}
}
let me know if you find any issue implementing it.

How to hide the sections in the tableview after deleting a particular section from tableview?

I am having three sections (see the image) in which one section is to display the items and remaining two cells are designed by using stroyboard now if i delete all the items using delete button in first section then the remaining two sections need to be hidden and to display some text can anyone help me how to do this ?
func numberOfSections(in tableView: UITableView) -> Int{
// #warning Incomplete implementation, return the number of sections
return 3
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
if (section == 0){
return itemsArray.count
}else{
return 1
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! productTableViewCell
tableDetails.isHidden = false
myActivityIndicator.stopAnimating()
let arr = itemsArray[indexPath.row]
let urls = NSURL(string: arr["img"] as! String)
let data = NSData (contentsOf: urls! as URL)
cell.imageview.image = UIImage(data: data! as Data)
cell.nameLabel.text = arr["productName"]as! String
var price = arr["productPrice"] as! String
print(price)
var Quantity : Float = 1
let itemId : Int = arr["sku"] as! Int
print(itemId)
for aDic in CartArray{
if aDic["id"] == String(itemId){
Quantity = Float(String(aDic["quantity"]!))!
}
}
print(CartArray)
cell.stepper.value = Double(Int(Quantity))
cell.stepper.tag = indexPath.row
cell.stepper.addTarget(self, action: #selector(stepperValueChange(stepper:)), for:.valueChanged)
price = price.replacingOccurrences(of: "KD", with: "")
cartstring = String(Float(price)! * Quantity) + "0KD"
cell.priceLabel.text = cartstring
let quantityText = String(Quantity)
let endIndex = quantityText.index(quantityText.endIndex, offsetBy: -2)
let truncated = quantityText.substring(to: endIndex)
cell.quantityTextField.text = truncated
cell.price = price
cell.deleteButton.addTarget(self, action: #selector(deleteButtonAction(button:)), for: .touchUpInside)
cell.deleteButton.tag = indexPath.row
return cell
}else if indexPath.section == 1{
let cell = tableView.dequeueReusableCell(withIdentifier: "couponcell", for: indexPath) as! CouponTableViewCell
cell.applyButton.addTarget(self, action: #selector(applyButtonAction(button:)), for: .touchUpInside)
return cell
}else {
let cell = tableView.dequeueReusableCell(withIdentifier: "checkout", for: indexPath) as! checkoutTableViewCell
cell.finalCartpriceLabel.text = total
return cell
}
}
func deleteButtonAction(button : UIButton) {
let buttonPosition = button.convert(CGPoint(), to: tableDetails)
let index = tableDetails.indexPathForRow(at: buttonPosition)
self.itemsArray.remove(at: (index?.row)!)
self.tableDetails.deleteRows(at: [index!], with: .automatic)
tableDetails.reloadData()
}
Modify your numberOfSections with:
func numberOfSections(in tableView: UITableView) -> Int {
if self.itemsArray.count > 0 {
return 3
}
//Show Message List is Empty
return 1
}
You can manage something like,
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
if (section == 0){
return itemsArray.count
}else{
if self.itemsArray.count == 0 {
return 0
}
else{
return 1
}
}
}
You can just check for self.itemsArray.count > 0 inside your func numberOfSections(in:) and show all the three sections for this condition. Otherwise, return only the first section and this will automatically hide the other two.
Example:
func numberOfSections(in tableView: UITableView) -> Int {
if self.itemsArray.count > 0 {
return 3
}
return 1
}
in numberOfSection datasource methods, check if itemArray has no elements, return just one section. In cellForRowAtIndexPath, check the same condition again, and show the empty text in this.
func numberOfSections(in tableView: UITableView) -> Int {
if(itemArray.count > 0)
{
if (section == 0){
return itemsArray.count
}else{
return 1
}
} else {
return 1;
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if(itemArray.count > 0)
{
}else {
//Show empty text view
}
}
this code worked for me perfectly
func deleteButtonAction(button : UIButton) {
let buttonPosition = button.convert(CGPoint(), to: tableDetails)
let index = tableDetails.indexPathForRow(at: buttonPosition)
self.itemsArray.remove(at: (index?.row)!)
self.tableDetails.deleteRows(at: [index!], with: .automatic)
tableDetails.reloadData()
if (tableView(tableDetails, numberOfRowsInSection: 0) == 0){
tableDetails.isHidden = true
}
if (tableDetails.isHidden == true){
self.loadingLabel.textColor = UIColor.gray
self.loadingLabel.textAlignment = NSTextAlignment.center
self.loadingLabel.text = "Your shopping cart is empty"
self.loadingLabel.frame = CGRect(x: 130, y: 320, width: 140, height: 30)
view.addSubview(loadingLabel)
}
}

How to dequeue correct custom cell type in tableview:cellForRow:AtIndexPath

I'm doing a SearchBar and when you type the word "nike" it has to display custom cells "shop Types" that has that name in their title but also the brand nike if it exists in the brands array.
For the moment I manage to get the correct numbers of rows in table view:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if(searchActive) {
return filtered.count + filteredBrands.count
}
return shops.count;
}
Also managed to filter brands and shops arrays:
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
filtered = shopNames.filter({ (text) -> Bool in
let tmp: NSString = text
let range = tmp.rangeOfString(searchText, options: NSStringCompareOptions.CaseInsensitiveSearch)
return range.location != NSNotFound
})
filteredBrands = brandNames.filter({ (text) -> Bool in
let tmp: NSString = text
let range = tmp.rangeOfString(searchText, options: NSStringCompareOptions.CaseInsensitiveSearch)
return range.location != NSNotFound
})
if(filtered.count == 0 && filteredBrands.count == 0){
searchActive = false
} else {
searchActive = true
}
//user pressed the x button to clean content
if(searchText == "") {
searchActive = false
}
currentTableView.reloadData()
}
But now I'm stuck in tableView:cellForRow:atIndexPath() :
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if(self.brandNamesCopyCounter > 0){
brandNamesCopyCounter -= 1
let cell = currentTableView.dequeueReusableCellWithIdentifier("brandCell") as! HomeSearchBrandCell
if(searchActive){
if(filteredBrands.count > indexPath.row){
cell.title.text = filteredBrands[indexPath.row]
if(cell.iconFacility != nil){
cell.iconFacility.image = UIImage.init(named: "brands.pdf")
}
}
} else {
print(indexPath.row)
if(brandsArray.count > indexPath.row){
cell.title.text = brandsArray[indexPath.row].name_en
}
if(cell.iconFacility != nil){
cell.iconFacility.image = UIImage.init(named: "brands.pdf")
}
}
return cell
}else{
let cell = currentTableView.dequeueReusableCellWithIdentifier("homeSearchCell") as! HomeSearchCell
if(searchActive){
if(filtered.count > indexPath.row){
print(indexPath.row)
cell.title.text = self.filtered[indexPath.row]
if(cell.iconFacility != nil){
cell.iconFacility.image = UIImage.init(named: "shops.pdf")
}
}
} else {
cell.title.text = shops[indexPath.row].name
if(cell.iconFacility != nil){
cell.iconFacility.image = UIImage.init(named: "shops.pdf")
}
}
return cell
}
}
I really don't have a clue on how to dequeue the correct cell and I'm having weird errors when reuse cells. Can anybody help?
I think that this example can help you
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 2
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if(section == 0)
{
return filtered.count
}
return filteredBrands.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var tableCell2 : UITableViewCell
if(indexPath.section == 0)
{
tableCell2 = tableView.dequeueReusableCellWithIdentifier("ShopCell") as! ShopCell
}else
{
tableCell2 = tableView.dequeueReusableCellWithIdentifier("BrandsCell") as! BrandsCell
}
return tableCell2
}
I hope this helps you

Different UITableViewCells overlapping

I have a UITableView with 3 prototype cells and 3 custom cell classes:
FriendCell
FriendRequestCell and AddFriendCell.
Initialized, the table displays Friends.
If there are any FriendRequests, it displays them in the section above Friends.
If there are no FriendRequests, it only displays Friends.
However, I also have a UISearchBar that searches for users and when it has results, should return AddFriendCells and reload the table.
Instead, I get this:
Code:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if searching == true {
if let cell = tableView.dequeueReusableCellWithIdentifier("AddFriendCell", forIndexPath: indexPath) as? AddFriendCell {
let resultCell = userResults[indexPath.row]
cell.configureCell(resultCell)
}
} else {
if friendRequests.isEmpty || (indexPath.section == 1) {
if let cell = tableView.dequeueReusableCellWithIdentifier("FriendCell", forIndexPath: indexPath) as? FriendCell {
let friendCell = friends[indexPath.row]
cell.configureCell(friendCell)
}
} else {
if (indexPath.section == 0) {
if let cell = tableView.dequeueReusableCellWithIdentifier("FriendRequestCell", forIndexPath: indexPath) as? FriendRequestCell {
let friendRequestCell = friendRequests[indexPath.row]
cell.configureCell(friendRequestCell)
}
}
}
}
return FriendCell()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
if searching == true {
return 1
} else {
return friendsDataSource.count
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searching == true {
return userResults.count
} else {
return friendsDataSource[section].count
}
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if searching == true {
return nil
} else {
if friendsDataSource.count > 1 {
if section == 0 {
return "Friend Requests"
} else if section == 1 {
return "Friends"
}
} else {
return "Friends"
}
return "Friends"
}
}
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if searching == true {
return 0
} else {
return 25
}
}
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
searching = true
searchBar.resignFirstResponder()
userResults = [UserProfile]()
activitySpinner.startAnimating()
if let searchText = searchBar.text {
let userProfileQuery = PFQuery(className: "UserProfile")
userProfileQuery.whereKey("username", containsString: searchText)
userProfileQuery.findObjectsInBackgroundWithBlock({ resultArray, error in
if error != nil {
print("there's been an error searching for users: \(error)")
} else if let resultArray = resultArray {
print("number of results: \(resultArray.count)")
self.parseResults = resultArray
for userProfile in resultArray {
let username = userProfile["username"] as! String
let profilePicUrl = userProfile["profilePicUrl"] as! String
let parseObjectId = userProfile.objectId!
let newProfile = UserProfile(username: username, profilePicUrl: profilePicUrl, parseObjectId: parseObjectId)
self.userResults.append(newProfile)
}
self.tableView.reloadData()
self.activitySpinner.stopAnimating()
}
})
}
}
Any ideas on the root of the problem?
OK, here is the code for multiple types of cell:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if searching == true {
let cell = tableView.dequeueReusableCellWithIdentifier("AddFriendCell", forIndexPath: indexPath) as! AddFriendCell
// ...configure your cell...
return cell
}
else{
if friendRequests.isEmpty || (indexPath.section == 1) {
let cell = tableView.dequeueReusableCellWithIdentifier("FriendCell", forIndexPath: indexPath) as! FriendCell
// ...configure your cell...
return cell
}
else{
if (indexPath.section == 0) {
let cell = tableView.dequeueReusableCellWithIdentifier("FriendRequestCell", forIndexPath: indexPath) as! FriendRequestCell
// ...configure your cell...
return cell
}
else {
// Decide what to do if section is NOT 0. If this CAN happen
// and you don't have a cell type to return, it is a design flaw.
// don't add a adummy "return FriendCell()" as a fallback for a
// case that should never happen, to make the compiler happy.
// This type of error should be caught during development.
}
}
}
}
(See the comment paragraph on how to deal with the unsuported execution path)
Alternatively, you could declare cell as a var of type UITableViewCell outside of all if/else blocks, assign it to the appropriatey dequeued cell inside, (i.e., remove the let keyword if modifying the code above), and return it at the very end.
But you still need to make sure it is initialized before returning.
if the method findObjectsInBackgroundWithBlock is asynchronous, I think you can use self.tableView.reloadData() instead of dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
})
add self.tableView.rowHeight = 50
and you don't return your addfriendcell. you just return FriendsCell() at the last line. add the return cell.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if searching == true {
if let cell = tableView.dequeueReusableCellWithIdentifier("AddFriendCell", forIndexPath: indexPath) as? AddFriendCell {
let resultCell = userResults[indexPath.row]
cell.configureCell(resultCell)
return cell! //add the return
}
} else {
if friendRequests.isEmpty || (indexPath.section == 1) {
if let cell = tableView.dequeueReusableCellWithIdentifier("FriendCell", forIndexPath: indexPath) as? FriendCell {
let friendCell = friends[indexPath.row]
cell.configureCell(friendCell)
return cell! //add the return
}
} else {
if (indexPath.section == 0) {
if let cell = tableView.dequeueReusableCellWithIdentifier("FriendRequestCell", forIndexPath: indexPath) as? FriendRequestCell {
let friendRequestCell = friendRequests[indexPath.row]
cell.configureCell(friendRequestCell)
return cell! //add the return
}
}
}
}
return FriendCell()
}

Resources