Selecting a custom cell activates another cell - swift

I have a custom cell class that has an image, a few text labels(1 truncated), and a button:
class CustomTVC: UITableViewCell {
/* Outlets */
#IBOutlet weak var imageHolder: UIImageView!
#IBOutlet weak var concatenatedTitleHolder: UILabel!
#IBOutlet weak var localDateHolder: UILabel!
#IBOutlet weak var descriptionHolder: UILabel!
#IBOutlet weak var seeMoreButton: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
}
}
When the user clicks on the button, it shows the full description of the truncated text label. However, the problem I have now is when the user clicks on the button for a specific cell, it shows the full description for the cell that the user clicked, and also the full description of another cell.
I know the reason that's happening is because the tableview reuses the cell via dequeueReusableCellWithIdentifier. How would I go about implementing a function that will make sure that when a user clicks on the button for a specific cell, only that cell's full description is shown?
Code for tableview:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("customCell", forIndexPath: indexPath) as! CustomTVC
if listOfShows.count != 0 {
// Downloading and displaying picture
if let downloadPicture: UIImage = helperFunctions.downloadImage(listOfShows[indexPath.row].imageLink) {
cell.imageHolder.image = downloadPicture
}
// Enlarging / dismissing picture
cell.imageHolder.userInteractionEnabled = true
let newTapped = UITapGestureRecognizer(target: self, action: #selector(MainTVC.imagedTapped(_:)))
cell.imageHolder.addGestureRecognizer(newTapped)
// Concatenating channel + series + episode title
let concatenatedTitle = listOfShows[indexPath.row].channel + " " + listOfShows[indexPath.row].series + " " + listOfShows[indexPath.row].episodeTitle
// Converting into local date / time
let universalTime = helperFunctions.localDateAndTimeConverter(listOfShows[indexPath.row].originalAirDate)
/* Other labels */
cell.concatenatedTitleHolder.text = concatenatedTitle
cell.localDateHolder.text = universalTime
cell.descriptionHolder.text = listOfShows[indexPath.row].description
cell.seeMoreButton.tag = indexPath.row
cell.seeMoreButton.addTarget(self, action: #selector(MainTVC.buttonTapped(_:markedArray:)), forControlEvents: .TouchUpInside)
resetCellSettings(cell)
}
return cell
}
func buttonTapped(sender: UIButton, markedArray: [Bool]) {
let indexPath = NSIndexPath(forRow: sender.tag, inSection: 0)
let cell = tableView.cellForRowAtIndexPath(indexPath) as! CustomTVC
cell.seeMoreButton.hidden = true
cell.descriptionHolder.numberOfLines = 0
cell.descriptionHolder.lineBreakMode = NSLineBreakMode.ByWordWrapping
cell.descriptionHolder.sizeToFit()
}
func resetCellSettings(cell: CustomTVC) {
cell.seeMoreButton.hidden = false
cell.descriptionHolder.numberOfLines = 1
cell.descriptionHolder.lineBreakMode = NSLineBreakMode.ByTruncatingTail
cell.descriptionHolder.sizeToFit()
}

You should put buttonTapped func in CustomTVC class. And set outlet IBAction of seeMoreButton for that func when cell created.

Related

tableviewcell changing the images while scrolling

I have four button inside a tableview cell and each of the button has a unique as 0,1,2 and 3 respectively.
These four buttons and linked to a single button action method.
The code inside tableviewcell is as follows:
#IBOutlet weak var questionLbl: UILabel!
#IBOutlet weak var q1: UIButton!
#IBOutlet weak var q2: UIButton!
#IBOutlet weak var q3: UIButton!
#IBOutlet weak var q4: UIButton!
typealias emptyButtonClosure = (String,Int) -> ()
var buttonTapped:emptyButtonClosure?
#IBAction func btnClicked(sender:UIButton){
let buttonArray = [q1,q2,q3,q4]
for button in buttonArray {
if sender.tag == button!.tag{
button!.isSelected = true;
if let buttonTapped = buttonTapped{
buttonTapped(sender.titleLabel!.text!,sender.tag)
}
if let image = UIImage(named: "checked-radio") {
button!.setImage(image, for: .normal)
}
else
{
let image1 = UIImage(named: "unchecked-radio")
button!.setImage(image1, for: .normal)
}
}else{
button!.isSelected = false;
if let image = UIImage(named: "unchecked-radio") {
button!.setImage(image, for: .normal)
}
else
{
let image1 = UIImage(named: "checked-radio")
button!.setImage(image1, for: .normal)
}
}
}
}
These buttons are grouped into single array called as buttonarray because these buttons are radio buttons and only single selection is allowed.
Now the issue is,the value is fetched correctly for each cell in the tableview.But when the tableview is scrolled,the image position keeps changing.The code inside tableview is as follows:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "questioncell", for: indexPath) as! ChildQuestionCell
cell.questionLbl.text = self.listData?.nanniBookingDetails.questionsData[indexPath.row].question
cell.q1.setTitle(self.listData?.nanniBookingDetails.questionsData[indexPath.row].option1, for: .normal)
cell.q2.setTitle(self.listData?.nanniBookingDetails.questionsData[indexPath.row].option2, for: .normal)
cell.q3.setTitle(self.listData?.nanniBookingDetails.questionsData[indexPath.row].option3, for: .normal)
cell.q4.setTitle(self.listData?.nanniBookingDetails.questionsData[indexPath.row].option4, for: .normal)
cell.buttonTapped = { value,index in
print("button selected is",value,index)
self.answers.append(value)
}
return cell
}
How to retain the image position even when it is scrolled.Like the image selected for 1st row should not be shown in 3rd or 4th row.It should remain only in 1st row.
Please let me know how to solve this?

