iOS:NSFetchResultsController对瞬态属性进行排序(Swift) [英] iOS: NSFetchResultsController sort on transient property (Swift)

查看:83
本文介绍了iOS:NSFetchResultsController对瞬态属性进行排序(Swift)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

例如,我有一个名为 Tasks Entity ,其 Attribute 名为日期和一个 UITableView 填充此任务 实体 p>

这是我目前看到的:

  2014年12月7日:30 
14年12月7日11:00
14年12月7日13:30
14年12月7日16:00

现在让我们假装当前时间实际上是14年12月7日12:00,因此前两行已经过去,但是后两行在将来。我想在 UITableView 中将它们分成组。



我发现可以在以下位置创建瞬态属性实体如下:

  var dateGroup:NSNumber {
get {
if date.compare(NSDate ())== NSComparisonResult.OrderedAscending {
返回0
}否则{
返回1
}
}
}

这可以正常工作,现在在设置sectionNameKeyPath时显示 UITableView 如下: dateGroup:

  Group 0 
-14-Dec-09 09:30
-Dec- 14 11:00
组1
14年12月7日13:30
14年12月7日16:00

我的麻烦是如何获取 UITableView 来实际显示这样的结果(因此,过期任务上方的未来任务):

  Group 1 
14年12月7日13:30
14年12月7日:00
群组0
14年12月7日09:30
14年12月7日11:00

我尝试在瞬态属性(dateGroup)上创建 NSSortDescriptor ,但这



我意识到这是因为我的 NSSortDescriptor 在 date属性上。但是我不知道如何搜索日期> currentDate,然后是日期<的行。



我认为基本上我想做的就是交换周围的节,如果存在多个。



<希望这是有道理的。您将如何解决该排序问题?



更新



好,我已经完全重写为使用2 x FetchRequestControllers self.upcomingFRC(第0部分)和self.elapsedFRC(第1部分),以下内容现在可以正常使用了。



所有插入,更新,移动和&在两个 FetchResultsControllers 之间删除是平滑且动态的。



非常感谢pbasdf。

  func控制器(控制器:NSFetchedResultsController,didChangeObject anObject:AnyObject,atIndexPath indexPath:NSIndexPath ?, forChangeType类型:NSFetchedResultsChangeType,newIndexPath:NSIndexPath?){
开关类型{
case。插入:
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。删除:
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))
如果让largeCell = self.tableViewEvent。 cellForRowAtIndexPath(indexPathOld)如? LargeTableViewCell {
如果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(找到了nil largeCell-配置大型单元)
println( **** ******************************************)
}
} else {
println( ***************************************** *)
println(找到零索引路径-配置大单元格)
println( ************************ ******************)
}
}否则{
如果让indexPathOld = indexPath {
如果让smallCell = self.tableViewEvent.cellForRowAtIndexPath(indexPathOld)为? SmallTableViewCell {
如果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(找到零索引路径-配置小型单元)
println( ************************ ******************)
}
}
case .Move:
println( move)
如果var indexPathOld = indexPath {
如果控制器== 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)
}
默认值:
返回
}
}


解决方案

我将修改您的tableView委托和数据源函数,以使它们交换各节。例如:

 重写func tableView(tableView:UITableView,numberOfRowsInSection部分:Int)-> Int {
如果self.fetchedResultsController.sections!.count = 2 {
section = 1-section
}
让sectionInfo = self.fetchedResultsController.sections![section]作为NSFetchedResultsSectionInfo
return sectionInfo.numberOfObjects
}

 重写func tableView(tableView:UITableView,cellForRowAtIndexPath indexPath:NSIndexPath)-> UITableViewCell {
var newIndexPath:NSIndexPath
如果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)
返回单元格
}

不幸的是,您必须这样做每个功能。还请注意,如果您使用提取的结果控制器来实现插入/删除等操作,因为您必须在此处进行相同的调整。


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

解决方案

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.

这篇关于iOS:NSFetchResultsController对瞬态属性进行排序(Swift)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