How do I save a table view?

How do I save the view of a table view. I use a strike through text, an accessory type check, and other attributes to the cell at indexPath. How do I save it? I can't even switch to a different view without it not staying.

Answered by DelawareMathGuy in 398712022

hi,


there are a whole bunch of things going on here that you need to address first, before moving along to any discussion of persisting data (if that's really what you mean, as in saving to disk).


(1) your data consists only of objectsArray: [String], but once the tableview is drawn for you, you try to then store/update the state of the objects in the attributedText field of each cell.


that's bad. you should perhaps keep a separate, parallel array to keep track of the additional state of each string in the object array. or, better still, your objectsArray should be an array of structs, where each struct is something like


struct Quarterback {

var name: String

var strikeThrough: Bool

}

when cellForRowAtIndexPath is called, get the information from objectsArray and fill in both the text and attributed text of the cell you have dequeued. example sequence:


let cell = top30QuarterbacksTable.cellForRow(at: indexPath)

let player: Quarterback = objectsArray[indexPath.row]

cell.textLabel?.text = "\(indexPath.row+1). " + player.name

cell.textLabel?.adjustsFontSizeToFitWidth = true

cell.textLabel?.font = UIFont.systemFont(ofSize: 22)

if player.strikeThrough {

cell?.textLabel?.attributedText = strikeThroughText(player.name)

} else {

cell?.textLabel?.attributedText = nil

}

return cell


you're also apparently trying to tweak a cell's accessoryType elsewhere in your code -- that's something that should also set up here and be tracked in the Quarterback struct by another variable.


(2) if you want to know what's in a given row of the table at anytime, don't ask cellForRowAtIndexPath for the cell (note: the cell you get back will not be the cell that's displayed on screen, but only a new cell with the information you're looking for that you already have). you know what will be in the row just by looking at the objectsArray. and cellForRowAtIndexPath is really something you want to let the system call -- it's not something you want to call on your own.


an example (just kill the commented-out lines)


func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {

// let cell = self.top30QuarterbacksTable.cellForRow(at: indexPath)

// let str: String = (cell?.textLabel!.text)!

let player: Quarterback = objectsArray[indexPath.row]

// if cell?.textLabel?.attributedText == strikeThroughText(str) {

// strikeThroughTextBool = true

// } else {

// strikeThroughTextBool = false

// }

// if strikeThroughTextBool == false

if player.strikeThrough {

......

}

note that addPlayer and RemovePlayer have the same issues at the start of their code.


(3) call top30QuarterbacksTable.reloadData() whenever you make any changes to the objectsArray -- don't try to do anything with cells directly. reloadData() will cause all the cells to be redrawn.


for example, each of your addPlayer and removePlayer should end with a call to reloadData().




hope that helps get you started ... happy to discuss more when you clean up some of these issues.


hope that helps,

DMG

The tableView has a dataSource associated to it.

dataSource is an array of struct, with the different elements you have in cell.

You use the dataSource in tableView(cettAtRow) to populate the table.


When you add data in the table by appending new cells, you have to update the datasource at the same time.


If you want to save data permanently (after quitting the app), you can write to a file: plist, or JSON encoder…


Please show the code of the controller with the tableView, that will be easier to explain in detail what you have to do.

import UIKit

@available(iOS 11.0, *)
class Top_30_Quarterbacks: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    var objectsArray: [String] = ["Patrick Mahomes, KC", "Deshaun Watson, HOU", "Aaron Rodgers, GB", "Matt Ryan, ATL", "Baker Mayfield, CLE", "Carson Wentz, PHI", "Jared Goff, LAR", "Cam Newton, CAR", "Andrew Luck, IND", "Drew Brees, NO", "Ben Roethlisberger, PIT", "Dak Prescott, DAL", "Russell Wilson, SEA", "Tom Brady, NE", "Lamar Jackson, BAL", "Mitchell Trubisky, CHI",  "Jameis Winston, TB", "Philip Rivers, LAC", "Kirk Cousins, MIN", "Derek Carr, OAK", "Sam Darnold, NYJ", "Josh Allen, BUF", "Matthew Stafford, DET", "Marcus Mariota, TEN", "Jimmy Garoppolo, SF", "Andy Dalton, CIN", "Eli Manning, NYG", "Nick Foles, JAC", "Joe Flacco, DEN", "Ryan Fitzpatrick, MIA"
    ]
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return objectsArray.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath as IndexPath)
        cell.textLabel?.text = "\(indexPath.row+1).  " + objectsArray[indexPath.row]
        cell.textLabel?.adjustsFontSizeToFitWidth = true
        cell.textLabel?.font = UIFont.systemFont(ofSize: 22)
        return cell
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        top30QuarterbacksTable.deselectRow(at: indexPath, animated: true)
    }
    
    func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
        let cell = self.top30QuarterbacksTable.cellForRow(at: indexPath)
        let str: String = (cell?.textLabel!.text)!
        let player: String = objectsArray[indexPath.row]
        
        if cell?.textLabel?.attributedText == strikeThroughText(str) {
            strikeThroughTextBool = true
        } else {
            strikeThroughTextBool = false
        }
        
        if strikeThroughTextBool == false {
            
            let add = UIContextualAction(style: .normal, title: "Add") { (contextualAction, view, actionPerformed: @escaping (Bool) -> Void) in
                let alert = UIAlertController(title: "Add Player", message: "Are you sure you want to add '\(player)' to your roster?", preferredStyle: .alert)
                alert.addAction(UIAlertAction(title: "No", style: .cancel, handler: { (alertAction) in
                    actionPerformed(false)
                }))
                alert.addAction(UIAlertAction(title: "Yes", style: .destructive, handler: { (alertAction) in
                    self.addPlayer(index: indexPath)
                    cell?.textLabel?.attributedText = strikeThroughText(str)
                    let okayAlert = UIAlertController(title: "Player Added!", message: "You added '\(player)' to your roster?", preferredStyle: .alert)
                    okayAlert.addAction(UIAlertAction(title: "OK", style: .default, handler: { (alertAction) in
                        actionPerformed(true)
                    }))
                    self.present(okayAlert, animated: true)
                    cell?.backgroundColor = .systemGray3
                }))
                self.present(alert, animated: true)
            }
            add.backgroundColor = .systemGreen
            let taken = UIContextualAction(style: .normal, title: "Taken") { (contextualAction, view, actionPerformed: @escaping (Bool) -> Void) in
                let alert = UIAlertController(title: "Player Taken", message: "Are you sure you want to mark '\(player)' as taken and not available?", preferredStyle: .alert)
                alert.addAction(UIAlertAction(title: "No", style: .cancel, handler: { (alertAction) in
                    actionPerformed(false)
                }))
                alert.addAction(UIAlertAction(title: "Yes", style: .destructive, handler: { (alertAction) in
                    self.markAsTaken(index: indexPath)
                    cell?.textLabel?.attributedText = strikeThroughText(str)
                    let okayAlert = UIAlertController(title: "Taken Player", message: "You marked '\(player)' as taken and not available!", preferredStyle: .alert)
                    okayAlert.addAction(UIAlertAction(title: "OK", style: .default, handler: { (alertAction) in
                        actionPerformed(true)
                    }))
                    self.present(okayAlert, animated: true)
                    cell?.backgroundColor = .systemGray2
                }))
                self.present(alert, animated: true)
            }
            taken.backgroundColor = .systemRed
            let config = UISwipeActionsConfiguration(actions: [taken, add])
            config.performsFirstActionWithFullSwipe = false
            return config
        } else {
            let undo = UIContextualAction(style: .normal, title: "Undo") { (contextualAction, view, actionPerformed: @escaping (Bool) -> Void) in
                let alert = UIAlertController(title: "Undo", message: "Are you sure you want undo the action for '\(player)'?", preferredStyle: .alert)
                alert.addAction(UIAlertAction(title: "No", style: .cancel, handler: { (alertAction) in
                    actionPerformed(false)
                }))
                alert.addAction(UIAlertAction(title: "Yes", style: .destructive, handler: { (alertAction) in
                    self.removePlayer(index: indexPath)
                    cell?.textLabel?.attributedText = noStrikeThroughText(str)
                    let okayAlert = UIAlertController(title: "Action Undone", message: "The previous action for '\(player)' has been undone!", preferredStyle: .alert)
                    okayAlert.addAction(UIAlertAction(title: "OK", style: .default, handler: { (alertAction) in
                        actionPerformed(true)
                    }))
                    self.present(okayAlert, animated: true)
                    cell?.backgroundColor = .none
                }))
                self.present(alert, animated: true)
            }
            undo.backgroundColor = .systemBlue
            let config = UISwipeActionsConfiguration(actions: [undo])
            config.performsFirstActionWithFullSwipe = false
            return config
        }
    }
    
    func addPlayer(index: IndexPath) {
        let cell = top30QuarterbacksTable.cellForRow(at: index)
        let str: String = objectsArray[index.row]
        cell?.accessoryType = UITableViewCell.AccessoryType.checkmark
        
        if myRoster == [""] {
            myRoster?.insert(str, at: 0)
            myRoster?.remove(at: 1)
        } else {
            myRoster?.append(str)
        }
        
        if draftOrder == [""] {
            draftOrder?.insert(str, at: 0)
            draftOrder?.remove(at: 1)
        } else {
            draftOrder?.append(str)
        }
    }
    
    func removePlayer(index: IndexPath) {
        let cell = top30QuarterbacksTable.cellForRow(at: index)
        let str: [String] = [objectsArray[index.row]]
        cell?.accessoryType = UITableViewCell.AccessoryType.none
        myRoster?.removeAll(where: { str.contains($0) })
        draftOrder?.removeAll(where: { str.contains($0) })
    }
        
    func markAsTaken(index: IndexPath) {
        _ = top30QuarterbacksTable.cellForRow(at: index)
        let str: String = objectsArray[index.row]
            
            if draftOrder == [""] {
                draftOrder?.insert(str, at: 0)
                draftOrder?.remove(at: 1)
            } else {
                draftOrder?.append(str)
            }
        }
    
    @IBOutlet weak var top30QuarterbacksTable: UITableView!
    @IBOutlet var view1: UIView!
    @IBOutlet weak var view2: UIView!
    @IBOutlet weak var label: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

