我的TableView包含代表里程记录的单元格。我需要允许用户删除任何错误。 tableview按降序列出日志。删除顶行是可以的。删除我需要发出警告的任何其他行作为警报,如果确认,则删除所选行+上面的所有行。这可能吗?在任何地方都有代码吗?
更新
根据我迄今为止所做的两个答案,我已经完成了以下工作....
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;
}
}
}
现在我的问题是触摸删除什么也没做。树视图已正确填充。 “编辑”按钮位于导航栏中。点击修改,然后点击“否”条目'图标出现在每一行...滑动一行,然后出现删除块。点击删除,没有......我错过了什么?
最终工作修补
// 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;
}
}
答案 0 :(得分:5)
除了使用编辑操作的增强功能外,这是一个简单的解决方案。
首先不要触及委托方法deploy.sh
保持原状。它在托管对象上下文中进行更改后调用,并且像MVC模式中的视图一样工作。
didChangeObject
插入代码以删除 func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
switch type {
case .Insert:
tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade)
case .Delete:
tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade)
case .Update:
self.configureCell(tableView.cellForRowAtIndexPath(indexPath!)!, atIndexPath: indexPath!)
case .Move:
tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade)
tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade)
}
}
中的行,其行为类似于MVC模式中的模型。代码将删除当前部分中上面所选行的所有行。
commitEditingStyle
答案 1 :(得分:2)
以下是我相信你能做的事情:)
知道你已经使用fetchedResultsController sort predicate :)对数据进行了排序现在你所要做的就是删除用户选择的从0到行的所有行:)
因为您只有一个部分,所有单元格的部分都为" 0"在他们的索引路径:)你要做的就是从0迭代到所选单元格的行号:)
创建一个索引路径,其迭代值为行和" 0"作为section :)从fetchedResultsController获取对象并在循环中删除它:)
完成后重新加载tableView:)
参考上一个问题:)
case .Delete:
// Delete the row from the data source
let context = fetchedResultsController.managedObjectContext
for deleteindex in 0 ... indexPath.row {
var deleteIndexPath = NSIndexPath(forRow: deleteindex, inSection: 0)
let objectToDelete = fetchedResultsController.objectAtIndexPath(deleteIndexPath) as! NSManagedObject
context.deleteObject(objectToDelete)
}
do {
try context.save()
self.tableView.reloadData();
} catch {
print(error)
}
修改强>
根据您更新的问题,没有调用fetchedResults控制器委托。
那是因为,您还没有告诉fetchedResults控制器,当DB中发生某些事情时,该控制器会通知谁。我的意思是你没有将fetchedResults控制器的委托设置为自己的伙伴:)
通过修改和评论复制粘贴您自己的代码
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")
//set the delegate to self here. You have confirmed the fetchedResultsController delegate in interface remember ??
fetchedResultsController.delegate = self
return fetchedResultsController
}()
希望我回答你的问题:)有疑问吗?在下面发表评论:)快乐的编码伙伴:)
答案 2 :(得分:1)
您可以使用自{8.0}以来的UITableViewDelegate协议editActionsForRowAtIndexPath
方法进行此操作。
返回值
表示行操作的UITableViewRowAction对象数组。您提供的每个操作都用于创建用户可以点按的按钮。
<强>讨论强>
如果要为其中一个表行提供自定义操作,请使用此方法。当用户在一行中水平滑动时,表格视图会将行内容移到一边以显示您的操作。点击其中一个操作按钮会执行与操作对象一起存储的处理程序块。
以下是实施示例
func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
if indexPath.row == 0 {
// Deleting without warning
// The closure will be called when tapping on the action
let deleteClosure = { (action: UITableViewRowAction!, indexPath: NSIndexPath!) -> Void in
// Delete the first object
// you can animate it with the BeginUpdates... EndUpdates too
self.dataSourceArray.removeAtIndex(0)
self.tableView.reloadData()
}
// Default style is Destructive
return [UITableViewRowAction(style: .Default, title: "Delete", handler: deleteClosure)]
}
else {
// Deleting with warning
// The closure will be called when tapping on the action
let deleteClosure = { (action: UITableViewRowAction!, indexPath: NSIndexPath!) -> Void in
let alertController = UIAlertController(title: nil, message: Localization(kStr_NotifDisabled), preferredStyle: .Alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (action) in
}
alertController.addAction(cancelAction)
let deleteAction = UIAlertAction(title: "Delete", style: .Default) { (action) in
self.dataSourceArray(Range(start: 0, end: indexPath.row))
self.tableView.reloadData()
}
alertController.addAction(deleteAction)
// Dispatch on the main thread
dispatch_async(dispatch_get_main_queue()) {
self.presentViewController(alertController, animated: true, completion:nil)
}
}
// Default style is Destructive
return [UITableViewRowAction(style: .Default, title: "Delete", handler: deleteClosure)]
}
}
答案 3 :(得分:0)
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == UITableViewCellEditingStyle.Delete {
arrRecordList.removeAtIndex(indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
}
}