我有一个自定义的 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 类中。
接下来,您需要向名为 arrayOfItems
的 Folder
类添加一个临时属性(您当然可以将其重命名为您想要的任何名称)。在 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/