Also, When I run the app and swipe on a cell and tap the add or taken actions, everything that happens to that cell, happens to every 15th cell as I scroll down. I think this has something to do with reusable cell. How can I fix this?

…swipe on a cell and tap the add or taken actions, everything that happens to that cell, happens to every 15th cell as I scroll down

What do you mean ? Each cell over 15 ? Or all cell after 15th below the one where you swiped ? Or something else. Please, be more clear.


It seems that your dataStore is objectsArray. Exact ?

When you swipe and add, I do not see that you append new item in objectsArray. Exact ?


So, add does not add to objectsArray.

What is addPlayer supposed to do ?

Whay is myRoster ?


There are absolutely no comment to your code, it is very hard to follow it. And it will be hard for you rapidly.


A few comments :

        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath as IndexPath)

casting indexPath as IndexPath is useless, it is already an IndexPath


What is strikeThroughText(str: String) doing ?

Accepted Answer

hi,


there are a whole bunch of things going on here that you need to address first, before moving along to any discussion of persisting data (if that's really what you mean, as in saving to disk).


(1) your data consists only of objectsArray: [String], but once the tableview is drawn for you, you try to then store/update the state of the objects in the attributedText field of each cell.


that's bad. you should perhaps keep a separate, parallel array to keep track of the additional state of each string in the object array. or, better still, your objectsArray should be an array of structs, where each struct is something like


struct Quarterback {

var name: String

var strikeThrough: Bool

}

when cellForRowAtIndexPath is called, get the information from objectsArray and fill in both the text and attributed text of the cell you have dequeued. example sequence:


let cell = top30QuarterbacksTable.cellForRow(at: indexPath)

let player: Quarterback = objectsArray[indexPath.row]

cell.textLabel?.text = "\(indexPath.row+1). " + player.name

cell.textLabel?.adjustsFontSizeToFitWidth = true

cell.textLabel?.font = UIFont.systemFont(ofSize: 22)

if player.strikeThrough {

cell?.textLabel?.attributedText = strikeThroughText(player.name)

} else {

cell?.textLabel?.attributedText = nil

}

return cell


you're also apparently trying to tweak a cell's accessoryType elsewhere in your code -- that's something that should also set up here and be tracked in the Quarterback struct by another variable.


(2) if you want to know what's in a given row of the table at anytime, don't ask cellForRowAtIndexPath for the cell (note: the cell you get back will not be the cell that's displayed on screen, but only a new cell with the information you're looking for that you already have). you know what will be in the row just by looking at the objectsArray. and cellForRowAtIndexPath is really something you want to let the system call -- it's not something you want to call on your own.


an example (just kill the commented-out lines)


func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {

// let cell = self.top30QuarterbacksTable.cellForRow(at: indexPath)

// let str: String = (cell?.textLabel!.text)!

let player: Quarterback = objectsArray[indexPath.row]

// if cell?.textLabel?.attributedText == strikeThroughText(str) {

// strikeThroughTextBool = true

// } else {

// strikeThroughTextBool = false

// }

// if strikeThroughTextBool == false

if player.strikeThrough {

......

}

note that addPlayer and RemovePlayer have the same issues at the start of their code.


(3) call top30QuarterbacksTable.reloadData() whenever you make any changes to the objectsArray -- don't try to do anything with cells directly. reloadData() will cause all the cells to be redrawn.


for example, each of your addPlayer and removePlayer should end with a call to reloadData().




hope that helps get you started ... happy to discuss more when you clean up some of these issues.


hope that helps,

DMG

objectsArray is set. Nothing is appended to it. When I add, it adds the contents to another array named myRoster. In this table view, strikeThroughText adds a line through the cell text at indexPath if the cell data is added to myRoster. It also adds a checkmark to the cell and changes the color of the cell. If the cell text has a line through it, that means that the data in the cell is already added to myRoster or added to draftOrder. In this case, if there is a line through the cell text, when I swipe there is an 'undo' button which deletes that player from myRoster or draftOrder, deletes the line going through the text, and deletes the checkmark. The app is working perfectly except that I cannot save the view if I change views and that when I add the cell data with a swipe and either 'add' button or 'taken' button, when I scroll down the table view, there is a line through the text, a checkmark, and the cell color is changed in every 15th table view row.

You should better edit your text to make it easier to read.


objectsArray is set. Nothing is appended to it.

When I add, it adds the contents to another array named myRoster.


In this table view, strikeThroughText adds a line through the cell text at indexPath if the cell data is added to myRoster. It also adds a checkmark to the cell and changes the color of the cell.

If the cell text has a line through it, that means that the data in the cell is already added to myRoster or added to draftOrder.

In this case, if there is a line through the cell text, when I swipe there is an 'undo' button which deletes that player from myRoster or draftOrder, deletes the line going through the text, and deletes the checkmark.


The app is working perfectly except that I cannot save the view if I change views and that when I add the cell data with a swipe and either 'add' button or 'taken' button, when I scroll down the table view, there is a line through the text, a checkmark, and the cell color is changed in every 15th table view row.


Let’s start with addPlayer


if myRoster == [""] { 
            myRoster?.insert(str, at: 0) 
            myRoster?.remove(at: 1) 
        } else { 
            myRoster?.append(str) 
        }


Why is myRoster == [""] and not just an empty array [] ?

You never use myRoster in tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)

So of course information is lost when you return to the view.


You should probably rethink the logic, as some others have pointed out.

Let's look at the second problem: cells which appear with marks.


The rror here is to use cells as storage items. You should never do this.


Let's explain.

Suppose cells 1 to 14 are visible on screen.

You swipe cell 2, adding accessory and other elements.

When you scroll upward, at some moment after cell 2 has disappeared, it is put in the queue. With all its content.

When table needs to dequeue a cell (for instance when row 17 appears), it will dequeue and get the former cell 2.

You change its title, so it seems you have changed the cellt, but the rest of the content (accessory) is still from cell 2.

But when you want a cell for row 18, it will dequeue a new one, may be former cell3 which had no accessory. Hence it appears "normal"

This is the whole cause of the problem.


The solution is simple:

in tableView(cellForRowAt:), you have to rebuild completely the content.

- after dequeue,

- remove the accessory view if it exists.

- depending on what you have in myRoster (which plays as data source), insert an accesory view.

Hello,

Thank you for your help.

I am getting an error though at


let player: Quarterback = objectsArray[indexPath.row]


Cannot convert value of type 'String' to specified type 'Quarterback'

hi,


as i suggested, your objectsArray should be an array of structs, i.e., objectsArray: [Quarterback]. populate it not as an array of strings, but as an array of Quarterback structs -- e.g.,


var objectsArray: [Quarterback] = [ Quarterback(name: "Patrick Mahomes, KC", strikeThrough: false), ... ]



hope that helps,

DMG

Did you try what I proposed in my 2 posts Dec 18, 2019 12:06 AM and Dec 18, 2019 1:27 AM ?

Hello, The reason why myRoster == [""] and not [] is because the app was crashing and finding nil. I had to


myRoster?.remove(at: 1) to remove the [""] after the string was inserted.


For some reason now, I changed it to an emty array and removed line 3 and now it works.


I don't use myRoster in this tableView because I want it accessed by other classes. For instance, I have other files that have classes such as:


Top_80_RunningBacks and Top_80_WideReceivers.


The information isn't lost when I return to the view. All that is lost is:


- strikeThroughText

- cell?accessoryType

- cell?backgroundColor


Another thing, when I scroll down and then scroll back up to the changed cell, the changes are lost.

The reason why myRoster == [""] and not [] is because the app was crashing and finding nil. I had to

If you declare as = [], you should not find nil and have a crash.


I don't use myRoster in this tableView because I want it accessed by other classes.

You can declare those var in a global, through a singleton.


The information isn't lost when I return to the view. All that is lost is:

- strikeThroughText

- cell?accessoryType

- cell?backgroundColor


You did not do what I recommended. Please, do it, or tell me you don't want to, I will stop commenting here.

You have to save those information in a dataSource (a global array ?), not rely on the cell to store it.

And use these information in tableView(cellForRowAt:) to set the cell property acccordingly.

I have been trying to do what you proposed. I think I almost got it.


1. I setup a global struct

struct Data {
    var num: Int = 0
    var name: String = ""
    var strikeThrough: Bool = false
    var color: Bool = false
    var accessory: Bool = false
}

var objectsArray = [Data]()


2. I setup a global function

func quarterBacks() {
    objectsArray = [
        Data(num: 1, name: "Patrick Mahomes, KC", strikeThrough: false, color: false, accessory: false),
        Data(num: 2, name: "Deshaun Watson, HOU", strikeThrough: false, color: false, accessory: false),
        Data(num: 3, name: "Aaron Rodgers, GB", strikeThrough: false, color: false, accessory: false),
        Data(num: 4, name: "Matt Ryan, ATL", strikeThrough: false, color: false, accessory: false),
        Data(num: 5, name: "Baker Mayfield, CLE", strikeThrough: false, color: false, accessory: false),
        Data(num: 6, name: "Carson Wentz, PHI", strikeThrough: false, color: false, accessory: false),
        Data(num: 7, name: "Jared Goff, LAR", strikeThrough: false, color: false, accessory: false),
        Data(num: 8, name: "Cam Newton, CAR", strikeThrough: false, color: false, accessory: false),
        Data(num: 9, name: "Andrew Luck, IND", strikeThrough: false, color: false, accessory: false),
        Data(num: 10, name: "Drew Brees, NO", strikeThrough: false, color: false, accessory: false),
        Data(num: 11, name: "Ben Roethlisberger, PIT", strikeThrough: false, color: false, accessory: false),
        Data(num: 12, name: "Dak Prescott, DAL", strikeThrough: false, color: false, accessory: false),
        Data(num: 13, name: "Russell Wilson, SEA", strikeThrough: false, color: false, accessory: false),
        Data(num: 14, name: "Tom Brady, NE", strikeThrough: false, color: false, accessory: false),
        Data(num: 15, name: "Lamar Jackson, BAL", strikeThrough: false, color: false, accessory: false),
        Data(num: 16, name: "Mitchell Trubisky, CHI", strikeThrough: false, color: false, accessory: false),
        Data(num: 17, name: "Jameis Winston, TB", strikeThrough: false, color: false, accessory: false),
        Data(num: 18, name: "Philip Rivers, LAC", strikeThrough: false, color: false, accessory: false),
        Data(num: 19, name: "Kirk Cousins, MIN", strikeThrough: false, color: false, accessory: false),
        Data(num: 20, name: "Derek Carr, OAK", strikeThrough: false, color: false, accessory: false),
        Data(num: 21, name: "Sam Darnold, NYJ", strikeThrough: false, color: false, accessory: false),
        Data(num: 22, name: "Josh Allen, BUF", strikeThrough: false, color: false, accessory: false),
        Data(num: 23, name: "Matthew Stafford, DET", strikeThrough: false, color: false, accessory: false),
        Data(num: 24, name: "Marcus Mariota, TEN", strikeThrough: false, color: false, accessory: false),
        Data(num: 25, name: "Jimmy Garoppolo, SF", strikeThrough: false, color: false, accessory: false),
        Data(num: 26, name: "Andy Dalton, CIN", strikeThrough: false, color: false, accessory: false),
        Data(num: 27, name: "Eli Manning, NYG", strikeThrough: false, color: false, accessory: false),
        Data(num: 28, name: "Nick Foles, JAC", strikeThrough: false, color: false, accessory: false),
        Data(num: 29, name: "Joe Flacco, DEN", strikeThrough: false, color: false, accessory: false),
        Data(num: 30, name: "Ryan Fitzpatrick, MIA", strikeThrough: false, color: false, accessory: false)
    ]
}


3. I call quarterbacks() in viewDidLoad()

override func viewDidLoad() {
        super.viewDidLoad()
       quarterBacks()
    }


4. I set the structs data in my three functions addPlayer(index: IndexPath), removePlayer(index: IndexPath), and markAsTaken(index: IndexPath)

func addPlayer(index: IndexPath) {
        _ = top30QuarterbacksTable.cellForRow(at: index)
        let str: String = objectsArray[index.row].name
        
        objectsArray[index.row].strikeThrough = true
        objectsArray[index.row].accessory = true
        objectsArray[index.row].color = true
        
        if myRoster == [] {
            myRoster?.insert(str, at: 0)
        } else {
            myRoster?.append(str)
        }
        
        if draftOrder == [] {
            draftOrder?.insert(str, at: 0)
        } else {
            draftOrder?.append(str)
        }
        top30QuarterbacksTable.reloadData()
    }
    
    func removePlayer(index: IndexPath) {
        _ = top30QuarterbacksTable.cellForRow(at: index)
        let str: [String] = [objectsArray[index.row].name]
        
        objectsArray[index.row].strikeThrough = false
        objectsArray[index.row].color = false
        objectsArray[index.row].accessory = false
        
        myRoster?.removeAll(where: { str.contains($0) })
        draftOrder?.removeAll(where: { str.contains($0) })
        top30QuarterbacksTable.reloadData()
    }
        
    func markAsTaken(index: IndexPath) {
        _ = top30QuarterbacksTable.cellForRow(at: index)
        let str: String = objectsArray[index.row].name
        
        objectsArray[index.row].strikeThrough = true
        objectsArray[index.row].color = true
        objectsArray[index.row].accessory = false
            
            if draftOrder == [] {
                draftOrder?.insert(str, at: 0)
            } else {
                draftOrder?.append(str)
            }
        top30QuarterbacksTable.reloadData()
        }


5. I setup cellForRowAt with if statements

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        let num = objectsArray[indexPath.row].num
        let name = objectsArray[indexPath.row].name
        cell.textLabel?.text = "\(num).  \(name)"
        cell.textLabel?.adjustsFontSizeToFitWidth = true
        cell.textLabel?.font = UIFont.systemFont(ofSize: 22)
        
        if objectsArray[indexPath.row].strikeThrough == false && objectsArray[indexPath.row].accessory == false && objectsArray[indexPath.row].color == false {
            cell.textLabel?.text = "\(num).  \(name)"
            cell.textLabel?.attributedText = noStrikeThroughText(name)
            cell.accessoryType = UITableViewCell.AccessoryType.none
            cell.backgroundColor = .none
        }
        else if objectsArray[indexPath.row].strikeThrough == true && objectsArray[indexPath.row].accessory == true && objectsArray[indexPath.row].color == true {
            cell.textLabel?.text = "\(num).  \(name)"
            cell.textLabel?.attributedText = strikeThroughText(name)
            cell.accessoryType = UITableViewCell.AccessoryType.checkmark
            cell.backgroundColor = .systemGray3
        } else {
            cell.textLabel?.text = "\(num).  \(name)"
            cell.textLabel?.attributedText = strikeThroughText(name)
            cell.accessoryType = UITableViewCell.AccessoryType.none
            cell.backgroundColor = .systemGray2
        }
        return cell
    }

It works perfectly except that when I added the if statements in cellForRowAt it doesn't display the num.


I want it to look like this:


1. Patrick Mahomes, KC

2. Deshaun Watson, HOU

3. Aaron Rodgers, GB

...


but it looks like this:


Patrick Mahomes, KC

Deshaun Watson, Hou

Aaron Rodgers, GB

...


All other functionalities work perfect. This is the only thing I cannot figure out why it is doing this. I remove the if statements from cellForRowAt and it displays the way I want it to but the other functionalities do not work right.


I am sorry if it seemed like I didn't want to do what you proposed but I am trying.

The problem is most likely in strikeThroughText which does not include num.


Could you show the code of strikeThroughText ? I do not see how it could get the num which is not passed as parameter.

Probably would have to change something like

func strikeThroughText( _ body: String, head: String = "") {

}


You can still call

strikeThroughText(t)

with a single parapeter or add

strikeThroughText(t, head: "\(num). ")
How do I save a table view?
 
 
Q