hi,i concur with Claude31 that we both hope you'll make this work!but i'd also agree that it might be useful to close out this thread, if only because we're now 22 replies into it and still have not yet gotten to your thread's original question of "How do I save a table view?"i'd suggest that once you really have the tableView working on its own -- the display is correct, you never call cellForRowAtIndexPath yourself, your swipe actions are working (making changes to the objectsArray directly), and the tableView is doing a reloadData() whenever the objectsArray is changed -- then it makes sense for the conversation to continue in a new thread, with working and updated code, possibly titled "How do I save a table view -- Part 2" or something.i see three things from here:(1) you added the question "Now, how do I get a smooth animation?" chances are the answer is to either call tableView.reloadRows(at:with:) to update an existing cell or cells individually, or to do a little more work when you add or delete rows. for example, to delete a player associated with an indexPath, you would calltop30QuarterbacksTable.beginUpdates()
objectsArray.remove(at: indexPath.row)
top30QuarterbacksTable.deleteRows(at: [indexPath], with: .fade)
top30QuarterbacksTable.endUpdates()(2) you more recently added "I cannot change views and go back to the view without the changed view back to its default view." i'm not sure what this means -- is there another ViewController around that we don't know about? and is the Top_30_Quarterbacks UIViewController presented by another?if so, that's another design issue to deal with, because right now a new objectsArray is created whenever time you bring the Top_30_Quarterbacks UIViewController on screen. it may or may not make sense in your application design for the Top_30_Quarterbacks UIViewController to read data from a file when it comes on screen, and then to write data when it goes off screen.(3) and once the situation for (2) is clarified and we know "who owns the data," then we can address the more specific problem of how to persist data of any sort (e.g., your objectsArray, which as i said is already Codable and can be easily saved and restored using JSON).we both look forward to where this goes!hope that helps,DMG
Post
Replies
Boosts
Views
Activity
hi,(i think you were responding to my suggestion, not Claude31's on this, but we're both trying to help you moving forward.)(and, i also note that as i'm about to post this, my good friend Claude31 has already added something -- so all of us will eventually get there.)your code is much improved, and creating the Data struct for full quarterback information is the right thing to do -- it will make it easier to save and later restore all your data.i'll make a suggestion, and then we can get on to the underlying question of saving data.(1) as long as you're willing to always create an attributedString for every quarterback using a computed property of the Data struct, as i'll show below, and then factor out what's happening in your lengthy if statement, your cellForRowAtIndexPath code will get much less clunky, perhaps as this (if i am reading your if-then logic correctly):func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) let quarterback = objectsArray[indexPath.row] cell.textLabel?.attributedText = quarterback.attributedText cell.textLabel?.adjustsFontSizeToFitWidth = true cell.textLabel?.font = UIFont.systemFont(ofSize: 22) cell.accessoryType = quarterback.accessory ? .checkmark : .none if !quarterback.color { cell.backgroundColor = .none } else if cell.accessory { cell.backgroundColor = .systemGray3 } else { cell.backgroundColor = .systemGray2 } return cell}now, add some code for your Data struct:struct Data { var num: Int var name: String var strikeThrough: Bool = false var color: Bool = false var accessory: Bool = false init(num: Int, name: String) { self.num = num self.name = name } var attributedText: NSAttributedString { // i had to do a quick EDIT on this line after my initial post // rewrite as needed, since there appears to be some question about whether the number is included or not let text = "\(num). \(name)" let attributeString: NSMutableAttributedString = NSMutableAttributedString(string: text) let valueCode = strikeThrough ? 1 : 0 attributeString.addAttribute(NSAttributedString.Key.strikethroughStyle, value: valueCode, range: NSMakeRange(0, attributeString.length)) return attributeString }}(2) since i added an init() method to your Data struct, you can now trim down some of the lengthy quarterBacks() function -- because all structs are initialized with the three booleans all false:let objectsArray = [ Data(num: 1, name: "Patrick Mahomes, KC"), Data(num: 2, name: "Deshaun Watson, HOU"), ... Data(num: 30, name: "Ryan Fitzpatrick, MIA")]in the future, some code-cleaning suggestions are in order, and then getting to save data will be easy, because your Data struct is already Codable.hope that helps,DMG
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
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 cellyou'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
hi uncletr,this sounds familiar to me ... a constraint reference unexpectedly being nil when trying to tweak a layout between portrait and landscape. please let us know how the constraint is defined: is it defined in IB and then referenced from your code, or is it defined and added directly in code, say in viewDidLoad()?in my recent case, i had a reference to a constraint defined in IB; when i set it to active = false, the constraint reference immediately became nil, almost exactly as you describe. looking forward to more info,DMG