Swift UITableView 删除所选行及其上方的任何行 [英] Swift UITableView delete selected row and any rows above it

查看:31
本文介绍了Swift UITableView 删除所选行及其上方的任何行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的 TableView 包含代表里程日志的单元格.我需要让用户能够删除任何错误.tableview 按降序列出日志.删除顶行是可以的.删除任何其他行,我需要发出警告作为警报,如果确认,则删除所选行及其上方的所有行.这可能吗?是否有任何示例代码?

My TableView contains cells that represent a mileage log. I need to allow users that ability to delete any mistakes. The tableview lists the logs in descending order. Deleting the top row is OK. Deleting any other row I need to issue a warning as an alert and if confirmed then delete the selected row + all rows above it. Is this possible? Is there any example code anywhere?

更新

根据我到目前为止的两个答案,我做了以下....

Based on the two answers I have had so far I have done the following....

import UIKit
import CoreData

class MileageLogsTableViewController: UITableViewController, NSFetchedResultsControllerDelegate {

    @IBOutlet var milageLogTableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        do {
            try fetchedResultsController.performFetch()
        } catch {
            let fetchError = error as NSError
            print("Unable to fetch MileageLog")
            print("\(fetchError), \(fetchError.localizedDescription)")
        }

        // Display an Edit button in the navigation bar for this view controller.
        self.navigationItem.leftBarButtonItem = self.editButtonItem()
    }

    // MARK: - Table view data source

    private lazy var fetchedResultsController: NSFetchedResultsController = {
        // Initialize Fetch Request
        let fetchRequest = NSFetchRequest(entityName: "MileageLog")

        // Add Sort Descriptors
        let dateSort = NSSortDescriptor(key: "tripDate", ascending: false)
        let mileSort = NSSortDescriptor(key: "startMileage", ascending: false)
        fetchRequest.sortDescriptors = [dateSort, mileSort]

        let delegate = UIApplication.sharedApplication().delegate as! AppDelegate
        let managedObjectContext = delegate.managedObjectContext

        // Initialize Fetched Results Controller
        let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedObjectContext, sectionNameKeyPath: nil, cacheName: "rootCache")

        //ADDED AS PER ANSWER FROM SANDEEP
    fetchedResultsController.delegate = self

        return fetchedResultsController

    }()


    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        if let sections = fetchedResultsController.sections {
            return sections.count
        }

        return 0
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if let sections = fetchedResultsController.sections {
            let sectionInfo = sections[section]
            return sectionInfo.numberOfObjects
        }

        return 0
    } 

     override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCellWithIdentifier("MileageLogCell") as! MileageTableViewCell

        // Fetch MileageLog
        if let mileageLog = fetchedResultsController.objectAtIndexPath(indexPath) as? MileageLog {
            //format date as medium style date
            let formatter = NSDateFormatter()
            formatter.dateStyle = .MediumStyle
            let logDateString = formatter.stringFromDate(mileageLog.tripDate!)
            //format NSNumber mileage to string
            let mileageInt:NSNumber = mileageLog.startMileage!
            let mileageString = String(mileageInt)

            cell.lb_LogDate.text = logDateString
            cell.lb_LogMileage.text = mileageString
            cell.lb_LogStartLocation.text = mileageLog.startLocation
            cell.lb_LogDestination.text = mileageLog.endLocation
        }
        return cell
     }


    // Override to support conditional editing of the table view.
    override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
        return true
    }

    // MARK: Fetched Results Controller Delegate Methods
    func controllerWillChangeContent(fetchedResultsController: NSFetchedResultsController) {
        tableView.beginUpdates()
    }

    func controllerDidChangeContent(fetchedResultsController: NSFetchedResultsController) {
        tableView.endUpdates()
    }

    func controller(fetchedResultsController: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
        switch (type) {
            case .Insert:
                break;
            case .Delete:

                let context = fetchedResultsController.managedObjectContext
                if let indexPath = indexPath {

                    if indexPath.row == 0 {
                        //this is the top (first row)
                        // Deleting without warning
                        let objectToDelete = fetchedResultsController.objectAtIndexPath(indexPath) as! NSManagedObject
                        context.deleteObject(objectToDelete)

                        do {
                            try context.save()
                            self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)

                        } catch {
                            print(error)
                        }
                        self.tableView.reloadData();

                    } else {
                        //we are deleted a row that is not the top row
                        // we need to give a warning and if acknowledged then delele all rows from the selected row and all rows above it

                        let alertController = UIAlertController(title: nil, message: "Are you sure? This will remove this and all logs above it.", preferredStyle: .Alert)
                        let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (action) in

                        }
                        alertController.addAction(cancelAction)
                        let deleteAction = UIAlertAction(title: "Delete", style: .Default) { (action) in

                            for deleteindex in 0 ... indexPath.row {
                                let deleteIndexPath = NSIndexPath(forRow: deleteindex, inSection: 0)
                                let objectToDelete = self.fetchedResultsController.objectAtIndexPath(deleteIndexPath) as! NSManagedObject
                                context.deleteObject(objectToDelete)

                                do {
                                    try context.save()
                                    self.tableView.deleteRowsAtIndexPaths([deleteIndexPath], withRowAnimation: .Fade)

                                } catch {
                                    print(error)
                                }
                            }
                            self.tableView.reloadData();
                        }
                        alertController.addAction(deleteAction)

                        // Dispatch on the main thread
                        dispatch_async(dispatch_get_main_queue()) { 
                            self.presentViewController(alertController, animated: true, completion:nil)
                        }

                    }
                }
                break;
            case .Update:
                break;
            case .Move:
                break;
        }
    }

}