Best Approach to make Calculation in tableviewcells and sums up in UILabel

My Cart looks like this
What should be the best approach to do calculation of all cells and sums up total Amount label
Cart Working like this :
Increment in cell's item doubles the value of price label but when i dequeue new cell it already has that increment value
When tried to work with custom delegate , Delegate always shows nil
What should I do ? why my delegate is always nil ?
TableViewCell
class ShoppingCartCell: UITableViewCell {
#IBOutlet weak var cellView:UIView!
#IBOutlet weak var productImageView:UIImageView!
#IBOutlet weak var productName:UILabel!
#IBOutlet weak var brandName:UILabel!
#IBOutlet weak var productPrice:UILabel!
#IBOutlet weak var modifier1Lbl:UILabel!
#IBOutlet weak var modifier2Lbl:UILabel!
#IBOutlet var counterBtns:[UIButton]!
#IBOutlet weak var counterLbl:UILabel!
var delegate : cellDelegateFunc?
override func layoutMarginsDidChange() {
super.layoutMarginsDidChange()
contentView.frame = contentView.frame.inset(by: UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10))
productImageView.layer.cornerRadius = productImageView.frame.height / 4
cellView.roundUIViewWithShadow(cornerRadius: 4, shadowColor: .darkGray)
cellView.layer.masksToBounds = false
cellView.layer.shadowColor = UIColor.lightGray.cgColor
cellView.layer.shadowOpacity = 1
cellView.layer.shadowOffset = .zero
}
override func awakeFromNib() {
super.awakeFromNib()
cellView.layer.cornerRadius = cellView.frame.height / 16
productImageView.layer.cornerRadius = productImageView.frame.height / 16
}
#IBAction func counter(_ sender:UIButton){
self.delegate?.countItems(self)
}
}
CartViewController (Particular Portion)
class ShoppingBagVC: UIViewController , cellDelegateFunc {
func countItems(_ cell: ShoppingCartCell) {
print("print")
}
}
Protocol
protocol cellDelegateFunc : class {
func countItems(_ cell:ShoppingCartCell)
}
CellForRow
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if cartAllData[indexPath.row].deal.data != nil {
let cell = cartTableView.dequeueReusableCell(withIdentifier: "cell3", for: indexPath) as! ShoppingCartDealCell
cell.originalPrice = Int(cartAllData[indexPath.row].deal.data!.dealPrice)
cell.productName.text = cartAllData[indexPath.row].deal.data?.dealName
cell.productPrice.text = "Rs.\(String(cell.originalPrice))"
cell.freeItem.text = cartAllData[indexPath.row].deal.data?.freeProduct
cell.productImageView?.sd_setImage(with: URL(string: cartAllData[indexPath.row].deal.data!.imageURL), completed: nil)
return cell
} else {
let cell = cartTableView.dequeueReusableCell(withIdentifier: "cell2", for: indexPath) as! ShoppingCartCell
var originalPrice = Int()
var price : Int = 2{
didSet {
cell.productPrice.text = "Rs.\(String(price))"
}
}
var count : Int = 1{
didSet {
cell.counterLbl.text = String(count)
price = originalPrice * count
}
}
if let value = cartAllData[indexPath.row].deal.data?.quantity {
cell.counterLbl.text = String(value)
}
if let value = cartAllData[indexPath.row].product.data?.quantity {
cell.counterLbl.text = String(value)
}
originalPrice = Int(cartAllData[indexPath.row].product.data!.productBasePrice)
cell.productPrice.text = "Rs.\(String(originalPrice))"
cell.productName.text = cartAllData[indexPath.row].product.data?.productName
cell.productImageView?.sd_setImage(with: URL(string: cartAllData[indexPath.row].product.data!.imageURL), completed: nil)
cell.modifier1Lbl.text = cartAllData[indexPath.row].product.data?.modifier1
cell.modifier2Lbl.text = cartAllData[indexPath.row].product.data?.modifier2
return cell
}
}
As #joakim said in comment you are doing calculations in a UI! and it's not a correct way
When a UITableView scrolls every cell will reload because of reusing and every cell will lose its state because it loads again. so you must store state of each cell in a Model and pass it to your cell each time a cell loads.
As you requested The Best approach would be to use a ViewModel or a Presenter to store state of a View (here your cell) and in every load you feed that View (for example in your cellForRow) with the stored States or Properties

