I am currently developing and application for the iPhone in Swift, and I have run into a very peculiar error: in one of my UITableViewControllers,enter code here cells disappear or change sections when I scroll up and down on the Table View.
I've been dealing with this issue for a few days now, and it has even prompted me to recode the entire class, but to no avail. I have researched extensively on this error, and I believe it has something to do with my data source and how the tableView handles it, and I have also noticed that other users have had the same problem before, but I cannot find a solution that applies to my problems.
For example, here seems to deal with the cell height, but I have continued to check and double check my code, and the cell height returns the correct values.
In addition, this post talks about different errors with the tableView's data source, but I have a strong pointer to the datasource's alert array and my content and heights are correct in cellForRowAtIndexPath.
This post also deals with my question, but everything I am currently doing with the tableView is on the main thread.
Currently the tableView has 4 sections: the first, second, and fourth contain only one cell and the third has a dynamic amount of cells based on the amount of alerts the user has added (for example, it has 3 alert cells plus one "Add Alert" cell always at the bottom). The only cells that are affected are those in the 2, 3, and 4 sections.
This is what my tableView should look like always:
But, however, here is what happens when I scroll:
I first create the variables here:
var currentPrayer: Prayer! // This is the prayer that the user is currently editing
var prayerAlerts: NSMutableOrderedSet! // This is the mutable set of the prayer alerts that are included in the prayer
Then I initialize them in viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
if currentPrayer == nil {
NSException(name: "PrayerException", reason: "Current Prayer is nil! Unable to show prayer details!", userInfo: nil).raise()
}
navItem.title = currentPrayer.name // Sets the Nav Bar title to the current prayer name
prayerAlerts = currentPrayer.alerts.mutableCopy() as! NSMutableOrderedSet // This passes the currentPrayer alerts to a copy called prayerAlerts
prayerAlertsCount = prayerAlerts.count + 1
}
Below are my TableView methods:
Here is my cellForRowAtIndexPath:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
println("cellForRowAtIndexPath called for the \(cellForRowRefreshCount) time")
cellForRowRefreshCount += 1
switch indexPath.section {
case 0:
var cell = tableView.dequeueReusableCellWithIdentifier(DetailsExtendedCellID, forIndexPath: indexPath) as! PrayerDetailsExtendedCell
cell.currentPrayer = currentPrayer
cell.refreshCell()
return cell
case 1:
var cell = tableView.dequeueReusableCellWithIdentifier(SetPrayerDateCellID, forIndexPath: indexPath) as! AddPrayerDateCell
cell.currentPrayer = currentPrayer
cell.refreshCell(false, selectedPrayer: cell.currentPrayer)
return cell
case 2:
if indexPath.row == prayerAlerts.count {
var cell = tableView.dequeueReusableCellWithIdentifier(AddNewAlertCellID, forIndexPath: indexPath) as! AddPrayerAlertCell
cell.currentPrayer = currentPrayer
cell.refreshCell(false, selectedPrayer: currentPrayer)
cell.saveButton.addTarget(self, action: "didSaveNewAlert", forControlEvents: .TouchDown)
return cell
} else {
var cell = tableView.dequeueReusableCellWithIdentifier(PrayerAlertCellID, forIndexPath: indexPath) as! PrayerAlertCell
let currentAlert = prayerAlerts[indexPath.row] as! Alert
cell.alertLabel.text = AlertStore.sharedInstance.convertDateToString(currentAlert.alertDate)
return cell
}
case 3:
var cell = tableView.dequeueReusableCellWithIdentifier(AnsweredPrayerCellID, forIndexPath: indexPath) as! PrayerAnsweredCell
cell.accessoryType = currentPrayer.answered == true ? .Checkmark : .None
return cell
default:
return UITableViewCell()
}
}
And my numberOfRowsInSection:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section {
case 0: println("Returning 1 Row for section 0"); return 1
case 1: println("Returning 1 Row for section 1"); return 1
case 2: println("Returning \(prayerAlertsCount) Rows for section 2"); return prayerAlertsCount
case 3: println("Returning 1 Row for section 3"); return 1
default: println("Returning 0 Rows for section Default"); return 0
}
}
And my heightForRowAtIndexPath:
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
switch indexPath.section {
case 0: return UITableViewAutomaticDimension
case 1:
let cell = tableView.cellForRowAtIndexPath(indexPath) as? AddPrayerDateCell
if let thisCell = cell {
let isAdding = thisCell.isAddingDate
if isAdding {
if thisCell.selectedType == PrayerType.None || thisCell.selectedType == PrayerType.Daily {
println("Selected Type is None or Daily")
println("Returning a height of 89 for AddPrayerDateCell")
return 89
} else {
println("Returning a height of 309 for AddPrayerDateCell")
return 309
}
} else {
println("Returning a height of 44 for AddPrayerDateCell")
return 44
}
} else {
println("Returning a default height of 44 for AddPrayerDateCell")
return 44
}
case 2:
if indexPath.row == prayerAlerts.count {
let cell = tableView.cellForRowAtIndexPath(indexPath) as? AddPrayerAlertCell
if let thisCell = cell {
let isAdding = thisCell.isAddingAlert
if isAdding { return 309 }; return 44
} else {
return 44
}
} else {
return 44
}
case 3: return 44
default: return 44
}
}
And estimatedHeightForRowAtIndexPath:
override func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
switch indexPath.section {
case 0: return 130
case 1: return 44
case 2: return 44
case 3: return 44
default: return 44
}
}
I have tried editing these methods extensively, as well as checking the code in each individual cell. Nothing seems to work.
Does anyone have any solutions to this error? I can always update with more code if necessary, but I believe that either my data source could be the problem, or that the cell's resuse could be creating this error, but I cannot seem to pinpoint anything. Thanks in advance for any help!
UPDATE
Here is my AddAlertCell "refreshCell()" method as well as my UITableViewCell extension:
func refreshCell(didSelect: Bool, selectedPrayer: Prayer!) {
tableView?.beginUpdates()
selectionStyle = didSelect == true ? .None : .Default
saveButton.hidden = !didSelect
cancelButton.hidden = !didSelect
addNewAlertLabel.hidden = didSelect
isAddingAlert = didSelect
dateLabel.text = AlertStore.sharedInstance.convertDateToString(datePicker.date)
println("AddPrayerAlertCell: Cell Refreshed")
tableView?.scrollEnabled = !didSelect
tableView?.endUpdates()
}
UITableViewCell Extension:
extension UITableViewCell {
var tableView: UITableView? {
get {
var table: UIView? = superview
while !(table is UITableView) && table != nil {
table = table?.superview
}
return table as? UITableView
}
}
}
You shouldn't need to call beginUpdates
/ endUpdates
when you refresh the cell - these methods are used if you are adding / deleting rows or sections from the tableview.
What happens if you remove the beginUpdates()
and endUpdates()
calls?
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.