现在我的问题是触摸删除什么都不做.树视图已正确填充.编辑按钮位于导航栏中.单击编辑",每行都会出现无条目"图标...滑动一行,会出现删除"块.点击删除,什么都没有...!我错过了什么?

Now my problem is that the touching Delete does nothing. The treeview is correctly populated. The Edit button is in the navbar. Click Edit and the 'no entry' icon appear on each row... slide a row and the Delete block appears. Click delete and nothing...! What have I missed out?

最终工作修复

// Override to support editing the table view.
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {

    switch editingStyle {

     case .Delete:
        let context = fetchedResultsController.managedObjectContext
            if indexPath.row == 0 {
                //this is the top (first row)
                // Deleting without warning
                let indexPathToDelete = NSIndexPath(forRow: 0, inSection: 0)
                let objectToDelete = fetchedResultsController.objectAtIndexPath(indexPathToDelete) as! NSManagedObject
                context.deleteObject(objectToDelete)

                do {
                    try context.save()
                    //self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)

                } catch {
                    print(error)
                }
                //self.tableView.reloadData();

            } else {
                //we are deleted a row that is not the top row
                // we need to give a warning and if acknowledged then delele all rows from the selected row and all rows above it

                let alertController = UIAlertController(title: nil, message: "Are you sure? This will remove this and all logs above it.", preferredStyle: .Alert)
                let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (action) in

                }
                alertController.addAction(cancelAction)
                let deleteAction = UIAlertAction(title: "Delete", style: .Default) { (action) in

                    for deleteindex in 0 ... indexPath.row {
                        let deleteIndexPath = NSIndexPath(forRow: deleteindex, inSection: 0)
                        let objectToDelete = self.fetchedResultsController.objectAtIndexPath(deleteIndexPath) as! NSManagedObject
                        context.deleteObject(objectToDelete)

                    }

                    do {
                        try context.save()

                    } catch {
                        print(error)
                    }
                }
                alertController.addAction(deleteAction)

                // Dispatch on the main thread
                dispatch_async(dispatch_get_main_queue()) {
                    self.presentViewController(alertController, animated: true, completion:nil)
                }

            }
        break;

    default :
        return
    }

}

// MARK: Fetched Results Controller Delegate Methods
func controllerWillChangeContent(controller: NSFetchedResultsController) {
    tableView.beginUpdates()
}

func controllerDidChangeContent(controller: NSFetchedResultsController) {
    tableView.endUpdates()
}

func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
    switch type {
    case .Insert:
        break;
    case .Delete:
        tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade)
    case .Update:
        break;
    case .Move:
        break;
    }
}

推荐答案

除了增强使用编辑操作之外,这是一个简单的解决方案.

Apart from the enhancement to use edit actions this is the easy solution.

首先不要碰委托方法didChangeObject.
保持原状.在托管对象上下文中进行更改后调用它,其工作方式类似于 MVC 模式中的视图.

First of all do not touch the delegate method didChangeObject.
Leave it as it is. It is called after making changes in the managed object context and works like the view in the MVC pattern.

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
    switch type {
        case .insert:
            tableView.insertRows(at: [newIndexPath!], with: .fade)
        case .delete:
            tableView.deleteRows(at: [indexPath!], with: .fade)
        case .update:
            self.configureCell(tableView.cellForRow(at: indexPath!)!, atIndexPath: indexPath!)
        case .move:
            tableView.deleteRows(at: [indexPath!], with: .fade)
            tableView.insertRows(at: [newIndexPath!], with: .fade)
    }
}

commitEditingStyle 中插入删除行的代码,其工作方式类似于 MVC 模式中的模型.该代码删除当前部分中上方选定行中的所有行.

Insert the code to delete the rows in commitEditingStyle which works like the model in the MVC pattern. The code deletes all rows from the selected row above in the current section.

override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
    switch editingStyle {
    case .delete:
      let context = fetchedResultsController.managedObjectContext
      let section = indexPath.section
      let currentRow = indexPath.row
      for index in 0...currentRow {
          let indexPathToDelete = IndexPath(row: index, section: section)
          let objectToDelete = fetchedResultsController.object(at: indexPathToDelete) as! NSManagedObject
          context.delete(objectToDelete)
      }
      do {
        try context.save()
      } catch {
        print(error)
      }
      
    case .insert, .none: break
    }
  }

这篇关于Swift UITableView 删除所选行及其上方的任何行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