iOS Swift教程 Core Data (五)NSFetchedResultsController 下

监视变化

上半部分中,我们已经学习了NSFetchResultsController的3个主要功能中的2个:section和caching,接下来我们学习它的最后一个主要特征,这个特征某种意义上来说,是一把双刃剑,用得好很有效但也很容易误用。

之前当我们点击某个国家的cell增加该国家的win场数后,调用了tableView的reload函数来更新表格,但是表格的更新源可能有很多种,不仅仅是点击某个cell,如果都手动做,会很繁琐,NSFetchResultsController可以监控这样的变化并通知它的代理-NSFetchResultsControllerDelegate。一旦数据发生变化,我们可以使用这个代理来刷新表格。

转载请注明出处:http://blog.csdn.net/yamingwu/article/details/42427205

源代码地址:https://github.com/dnawym/StudySwift/tree/master/CoreData/WorldCup

NSFetchResultsController监控的是所有已经被fetch的对象。下面我们来看看怎么实现这个功能:

继承于这个代理并设置自己是其代理即可以监视变化了:

class ViewController: UIViewController, <span style="color:#ff0000;">NSFetchedResultsControllerDelegate</span> {
fetchedResultsController.delegate = self
这里需要注意的是NSFetchResultsController只能监视在其被构造时传入的managed object context中发生的变化。

响应变化

移除之前调用的reloadData,添加以下代理函数重载:

    func controllerDidChangeContent(controller: NSFetchedResultsController) {
            tableView.reloadData()
    }
程序执行效果如下,当某个国家胜场超过排在它之前的国家时,这个国家会被自动移动到胜场低于它的国家之前。这里可以看到,加纳已经在喀麦隆之前,因为加纳胜场为5而喀麦隆胜场为4。


添加以下代码,让table view cell的刷新更完善,这里是一个标准做法begin updates-make changes-end updates:

    // 变化即将发生,调用beginUpdates可以让一些列变化同时以动画的方式发生
    func controllerWillChangeContent(controller: NSFetchedResultsController) {
        tableView.beginUpdates()
    }
    
    // 哪些object发生了什么样的变化(插入,删除,更新还是移动)以及会影响哪些index
    func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath!, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath!) {
        switch type {
            case .Insert:
                tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Automatic)
            case .Delete:
                tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
            case .Update:
                let cell = tableView.cellForRowAtIndexPath(indexPath) as TeamCell
                configureCell(cell, indexPath: indexPath)
            case .Move:
                tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
                tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Automatic)
            default:
                break
        }
    }
    
    // 应用这些变化
    func controllerDidChangeContent(controller: NSFetchedResultsController) {
        tableView.endUpdates()
    }
编译并运行程序,多次点击某个国家,你将看到cell以平滑的方式在更新着。
类似的方法还有didChangeSection:

    func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
        let indexSet = NSIndexSet(index: sectionIndex)
        
        switch type {
        case .Insert:
            tableView.insertSections(indexSet, withRowAnimation: .Automatic)
        case .Delete:
            tableView.deleteSections(indexSet, withRowAnimation: .Automatic)
        default:
            break
        }
    }
添加队伍

接下来,我们实现添加队伍功能,现在程序的右上角有一个disabled的“+”按钮,我们通过晃动手机来enable这个按钮

    override func motionEnded(motion: UIEventSubtype, withEvent event: UIEvent) {
        if motion == .MotionShake {
            addButton.enabled = true
        }
    }


实现addTeam:

    @IBAction func addTeam(sender: AnyObject) {
        var alert = UIAlertController(title: "Secret Team", message: "Add a new team", preferredStyle: UIAlertControllerStyle.Alert)
        
        alert.addTextFieldWithConfigurationHandler{(textField: UITextField!) in
            textField.placeholder = "Team Name"
        
        }
        alert.addTextFieldWithConfigurationHandler{(textField: UITextField!) in
            textField.placeholder = "Qualifying Zone"
        
        }
        
        alert.addAction(UIAlertAction(title: "Save", style: .Default, handler: {
            (action: UIAlertAction!) in
            println("Saved")
            
            let nameTextField = alert.textFields![0] as UITextField
            let zoneTextField = alert.textFields![0] as UITextField
            
            let team = NSEntityDescription.insertNewObjectForEntityForName("Team", inManagedObjectContext: self.coreDataStack.context) as Team
            
            team.teamName = nameTextField.text
            team.qualifyingZone = zoneTextField.text
            team.imageName = "wenderland-flag"
            
            self.coreDataStack.saveContext()
            }))
        
        alert.addAction(UIAlertAction(title: "Cancel", style: .Default, handler: {
                (action: UIAlertAction!) in
                println("Cancel")
                }))
        
        presentViewController(alert, animated: true, completion: nil)
    }
编译运行,按下键盘的Cmd+Ctrl+Z来模拟摇晃事件,这将使能右上角的+按钮:


将table下滑到欧洲国家结束和中北美及加勒比国家开始处:


点击+号,添加如图所示的国家:


点击save,你将会看到新的section被添加到table view中。这个操作既添加了新的section同时也将属于这个section的国家添加到了fetch results controller的结果集合中。由于我们实现了fetch results controller的代理,table view也会被自动更新,多么神奇!

至此,我们完成了第五节的学习。通过这一节,我们知道了NSFetchedResultsController的作用,以及它是如何和table view配合工作的。需要注意的是,NSFetchedResultsController不是为了用于监控Core Data的变化而设计的,有一些其它的通知和技术更适合做监控用。如果实现了NSFetchResultsController的代理,即使对后台数据进行很小的改变,也会触发它的代理,所以需要注意。当你发现你在写一些复杂的逻辑来计算section或者为了让你的table view和CoreData配合工作,请使用NSFetchedResultsController。




评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值