将“didMoveCellFromIndexPathToIndexPathBlock”与核心数据一起使用

Posted

技术标签:

【中文标题】将“didMoveCellFromIndexPathToIndexPathBlock”与核心数据一起使用【英文标题】:Using 'didMoveCellFromIndexPathToIndexPathBlock' with Core Data 【发布时间】: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]


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

【问题讨论】:

【参考方案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

以上是关于将“didMoveCellFromIndexPathToIndexPathBlock”与核心数据一起使用的主要内容,如果未能解决你的问题,请参考以下文章

如何将Ios文件上传到

Javascript 将正则表达式 \\n 替换为 \n,将 \\t 替换为 \t,将 \\r 替换为 \r 等等

如何将视频文件转换格式

sh 一个将生成CA的脚本,将CA导入到钥匙串中,然后它将创建一个证书并与CA签名,然后将其导入到

python怎么将0写入文件?

如何将CMD窗口背景改成透明?