дублирование с использованием раздела заголовков в табличном представлении с использованием Swift - PullRequest
0 голосов
/ 03 августа 2020

ну, я пытаюсь добавить дату в разделы заголовка каждый раз, когда пользователь выполняет свою задачу. проблема в том, что я новичок в разделе заголовков, и по какой-то причине каждый раз, когда я добавляю более двух задач в раздел «Готово», кажется, что он дублирует себя.

просмотрел stackOverFlow и не смог найти то, что мне нужно, и я надеюсь, что вы, ребята, сможете мне помочь :) Вот пи c приложения с проблемой: https://imgur.com/wjVy9Uy

Вот мой код:

import Foundation
import CoreData
import UIKit
import SwipeCellKit

protocol TaskDelegate {
    func updateTaskName(name:String)
}

class TasksManViewController: UITableViewController, SwipeTableViewCellDelegate {
    
    
    
    @IBOutlet weak var Sege: UISegmentedControl!
    
    
    
    var tasksArray = [Task](){
        didSet {
            // because we perform this operation on the main thread, it is safe
            DispatchQueue.main.async {
                self.tableView.reloadData()
            }
        }
    }
    
    
    let isSwipeRightEnabled = true

    var delegate: TaskDelegate?

    let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
    
    
    override func viewDidLoad() {
        
    }
    
    
    override func viewWillAppear(_ animated: Bool) {
        loadTasks()
    }

    
    
    // MARK: - DataSource + Delegate Methods:
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return tasksArray.count
    }
    
    
    override func numberOfSections(in tableView: UITableView) -> Int {
        return tasksArray.count
    }
    
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "taskCellRow") as! SwipeTableViewCell
        cell.delegate = self
        
        cell.textLabel?.text = tasksArray[indexPath.row].title
        
        return cell
    }
    
    
    
    func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> [SwipeAction]? {
        if orientation == .left {
            
            guard isSwipeRightEnabled else { return nil }

            let doneAction = SwipeAction(style: .destructive, title: "Done") { (action, indexPath) in
                
                //STEP1: Append the task to the doneTasksArr:
                self.tasksArray[indexPath.row].isDone = true
                
                //STEP3: Remove the Row:
                self.tasksArray.remove(at: indexPath.row)
                
                //STEP4: Update the Model:
                self.saveTasks()
                
                self.delegate?.updateTaskName(name: "")
                
                self.tableView.reloadData()
                
            }
            
            let unDoneAction = SwipeAction(style: .destructive, title: "Undone") { (unDoneAction, indexPath) in
                self.tasksArray[indexPath.row].isDone = false
                
                self.tasksArray.remove(at: indexPath.row)
                
                self.saveTasks()
                
            }
            
            
            //configure btn:
            doneAction.backgroundColor = .cyan
            unDoneAction.backgroundColor = .blue
            
            
            if Sege.selectedSegmentIndex == 0 { //Doing this to allow the user to unDone tasks.
            return [doneAction]
            } else { return [unDoneAction] }

            
        } else {
            let deleteAction = SwipeAction(style: .destructive, title: "Delete") { action, indexPath in
                
                self.context.delete(self.tasksArray[indexPath.row])
                
                self.tasksArray.remove(at: indexPath.row)
                
                
                self.saveTasks()
                
                self.delegate?.updateTaskName(name: "")

                self.tableView.reloadData()
                
            }
            
            return [deleteAction]
        }
        
    }
    
    
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        
        
    }
    
    // MARK: - Class Methods:
    @IBAction func addBtnTapped(_ sender: UIBarButtonItem) {
        Sege.selectedSegmentIndex = 0 // Doing this to avoid the user to insert a task into the DoneTasks by mistake! and avoiad a bug :)
        insertNewTask()
    }
    
    
    
    func insertNewTask() {
        var textField = UITextField()
        
        
        let alert = UIAlertController(title: "New Task", message: "Please Add Your Task", preferredStyle: .alert)
        
        alert.addTextField { (alertTextField) in
            alertTextField.placeholder = "Create New Task"
            textField = alertTextField
        }
        
        
        let action = UIAlertAction(title: "Add", style: .default) { (action) in
            
            let newItem = Task(context: self.context)
            
            newItem.title = textField.text!
            newItem.isDone = false
            newItem.date = Date()
            
            
            self.tasksArray.append(newItem)

            self.delegate?.updateTaskName(name: newItem.title!)
            
            self.saveTasks()
            
        }
        
        
        
        alert.addAction(action)
        
        
        
        self.present(alert, animated: true, completion: nil)
        
    }
    
    
    // MARK: - Sege Section:
    @IBAction func segeControlTapped(_ sender: UISegmentedControl) {
        
        switch Sege.selectedSegmentIndex
        {
        case 0:
            //Loading normal tasks whose are not done
            loadTasks()
            
        case 1:
            //Loading the doneTasks:
            loadDoneTasksFrom()

            
            
        default:
            print("There's something wrong with Sege!")
        }
        
    }
    
    
    
    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        let completedTasksToDisply = 0
        
        if Sege.selectedSegmentIndex == 1 {
            if let firstTask = tasksArray[section].date {
            let dateFormatter = DateFormatter()
            dateFormatter.dateFormat = "dd/MM/yyyy"
            let dateString = dateFormatter.string(from: firstTask)
            
            return   " " + dateString + " " +  " " + "Completed Tasks: \(completedTasksToDisply)"
            }
            
        }
        
        
        return ""
}
    
    
    override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
        let header: UITableViewHeaderFooterView = view as! UITableViewHeaderFooterView
        header.textLabel?.font = UIFont(name: "Verdana", size: 13.0)
        header.textLabel?.textAlignment = NSTextAlignment.center
        
    }
    
    
    
    
    //MARK: - Model Manipulation Methods:
    func saveTasks() {
        do {
            try! context.save()
        } catch let err {
            print("Error Saving context \(err)")
        }
    }
    
    
    func loadTasks() {
        let request: NSFetchRequest<Task> = Task.fetchRequest()
        
        request.predicate = NSPredicate(format: "isDone == %@", NSNumber(value: false))
        
        request.sortDescriptors = [NSSortDescriptor(key: "isDone", ascending: false)]
        
        do{
            tasksArray = try! context.fetch(request)
        } catch {
            print("There was an error with loading items \(error)")
        }
        
        tableView.reloadData()

    }
    
    
    func loadDoneTasksFrom() {
        let request:NSFetchRequest<Task> = Task.fetchRequest()

        request.predicate = NSPredicate(format: "isDone == %@", NSNumber(value: true))
        
        request.sortDescriptors = [NSSortDescriptor(key: "isDone", ascending: false)]
        
        do{
            tasksArray = try context.fetch(request)
        } catch {
            print("Error fetching data from context\(error)")
        }
        
        tableView.reloadData()
        
    }
    
}

