问题
Say for example I have an Entity
called Tasks with an Attribute
called date and a UITableView
populating this Tasks Entity
.
This is what I currently see:
7-Dec-14 09:30
7-Dec-14 11:00
7-Dec-14 13:30
7-Dec-14 16:00
Now lets pretend the current time is actually 7-Dec-14 12:00 so the first 2 rows have passed but the second 2 rows are in the future. I want to split these into Groups within the UITableView
.
I've found I can create a Transient Property on the Entity as follows:
var dateGroup: NSNumber {
get {
if date.compare(NSDate()) == NSComparisonResult.OrderedAscending {
return 0
} else {
return 1
}
}
}
This works and now shows the UITableView
as follows, when I set sectionNameKeyPath: "dateGroup":
Group 0
7-Dec-14 09:30
7-Dec-14 11:00
Group 1
7-Dec-14 13:30
7-Dec-14 16:00
My trouble is how can I get the UITableView
to actually display the results like this (so future tasks above the expired tasks):
Group 1
7-Dec-14 13:30
7-Dec-14 16:00
Group 0
7-Dec-14 09:30
7-Dec-14 11:00
I've tried creating a NSSortDescriptor
on the transient property (dateGroup) but this doesn't work.
I realise this is happening because my NSSortDescriptor
on the "date" attribute. But I don't know how to search for rows where date > currentDate, followed by date < currentDate.
I think basically what I want to do is swap the sections around IF there is more than 1.
Hope this makes sense. How would you tackle this sorting issue?
Update
OK, I've completely rewritten it to use 2 x FetchRequestControllers
self.upcomingFRC (section 0) and self.elapsedFRC (section 1) and the following is now working without any errors or nils.
All Inserts, Updates, Moves & Deletes are smooth and animated between both FetchResultsControllers
.
Thank you very much pbasdf.
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
switch type {
case .Insert:
println("insert")
if var indexPathNew = newIndexPath {
if controller == self.elapsedFRC { indexPathNew = NSIndexPath(forRow: newIndexPath!.row, inSection: 1) }
println("N indexPath : \(indexPathNew)")
self.tableViewEvent.insertRowsAtIndexPaths([indexPathNew], withRowAnimation: .Fade)
}
case .Delete:
println("delete")
if var indexPathOld = indexPath {
if controller == self.elapsedFRC { indexPathOld = NSIndexPath(forRow: indexPath!.row, inSection: 1) }
println("O indexPath : \(indexPathOld)")
self.tableViewEvent.deleteRowsAtIndexPaths([indexPathOld], withRowAnimation: .Fade)
}
case .Update:
println("update")
if self.showLarge {
if var indexPathOld = indexPath {
if controller == self.elapsedFRC { indexPathOld = NSIndexPath(forRow: indexPath!.row, inSection: 1) }
println("O indexPath : \(indexPathOld)")
if let largeCell = self.tableViewEvent.cellForRowAtIndexPath(indexPathOld) as? LargeTableViewCell {
if indexPathOld.section == 0 { self.configureLargeCell(largeCell, frc:self.upcomingFRC, row:indexPathOld.row) }
else if indexPathOld.section == 1 { self.configureLargeCell(largeCell, frc:self.elapsedFRC, row:indexPathOld.row) }
} else {
println("******************************************")
println("found nil largeCell - configure Large Cell")
println("******************************************")
}
} else {
println("******************************************")
println("found nil indexPath - configure Large Cell")
println("******************************************")
}
} else {
if let indexPathOld = indexPath {
if let smallCell = self.tableViewEvent.cellForRowAtIndexPath(indexPathOld) as? SmallTableViewCell {
if indexPathOld.section == 0 { self.configureSmallCell(smallCell, frc:self.upcomingFRC, row:indexPathOld.row) }
else if indexPathOld.section == 1 { self.configureSmallCell(smallCell, frc:self.elapsedFRC, row:indexPathOld.row) }
} else {
println("******************************************")
println("found nil smallCell - configure Small Cell")
println("******************************************")
}
} else {
println("******************************************")
println("found nil indexPath - configure Small Cell")
println("******************************************")
}
}
case .Move:
println("move")
if var indexPathOld = indexPath {
if controller == self.elapsedFRC { indexPathOld = NSIndexPath(forRow: indexPath!.row, inSection: 1) }
println("O indexPath : \(indexPathOld)")
self.tableViewEvent.deleteRowsAtIndexPaths([indexPathOld], withRowAnimation: .Fade)
}
if var indexPathNew = newIndexPath {
if controller == self.elapsedFRC { indexPathNew = NSIndexPath(forRow: newIndexPath!.row, inSection: 1) }
println("N indexPath : \(indexPathNew)")
self.tableViewEvent.insertRowsAtIndexPaths([indexPathNew], withRowAnimation: .Fade)
}
default:
return
}
}
回答1:
I would amend your tableView delegate and datasource functions, so that they "swap" the sections over. For example:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if self.fetchedResultsController.sections!.count = 2 {
section = 1 - section
}
let sectionInfo = self.fetchedResultsController.sections![section] as NSFetchedResultsSectionInfo
return sectionInfo.numberOfObjects
}
and
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var newIndexPath : NSIndexPath
if self.fetchedResultsController.sections!.count = 2 {
newIndexPath = NSIndexPath(forRow: indexPath.row, inSection: (1 - indexPath.section))
} else {
newIndexPath = indexPath
}
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
self.configureCell(cell, atIndexPath: newIndexPath)
return cell
}
Sadly you will have to do this for each of the functions. Also beware if you use the fetched results controller to implement inserts/deletes etc, because you will have to make the same adjustment there.
来源:https://stackoverflow.com/questions/27347181/ios-nsfetchresultscontroller-sort-on-transient-property-swift