Swift: Button image will not save, isComplete state to change button does save

Viewed 29

I've read some other threads regarding this issue and have been trouble shooting on my end. No luck so far.

I've stepped through each card and the isComplete state IS sticking on open and closing, the button image still does not stick. However, I'm still going through this bug... When the isComplete state is TRUE and you reopen it the images are blank circles, however clicking them once does not change the image BUT it does change the state to false.. which is why the image doesn't appear to change. Which makes me believe my only issue is the image itself not sticking

How the app works: There is a table view of cells (Cards), clicking a cell brings up a table view that holds multiple custom cells (Details of particular card clicked). Five of which have a button you can click if you complete the "task" for that cell.

I have a button that changes it's image based off a bool var (default false) that changes when the button is clicked. The value of this var does change from false -> true on each tap, however when exit out of the view controller and re-enter the button image has not stuck.

Enough of my ramble, here is the code. I've been starring at this for 3 days now, any help would be much appreciated! If you need any other information or additional code please let me know!

Struct for Card:

import Foundation
import UIKit

struct Task: Codable {
    var text: String?
    var isComplete: Bool
    
    static let sample = Task(text: "One", isComplete: false)
    static let sample2 = Task(text: "Two", isComplete: false)
    static let sample3 = Task(text: "Three", isComplete: false)
    static let sample4 = Task(text: "Four", isComplete: false)
    static let sample5 = Task(text: "Five", isComplete: false)


}

struct Grateful: Codable {
    var text: String?
    
    static let sample = Grateful(text: "One")
    static let sample2 = Grateful(text: "Two")
    static let sample3 = Grateful(text: "Three")
    static let sample4 = Grateful(text: "Four")

}
struct Card: Equatable, Codable {
    
    var id = UUID()
    var date: Date = Date()
    var tasks: [Task]
    var gratefuls: [Grateful]
    
    static let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
    static let archiveURL = documentsDirectory.appendingPathComponent("cards").appendingPathExtension("plist")
    
    static func ==(lhs: Card, rhs: Card) -> Bool {
            return lhs.id == rhs.id
    }
    
    static func loadCards() -> [Card]?  {
        guard let codedCards = try? Data(contentsOf: archiveURL) else { return nil}
        let propertlyListDecoder = PropertyListDecoder()
        return try? propertlyListDecoder.decode(Array<Card>.self, from: codedCards)
    }
    
    static func saveCards(_ cards: [Card]) {
        let propertlyListEncoder = PropertyListEncoder()
        let codedCards = try? propertlyListEncoder.encode(cards)
        try? codedCards?.write(to: archiveURL, options: .noFileProtection)
    }
    
    static func loadSampleTasks() -> [Card]? {
        
        let task1 = Card(tasks: [.sample,.sample2,.sample3,.sample4,.sample5], gratefuls: [.sample, .sample2,.sample3,.sample4])
        
        return [task1]
        
    }
    
}

TaskCell class: (This is where the image changes for the button)


import UIKit

class TaskCell: UITableViewCell {
    
    @IBOutlet weak var taskBtn: UIButton!
    @IBOutlet weak var taskText: UITextField!
    
    
    var isComplete: Bool = false
    
    override func awakeFromNib() {
        super.awakeFromNib()
        setButtOnImage()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

//         Configure the view for the selected state
    }
    
    
//     To check if text is in field so that we can update state of save button on VC
    @IBAction func textEditingChanged(_ sender: UITextField) {
//        updateSaveButtonState()
    }
    

    @IBAction func isTaskBtnTapped(_ sender: UIButton) {
        print("Button did get tapped.")
        print(isComplete)
        isComplete.toggle()
        print(isComplete)
        setButtOnImage()
    }
    
    private func setButtOnImage() {
          let buttonImage = isComplete ? "checkmark.circle.fill" : "circle"
          taskBtn.setImage(UIImage(systemName: buttonImage), for: .normal)
      }
    
}

Card View Controller:

import UIKit

class CardViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    var card: Card?
    var tasks: Task?
    var gratefuls: Grateful?
    var taskCell = TaskCell()
    var gratefulCell = GratefulCell()
    
    @IBOutlet weak var cardTable: UITableView!
    @IBOutlet weak var saveButton: UIBarButtonItem!
    @IBOutlet weak var cardDateDisplay: UILabel!
    
    @IBAction func saveButtonPressed(_ sender: UIBarButtonItem) {
        let card = readDataFromCells()
        performSegue(withIdentifier: "saveUnwind", sender: card)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.cardTable.register(UINib.init(nibName: "TaskCell", bundle: .main), forCellReuseIdentifier: "TaskCell")
        self.cardTable.register(UINib.init(nibName: "GratefulCell", bundle: .main), forCellReuseIdentifier: "GratefulCell")
        
        cardTable.separatorStyle = .none
        updateDateDisplay()
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 59
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 9
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if (indexPath.row < 5) {
            let cell:TaskCell = tableView.dequeueReusableCell(withIdentifier: "TaskCell", for: indexPath) as! TaskCell
            let taskIndex = indexPath.row
                if let task = card?.tasks[taskIndex] {
                    cell.taskText.text = task.text
                    cell.isComplete = task.isComplete
                }
            
            //Might be unneeded.
//            if cell.taskBtn.isSelected == true {
//                tasks?.isComplete.toggle()
//            }
            
            cell.selectionStyle = .none
            
            return cell
        } else {
            let cell:GratefulCell = tableView.dequeueReusableCell(withIdentifier: "GratefulCell", for: indexPath) as! GratefulCell
            let gratefulIndex = indexPath.row - (card?.tasks.count ?? 0)
            cell.gratefulNum.text = String(indexPath.row - 4)
            
            if let grateful = card?.gratefuls[gratefulIndex] {
                cell.gratefulText.text = grateful.text
            }
            
            cell.selectionStyle = .none
            
            return cell
        
    }
}
//loop through rows to check if empty to enable button
//    func updateSaveButtonState() {
//        let numOfRows = cardTable.numberOfRows(inSection: 0)
//        var tasks: [Task] = []
//        var gratefuls: [Grateful] = []
//        for row in 0..<numOfRows {
//            let indexPath = 0
////            let cell = cardTable.cellForRow(at: indexPath)
//            let emptyTasks = tasks[indexPath] == nil
//            let emptyGratefuls = indexPath.isEmpty
//
//            if emptyTasks == false || emptyGratefuls == false {
//                let shoudldEnableSaveButton = false
//                saveButton.isEnabled = shoudldEnableSaveButton
//
//            }
//        }
//    }
    
    
    func updateDateDisplay() {
        let date = Date()
        let card: Card? = card
        if let card = card {
            cardDateDisplay.text = card.date.formatted(Date.FormatStyle()
                                                        .weekday(.abbreviated)
                                                        .month(.abbreviated)
                                                        .day(.twoDigits)
                                                        .year(.twoDigits))
        } else {
            cardDateDisplay.text = date.formatted(Date.FormatStyle()
                                                    .weekday(.abbreviated)
                                                    .month(.abbreviated)
                                                    .day(.twoDigits)
                                                    .year(.twoDigits))
        }
    }
    
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        super.prepare(for: segue, sender: sender)
        guard segue.identifier == "saveUnwind" else { return }
        
       card = readDataFromCells()
    }
    
    func readDataFromCells() -> Card {
        let numOfRows = cardTable.numberOfRows(inSection: 0)
        var tasks: [Task] = []
        var gratefuls: [Grateful] = []
        for row in 0..<numOfRows {
            let indexPath = IndexPath(row: row, section: 0)
            let cell = cardTable.cellForRow(at: indexPath)
            
            if let cell = cell as? TaskCell {
                let task = Task(text: cell.taskText.text ?? "", isComplete: cell.isComplete)
                tasks.append(task)
            } else if let cell = cell as? GratefulCell {
                let grateful = Grateful(text: cell.gratefulText.text ?? "")
                gratefuls.append(grateful)
            }
        }
        let card: Card? = card
        if let card = card {
            print(card)
            return Card(id: card.id, date: card.date, tasks: tasks, gratefuls: gratefuls)
        } else {
            return Card(tasks: tasks, gratefuls: gratefuls)
        }
    }
}

Appreciative of any insight!

0 Answers
Related