【问题标题】:Using 'didMoveCellFromIndexPathToIndexPathBlock' with Core Data将“didMoveCellFromIndexPathToIndexPathBlock”与核心数据一起使用
【发布时间】:2015-07-11 13:45:32
【问题描述】:

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

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

[(Item)] 没有名为 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() }

}

这是因为:

NSSet、NSMutableSet 和 NSCountedSet 类声明 无序对象集合的编程接口。

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

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

然后我在我的表格视图中收到以下错误;这是因为可变数组是 AnyObject,所以 swift 不相信它有 title 属性。

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

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

这是我的Folder 班级:

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]
}
}

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

【问题讨论】:

    标签: ios swift uitableview core-data


    【解决方案1】:

    这很容易实现。您需要将名为index 的属性添加到您的Item。将其设置为整数类型,并且每当您添加新的Item 时,将此值设置为您希望项目出现在其下的索引。这个属性应该作为NSManaged 属性添加到Core Data Model 和你的Item 的类中。

    接下来,您需要向您的 Folder 类添加一个名为 arrayOfItems 的瞬态属性(当然,您可以将其重命名为您想要的任何名称)。在 Core Data Model 中将其设置为 Transient 和 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 的任何实例时,您都将获得一个正确排序且可变的Items 数组。您只需要考虑其他两种情况。

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

    添加新的Item

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

    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()
    

    重新排列Items

    此外,当您在表格视图中移动Items 时,您需要更改它们在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 的逻辑。

    【讨论】:

    • 非常感谢您的回复,非常有用。按照您的建议进行了一些代码重构并更新了核心数据模型和类。我了解到目前为止的更新,但不确定将项目添加到文件夹时的含义。为什么我需要追加到 arrayOfItems 时创建一个 Items 数组?或者为什么我需要在之后致电regenerateItems()?我问的原因是要完全理解代码,而不是盲目地更新代码希望得到结果。我用添加项目的代码更新了我的问题
    • 给我几分钟,我将在我的回答中对此进行扩展
    • 我会接受这个答案,非常感谢你的帮助,我真的很感激!信息量很大。仍在处理一个错误,当我移动一个单元格时,其他单元格将其名称更改为它们正在替换的单元格。例如。如果它们是 5 个单元格 - 1,2,3,4,5 并且我将 3 放在应该 5 而不是 1,2,4,5,3 的末尾,则其他单元格将其文本更新为替换单元格,例如1,2,3(4),4(5),3(移动单元格)
    • @JKSDEV 您是从 currentFolder.arrayOfItems 数组中填充单元格还是使用其他数组?我使用与我发布的代码相同的代码,并且在重新排列单元格时它可以正常工作,所以很奇怪它不适合你:(
    • 我在填充单元格时直接使用selectedFolder.arrayOfItems,例如cell.textLabel?.text = selectedFolder.arrayOfItems[indexPath.row].item & returnCount = selectedFolder.arrayOfItems
    猜你喜欢
    • 2019-10-28
    • 1970-01-01
    • 1970-01-01
    • 2011-11-21
    • 2011-01-06
    • 2016-07-30
    • 2019-12-28
    • 2013-05-28
    • 1970-01-01
    相关资源
    最近更新 更多