Если условие не работает для зачеркивания текста в приложении ToDo iOS tableview - PullRequest
0 голосов
/ 14 февраля 2020

У меня есть приложение iOS ToDo, основанное на разработке приложений iBook с Swift. Я расширил его, чтобы использовать CoreData (чтобы иметь возможность сортировать по дате). Я также добавил функцию зачеркивания taskTitleLabel при переключении кнопки isCompleteButton. Кажется, что все работает нормально, пока последний элемент в табличном представлении не будет завершен, а затем не завершен. Если новый элемент добавляется в список после переключенного, к заголовку применяется зачеркивание без выбора isCompleteButton. Вот код:

TaskCell.swift

import UIKit

@objc protocol TaskCellDelegate: class {
    func checkmarkTapped(sender: TaskCell) 
}

class TaskCell: UITableViewCell {

    var delegate: TaskCellDelegate?

    @IBOutlet weak var isCompleteButton: UIButton!

    @IBOutlet weak var taskTitleLabel: UILabel!


    @IBAction func isCompleteButtonTapped(_ sender: UIButton) {
        delegate?.checkmarkTapped(sender: self)

    }
    override func prepareForReuse() {
        super.prepareForReuse()

        isCompleteButton.isSelected = !isCompleteButton.isSelected
    }
}

TasksTableViewController

    ...
 func checkmarkTapped(sender: TaskCell) {

        if let indexPath = tableView.indexPath(for: sender){
            let task = fetchedResultsController.object(at: indexPath) as? Task
            task?.isComplete = !task!.isComplete
            coreDataStack.saveContext()
        }
    }
...
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "taskCell") as? TaskCell else { fatalError("Could not dequeue a celL")}

        cell.delegate = self

        let task = fetchedResultsController.object(at: indexPath) as! Task
        cell.taskTitleLabel.text = task.title
        cell.isCompleteButton.isSelected = task.isComplete

        if  task.isComplete {
            let strikeThroughTask = NSMutableAttributedString(string: task.title!)
            strikeThroughTask.addAttributes([
                NSAttributedString.Key.strikethroughStyle: NSUnderlineStyle.single.rawValue,
                NSAttributedString.Key.strikethroughColor: UIColor.darkGray,
                NSAttributedString.Key.font : UIFont.systemFont(ofSize: 12.0)
            ], range: NSMakeRange(0, strikeThroughTask.length))
            cell.taskTitleLabel.attributedText = strikeThroughTask
        }

        if task.hasDueDate {
            if task.dueDate! < Date().startOfDay {
              cell.taskTitleLabel.textColor = .red
            } else if task.dueDate! > Date().startOfDay && task.dueDate! < Date().endOfDay {
                if #available(iOS 13.0, *) {
                    cell.taskTitleLabel.textColor = .label
                } else {
                    // Fallback on earlier versions
                    cell.taskTitleLabel.textColor = .black
                }
            } else {
                // future due date
                cell.taskTitleLabel.textColor = UIColor(red: 100/255.0, green: 100/255.0, blue: 100/255.0, alpha: 1)
            }
        } else {
            //no dueDate
            cell.taskTitleLabel.textColor = UIColor(red: 125/255.0, green: 125/255.0, blue: 125/255.0, alpha: 1)
        }

        return cell
    }

Я также использую NSFetchResultsController

extension TasksTableViewController: NSFetchedResultsControllerDelegate {

    func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
        tableView.beginUpdates()
    }

    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {

        let index = indexPath ?? (newIndexPath ?? nil)
        guard let cellIndex = index else { return }

        switch type {
            case .insert:
                tableView.insertRows(at: [cellIndex], with: .automatic)
            case .delete:
                tableView.deleteRows(at: [cellIndex], with: .automatic)
            case .update:
                tableView.reloadRows(at: [cellIndex], with: .automatic)
            default:
                break
        }
    }


    func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
        tableView.endUpdates()
    }

}

Из AddTaskTableViewController

...
func updateTaskEntry() {
        guard let task = task else { return }

        task.title = taskTitleTextField.text
        task.isComplete = isCompleteButton.isSelected
        task.hasDueDate = hasDueDateSwitch.isOn
        if hasDueDateSwitch.isOn {
            task.dueDate = dueDatePicker.date
        } else {
            task.dueDate = nil
        }
        task.notes = notesTextView.text
        coreDataStack.saveContext()
    }

    @IBAction func saveButtonTapped(_ sender: UIBarButtonItem) {

    }

    func saveNewTask() {
        let task = Task(context: coreDataStack.managedObjectContext)
            task.title = taskTitleTextField.text
            task.isComplete = isCompleteButton.isSelected
            task.hasDueDate = hasDueDateSwitch.isOn
            if hasDueDateSwitch.isOn {
                task.dueDate = dueDatePicker.date
            } else {
                task.dueDate = nil
            }
            task.notes = notesTextView.text
            task.createdOn = Date()

            coreDataStack.saveContext()
    }
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        super.prepare(for: segue, sender: sender)

        guard segue.identifier == "saveUnwind" else {return}

        if navigationItem.title == "Add Task" {

            saveNewTask()

        } else if navigationItem.title == "Update Task" {

            updateTaskEntry()
        }
    }
}

Итак, мой вопрос: почему текст в заголовке метки имеет зачеркнутый текст без выделенной кнопки isCompleteButton или task.isComplete? Чего мне не хватает?

Ответы [ 2 ]

0 голосов
/ 16 февраля 2020

Я решил проблему с помощью здесь Невозможно сбросить UILabel attribuText при повторном использовании UITableViewCell Я добавил taskTitleLabel.attributedText = nil в функцию prepareForReuse.

0 голосов
/ 14 февраля 2020

Я думаю, что половина проблемы заключается в этой строке, где при подготовке к повторному использованию ячеек вы устанавливаете isCompleteButton в его противоположное состояние:

override func prepareForReuse() {
    super.prepareForReuse()

    isCompleteButton.isSelected = !isCompleteButton.isSelected
}

Я думаю, что состояние isCompleteButton для каждой из ваших задач должно быть привязанным только к вашей модели данных. Это не должно быть изменено в этой функции. Возможно, я бы вообще удалил эту функцию.

И другая проблема заключается в том, что при сохранении новой задачи в saveNewTask () вы устанавливаете свойство isComplete в зависимости от того, выбрана эта кнопка или нет:

task.isComplete = isCompleteButton.isSelected

Я бы сказал, что это следует изменить на:

task.isComplete = false

Объяснение неожиданного поведения:

Я представляю, готовится ли ячейка к повторному использованию для новой задачи, и кнопка этой ячейки была ранее отключена (isSelected: false), prepareForReuse () сделает это значение истинным, поскольку именно это делает ваш код в настоящее время. Затем новая задача будет сохранена с параметром task.isComplete, установленным в значение true. И это может быть причиной того, что зачеркивание уже применено.

...