1 Ответ

0 голосов
/ 03 августа 2020

РЕДАКТИРОВАТЬ: Хорошо, я понимаю, что вы пытаетесь сделать. Попробуйте - нам понадобится двойной массив - каждый массив внутри нужно будет разделить по дате - наш запрос будет выглядеть примерно так:

var tasksArray = [[Task]]()
var sectionDates = [String]()

func loadTasks() {
    
    tasksArray.removeAll(keepingCapacity: false)
    sectionDates.removeAll(keepingCapacity: false)
    
    let request: NSFetchRequest<Task> = Task.fetchRequest()
        
    request.predicate = NSPredicate(format: "isDone == %@", NSNumber(value: false))
        
    request.sortDescriptors = [NSSortDescriptor(key: "isDone", ascending: false)]
        
    do{
        let tasks = try! context.fetch(request)

        for task in tasks {
             if let taskDate = task.date {
                
                 let dateFormatter = DateFormatter()
                 dateFormatter.dateFormat = "dd/MM/yyyy"
                 let dateString = dateFormatter.string(from: taskDate)
                 
                 if self.sectionDates.contains(dateString) {

                    if let section = self.sectionDates.firstIndex(of: dateString) {
                        self.tasksArray[section].append(task)
                    }
                    
                 } else {
                    self.sectionDates.append(dateString)

                    // EDIT - ADD THIS LINE (and self. where necessary)
                    self.tasksArray.append([])

                    if let section = self.sectionDates.firstIndex(of: dateString) {
                        self.tasksArray[section].append(task)
                    }
                 }
             }
        }

    } catch {
        print("There was an error with loading items \(error)")
    }
        
    tableView.reloadData()

}

Также может быть полезно загружать ваши объекты по порядку но с этой настройкой он все равно должен правильно группировать все независимо от порядка - если вы не хотите, чтобы ваши разделы были в определенном c порядке, вы можете указать в запросе

Теперь изменения в методах делегата tableView

override func numberOfSections(in tableView: UITableView) -> Int {
    return sectionDates.count
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return tasksArray[section].count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "taskCellRow") as! SwipeTableViewCell
    cell.delegate = self
    
    cell.textLabel?.text = tasksArray[indexPath.section][indexPath.row].title
    
    return cell
}

override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    let completedTasksToDisply = 0
        
    if Sege.selectedSegmentIndex == 1 {
        let dateString = sectionDates[section]
        return   " " + dateString + " " +  " " + "Completed Tasks: \(completedTasksToDisply)"
    }
    return ""
}

Я подумал, что оставлю вам остальные методы делегата tableView, но по большей части нам просто нужно идентифицировать раздел перед строкой indexPath при работе с двойным массивом - как мы это делали в cellForRow

Я запустил этот код, и вот результат: введите описание изображения здесь

...