ios - 将 'didMoveCellFromIndexPathToIndexPathBlock' 与核心数据一起使用

标签 ios swift uitableview core-data

我有一个自定义的 UITableView,它负责重新排列单元格的动画,并与不使用核心数据的标准测试数组完美配合。

当尝试使用核心数据和两个实体“文件夹”和“项目”的应用程序时,它们具有To Many 关系,我收到一个错误。

[(Item)] does not have a member called exchangeObjectAtIndex

为了;

tableView.didMoveCellFromIndexPathToIndexPathBlock = {(fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) -> Void in

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

self.itemsArray.exchangeObjectAtIndex(toIndexPath.row, withObjectAtIndex: fromIndexPath.row)

    var error: NSError? = nil
    if !context.save(&error) { abort() }

}

这是因为:

The NSSet, NSMutableSet, and NSCountedSet classes declare the programmatic interface to an unordered collection of objects.

所以我尝试将 NSSet 转换为 NSMutableArray 来管理对象顺序。

func itemsMutableArray() -> NSMutableArray {
    return NSMutableArray(array: (item.allObjects as! [Item]).sorted{ $0.date.compare($1.date) == NSComparisonResult.OrderedAscending } )
}

但随后我在 tableview 中收到以下错误;这是因为可变数组是 AnyObject 所以 swift 不相信它有 title 属性。

cell.textLabel?.text = folderMutableArray[indexPath.row].title

然后我回到我开始的地方。我只是想创建一个简单的列表并重新排列对象的顺序。

这是我的文件夹类:

class Folder: NSManagedObject {

@NSManaged var date: NSDate
@NSManaged var title: String
@NSManaged var item: NSSet

/// Method 1 - Converting to a NSMutableArray

// func itemsMutableArray() -> NSMutableArray {
//    return NSMutableArray(array: (item.allObjects as! [Item]).sorted{ $0.date.compare($1.date) == NSComparisonResult.OrderedAscending } )
// }


// Method 2 - creating an array of type Item
func itemArray() -> [Item] {
    let sortByDate = NSSortDescriptor(key: "Date", ascending: true)
    return item.sortedArrayUsingDescriptors([sortByDate]) as! [Item]
}
}

生产力应用程序一直这样做,所以我知道这是可能的,但不确定如何,有谁知道我哪里出错了或者有任何想法或建议?

最佳答案

这很容易实现。您需要将名为 index 的属性添加到您的 Item。将其设置为整数类型,每当您添加新的 Item 时,将此值设置为您希望项目显示在其下的索引。此属性应作为 NSManaged 属性添加到核心数据模型和您的 Item 类中。

接下来,您需要向名为 arrayOfItemsFolder 类添加一个临时属性(您当然可以将其重命名为您想要的任何名称)。在 Core Data Model 中将其设置为 Transient and Transformable。

在您的 Folder 类中执行以下操作:

class Folder: NSManagedObject {

    @NSManaged var date: NSDate
    @NSManaged var title: String
    @NSManaged var item: NSSet
    @NSManaged var arrayOfItems: [Items]

    override func awakeFromFetch() {
        super.awakeFromFetch()
        self.regenerateItems()
    }

    func regenerateItems() {
        let desc = NSSortDescriptor(key: "index", ascending: true)
        if let array = item.sortedArrayUsingDescriptors([desc]) as? [Item] {
            self.arrayOfItems = array
        }
    }

}

现在,无论何时获取 Folder 的任何实例,您都将获得正确排序且可变的 Item 数组。您只需要考虑另外两种情况。

它们的结果是 awakeFromFetch 仅在您从 Core Data 获取数据时才被调用。因此,您必须考虑其他情况。

添加新的项目

添加新的 Item 时,您需要手动将新的 Item 附加到 arrayOfItems 或调用 regenerateItems( ) 完成添加新的 Item 后。例如,假设您在代码中的某处创建了初始数据:

var folder = NSEntityDescription.insertNewObjectForEntityForName("Folder", inManagedObjectContext: self.managedObjectContext!) as! Folder
var firstItem = NSEntityDescription.insertNewObjectForEntityForName("Item", inManagedObjectContext: self.managedObjectContext!) as! Item
// assuming that you have an inverse relationship from Item to Folder
// line below will assign it and will add your firstItem to Folder's
// NSSet of items
firstItem.folder = folder

// at this point your firstItem is added to your Folder but
// arrayOfItems is empty. So, you should call
folder.arrayOfItems = [firstItem]
// or you can call folder.regenerateItems()

上面的代码是指您创建初始数据时的情况。如果在你的代码中的某处你添加了一个新的 Item 到已经有一些 Items 的文件夹,你有以下内容:

var newItem = NSEntityDescription.insertNewObjectForEntityForName("Item", inManagedObjectContext: self.managedObjectContext!) as! Item
// assuming that you have an inverse relationship from Item to Folder
// line below will assign it and will add your newItem to Folder's
// NSSet of items
newItem.folder = someExistingFolder

// at this point your newItem is added to your Folder but
// arrayOfItems is not yep updated and does not include newItem
// so you should either call
folder.arrayOfItems.append(newItem)
// or you can call folder.regenerateItems()

重新排列项目

此外,当您在 TableView 中移动 Item 时,您需要更改它们在 arrayOfItems 中的索引和顺序。实现此目的的最简单方法可能是更改 arrayOfItems 中项目的顺序,然后遍历此数组,为其中的所有项目分配正确的新索引:

func tableView(tableView: UITableView, moveRowAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath) {
    let itemThatMoved = currentFolder.arrayOfItems[sourceIndexPath.row]
    currentFolder.arrayOfItems.removeAtIndex(sourceIndexPath.row)
    currentFolder.arrayOfItems.insert(itemThatMoved, atIndex:destinationIndexPath.row )
    var currentIndex = 0
    for item in currentFolder.arrayOfItems {
        item.index=currentIndex
        currentIndex++
    }
}

如果这有帮助或者您有任何其他问题,请告诉我。

附言我强烈建议您将关系的名称从 item 更改为 items。复数名称 items 对于 NSSet 来说更符合逻辑。

关于ios - 将 'didMoveCellFromIndexPathToIndexPathBlock' 与核心数据一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31357818/

相关文章:

ios - 如何使用 UIApplication 和 openURL 并从 foo ://q=string? 调用 "string"上的 swift 函数

ios - 返回前台时重新启动动画

ios - 在 swift 中将 url 参数添加到每个 url 的末尾

ios - 如何在 tableViewCell 中运行 imagePicker

ios - ios8 中 iphone 的 UIPopoverController 显示白屏

ios - 实现 3D Touch 预览时非常奇怪的 View 行为

ios - 如何在 iOS 8 中强制 View Controller 方向?

ios - 如何使用删除(_ :) in Swift4 to Removes the selected content from your interface?

ios - 显示表格 View 所有单元格的详细信息

ios - 如何使 UIScrollView 向上滚动效果与 UITableView 一样