How can I display different products from an array in each custom cell?

I need to display three or less products from an array in every custom cell of a tableview, I putted three image views and three labels in each cell to show the products. This is my TableviewDataSource Code.
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return products.count / 3
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "HomeCell", for: indexPath) as! HomeTableViewCell
let sectionIndex = indexPath.section
if (sectionIndex + index + 2) <= products.count && (sectionIndex + index + 1) <= products.count && currentUser != nil {
cell.product1 = self.products[sectionIndex + index]
cell.product2 = self.products[sectionIndex + index + 1]
cell.product3 = self.products[sectionIndex + index + 2]
cell.selectionStyle = .none
index += 2
}
cell.delegate = self
return cell
}
And this is my TableviewCell Code.
protocol CustomCell : class {
func accessToProduct(product: Product)
func performSegueToProduct()
}
class HomeTableViewCell: UITableViewCell {
#IBOutlet weak var image1 : UIImageView!
#IBOutlet weak var image2 : UIImageView!
#IBOutlet weak var image3 : UIImageView!
#IBOutlet weak var label1: UILabel!
#IBOutlet weak var label2: UILabel!
#IBOutlet weak var label3: UILabel!
weak var delegate: CustomCell?
var product1: Product! {
didSet {
updateUI1()
}
}
var product2: Product! {
didSet {
updateUI2()
}
}
var product3: Product! {
didSet {
updateUI3()
}
}
var cache = SAMCache.shared()
func downloadPopularImages (product: Product, imageView: UIImageView, label: UILabel) {
imageView.image = nil
let productuid = product.uid
let profileImageKey = "\(productuid)"
if let image = cache?.object(forKey: profileImageKey) as? UIImage {
imageView.image = image
} else {
product.downloadPopularProductImage { [weak self] (image, error) in
if let error = error {
print(error.localizedDescription)
} else {
imageView.image = image
self?.cache?.setObject(image, forKey: profileImageKey)
}
}
}
}
// MARK: - Update the UI downloading product images and adding tapGestureRecognizer
func updateUI1() {
downloadPopularImages(product: product1, imageView: image1, label: label1)
label1.text = product1.name + " \(product1.subName)"
let tapGestureRecognizer1 = UITapGestureRecognizer(target: self, action: #selector(self.image1IsTapped))
image1.addGestureRecognizer(tapGestureRecognizer1)
}
func image1IsTapped () {
delegate?.accessToProduct(product: product1)
print(product1)
delegate?.performSegueToProduct()
}
func updateUI2() {
downloadPopularImages(product: product2, imageView: image2, label: label2)
label2.text = product2.name + " \(product2.subName)"
let tapGestureRecognizer2 = UITapGestureRecognizer(target: self, action: #selector(self.image2IsTapped))
image2.addGestureRecognizer(tapGestureRecognizer2)
}
func image2IsTapped() {
delegate?.accessToProduct(product: product2)
delegate?.performSegueToProduct()
}
func updateUI3() {
downloadPopularImages(product: product3, imageView: image3, label: label3)
label3.text = product3.name + " \(product3.subName)"
let tapGestureRecognizer3 = UITapGestureRecognizer(target: self, action: #selector(self.image3IsTapped))
image3.addGestureRecognizer(tapGestureRecognizer3)
}
func image3IsTapped() {
delegate?.accessToProduct(product: product3)
delegate?.performSegueToProduct()
}
}
However, if I have an array with a number of products that is not divisible by 3, does not correctly display all products. Imagine that we have 5 products, so in the first cell it will display the three first products and in the second cell it will display the two remaining products and there will be one image view and one label empties. But this doesn't happen, the code fills the above with one of the products already displayed.
I tried to use a collection view with three cells y each tableview cell but I need the cells of the uicollectionview to be fixed and not cut with the edges, so for that reason i implemented the three image views and three labels.
How can I fix this?
This is what I want:

Tab Bar Item hidden behind tableview / not being shown?

I have an empty view with a tab bar pictured below, when i load a routine a table appears containing the contents, however it seems to overlay the tab bar killing off app navigation. Its not sized in the storyboard to overlay it and its constraint locked to not do so, so im unsure why this is happening, pics of the issue and VC's code below:
VC Code:
import Foundation
import UIKit
import CoreData
class RoutineController: UIViewController, UITableViewDataSource, UITableViewDelegate {
// MARK: - DECLARATIONS
#IBAction func unwindToRoutine(segue: UIStoryboardSegue) {}
#IBOutlet weak var daysRoutineTable: UITableView!
#IBOutlet weak var columnHeaderBanner: UIView!
#IBOutlet weak var todaysRoutineNavBar: UINavigationBar!
#IBOutlet weak var addTOdaysRoutineLabel: UILabel!
let date = Date()
let dateFormatter = DateFormatter()
let segueEditUserExerciseViewController = "editExerciseInRoutineSegue"
//This is the selected routine passed from the previous VC
var selectedroutine : UserRoutine?
// MARK: - VIEWDIDLOAD
override func viewDidLoad() {
super.viewDidLoad()
setupView()
daysRoutineTable.delegate = self
daysRoutineTable.dataSource = self
view.backgroundColor = (UIColor.customBackgroundGraphite())
dateFormatter.dateStyle = .short
dateFormatter.dateFormat = "dd/MM/yyyy"
let dateStr = dateFormatter.string(from: date)
todaysRoutineNavBar.topItem?.title = dateStr + " Routine"
}
// MARK: - VIEWDIDAPPEAR
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.daysRoutineTable.reloadData()
self.updateView()
}
// MARK: - TABLE UPDATE COMPONENTS
private func setupView() {
updateView()
}
// MARK: - TABLE SETUP
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let count = self.selectedroutine?.userexercises?.count
{
print("exercises: \(count)")
return count
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as? TodaysRoutineTableViewCell else {
fatalError("Unexpected Index Path")
}
cell.backgroundColor = UIColor.customBackgroundGraphite()
cell.textLabel?.textColor = UIColor.white
configure(cell, at: indexPath)
return cell
}
// MARK: - VIEW CONTROLER ELEMENTS VISIBILITY CONTROL
fileprivate func updateView() {
var hasUserExercises = false
if let UserExercise = self.selectedroutine?.userexercises {
hasUserExercises = UserExercise.count > 0
}
addTOdaysRoutineLabel.isHidden = hasUserExercises
columnHeaderBanner.isHidden = !hasUserExercises
daysRoutineTable.isHidden = !hasUserExercises
}
// MARK: - SETTING DATA FOR A TABLE CELL
func configure(_ cell: TodaysRoutineTableViewCell, at indexPath: IndexPath) {
if let userExercise = selectedroutine?.userexercises?.allObjects[indexPath.row]
{
print("\((userExercise as! UserExercise).name)")
cell.todaysExerciseNameLabel.text = (userExercise as! UserExercise).name
cell.todaysExerciseRepsLabel.text = String((userExercise as! UserExercise).reps)
cell.todaysExerciseSetsLabel.text = String((userExercise as! UserExercise).sets)
cell.todaysExerciseWeightLabel.text = String((userExercise as! UserExercise).weight)
}
}
}
requested table constraints
Debug hierarchy
The Segue that sends the user back to the view that looses its tab bar
if segue.identifier == "addToTodaySegue" {
let indexPath = workoutTemplateTable.indexPathForSelectedRow
let selectedRow = indexPath?.row
print("selected row\(selectedRow)")
if let selectedRoutine = self.fetchedResultsController.fetchedObjects?[selectedRow!]
{
if let todaysRoutineController = segue.destination as? RoutineController {
todaysRoutineController.selectedroutine = selectedRoutine
}
}
}
I also feel perhaps the viewDidAppear code may cause the issue, perhaps the super class?
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.daysRoutineTable.reloadData()
self.updateView()
Updated storyboard image
I suspect you need to embed your viewController in a UINavigationController.
Consider the following setup:
I suspect your setup is like the upper one:
TapBar -> ViewController -show segue-> ViewController
Which results in a hidden tapbar, like in your description:
While the bottom setup:
TapBar -> NavigationCntroller -rootView-> ViewController -show segue-> ViewController
results in:
which is what you want, how I understood.
Update
It's hard to see. The screenshot of your Storyboard is in pretty low resulution, but the segues look wrong. Double check them. A Segue of type show (e.g push) looks like this:
Also clear project and derived data. Segue type changes sometime are ignored until doing so.
Try calling this self.view.bringSubviewToFront(YourTabControl).
The previous suggestion should work. But the content at the bottom part of tableview will not be visible as the tabbar comes over it. So set the bottom constraint of tableview as the height of tabbar.

Found nil when trying to read from table cell in Swift

I have a problem I do not understand since I am new to iPhone app programming and Swift.
I have a TableView in Swift which I use to display some results on. I have added a button to each cell such that the user can choose different cells and then press delete in order to delete the results shown in the cell.
For just a few number of results that worked just fine but now I have started to get nil-exception.
The program crashes in the function getIndexToDelete when I try to get the cell for a certain row.
Here is the code where I handle the table:
import UIKit
class DailyResultTable: UIViewController, UITableViewDataSource, UITableViewDelegate {
var results = Results()
var yearShownIndex = 0
var monthShownIndex = 0
var dayShownIndex = 0
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var DeleteButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// self.view.backgroundColor = UIColor(patternImage: UIImage(named: "StatisticBackground")!)
}
// DataSource
func numberOfSectionsInTableView(tableview: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// return (self.results?.getDayList(yearShownIndex, posMonth: monthShownIndex).count)!
print("return number of rows")
if (results.getYearList().count > 0 ){
if (results.getMonthList(yearShownIndex).count > 0){
if (results.getDayList(yearShownIndex, posMonth: monthShownIndex).count > dayShownIndex){
return (results.getDayList(yearShownIndex, posMonth: monthShownIndex)[dayShownIndex].results.count)
}
}
}
print("No numbers to show return 0")
return 0;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("DayResultCell", forIndexPath: indexPath) as! ResultTableCell
let row = indexPath.row
//cell.ResultField.text = String((results?.getDayList(yearShownIndex, posMonth: monthShownIndex)[row].day)!) + "/" + String((results?.getMonthList(yearShownIndex)[monthShownIndex].month)!)
let res = results.getDayList(yearShownIndex, posMonth: monthShownIndex)[dayShownIndex].results[row].result
let maxRes = results.getDayList(yearShownIndex, posMonth: monthShownIndex)[dayShownIndex].results[row].maxresult
let discipline = results.getDayList(yearShownIndex, posMonth: monthShownIndex)[dayShownIndex].results[row].discipline
let text1 = String(res) + "/"
let text2 = String(maxRes)
let text3 = " - " + discipline
let text = text1 + text2 + text3
print(text)
cell.ResultField.text = text
return cell
}
// Delegate
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
}
#IBAction func CheckBox(sender: UIButton) {
let image = UIImage(named: "Selected") as UIImage!
let selected = sender.selected
sender.selected = !selected
sender.setImage(image, forState: .Selected)
}
func getIndexToDelete()->[Int]{
var indices = [Int]()
for i in 0..<tableView.numberOfRowsInSection(0){
let indexPath = NSIndexPath(forRow: i, inSection: 0)
// Here does the program crash
let cell = tableView.cellForRowAtIndexPath(indexPath) as! ResultTableCell
if (cell.CheckBoxButton.selected){
indices += [i]
}
}
return indices
}
#IBAction func DeletePressed(sender: UIButton) {
let deleteIndices = getIndexToDelete()
var goback = false;
var count = 0;
for index in deleteIndices{
print("Count: " + String(count))
results.ListResults[yearShownIndex].months[monthShownIndex].day[dayShownIndex].results.removeAtIndex(index-count)
count += 1
print(String((results.getDayList(yearShownIndex, posMonth: monthShownIndex)[dayShownIndex].results.count)));
}
loadView()
results.recreatePlainResult()
results.saveResults()
if (results.ListResults[yearShownIndex].months[monthShownIndex].day[dayShownIndex].results.count == 0){
print(String(results.ListResults[yearShownIndex].months[monthShownIndex].day.count))
results.ListResults[yearShownIndex].months[monthShownIndex].day.removeAtIndex(dayShownIndex)
results.recreatePlainResult()
results.saveResults()
print(String(results.ListResults[yearShownIndex].months[monthShownIndex].day.count))
goback = true
}
if (results.ListResults[yearShownIndex].months[monthShownIndex].day.count == 0){
results.ListResults[yearShownIndex].months.removeAtIndex(monthShownIndex)
results.recreatePlainResult()
results.saveResults()
goback = true
}
if (results.ListResults[yearShownIndex].months.count == 0){
results.ListResults.removeAtIndex(monthShownIndex)
results.recreatePlainResult()
results.saveResults()
goback = true
}
if (goback){
// return;
navigationController?.popViewControllerAnimated(true)
}
}
}
Here is the ResultTableCell:
import UIKit
class ResultTableCell: UITableViewCell {
#IBOutlet weak var ResultField: UITextField!
#IBOutlet weak var CheckBoxButton: UIButton!
}
I can of course put let cell = tableView.cellForRowAtIndexPath(indexPath) as! ResultTableCellinside an if-clause, but then other strange things happens.
Don't use !.
cellForRowAtIndexPath returns UITableViewCell? and can be nil if the row isn't visible when you make the call.
Check whether you actually got a cell at all using if let before casting it to your expected object type.
There are a few things going on here, let's take them one at a time:
The crash is from forcing the nil value through the ! that part should be obvious.
The for loop goes from 0 through to the number of rows, but UITableViewCell instances get recycled, so that can't work.
The checkbox selection is not the standard iOS table cell selection but something more custom
If you were using the built-in selection behavior of UITableViewyou could use this method.
If you want to continue using your custom checkbox selection, than probably the easiest way to do that is to listen for the selection change and build up the NSIndexPath as things are selected.
Afterward when the delete button is pressed you will have a pre-built index ready to delete and you won't have to loop to search for what is selected.