iOS: NSFetchResultsController sort on transient property (Swift)

别等时光非礼了梦想. 提交于 2019-12-25 04:07:22

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!