核心数据和Swift:批量更新

尽管Core Data在OS X和iOS上已经存在很多年了,但最近才添加的功能是批处理更新。 多年来,开发人员一直在要求此功能,Apple终于找到了一种将其集成到Core Data中的方法。 在本教程中,我将向您展示批处理更新的工作方式以及它们对Core Data框架的意义。

1.问题

核心数据擅长管理对象图。 对于核心数据而言,即使是具有许多实体和关系的复杂对象图也不是什么大问题。 但是,Core Data确实存在一些薄弱环节,因此更新大量记录就是其中之一。

这个问题很容易理解。 每当您更新记录时,Core Data都会将记录加载到内存中,更新记录,然后将更改保存到持久存储中,例如SQLite数据库。

如果Core Data需要更新大量记录,则需要将每条记录加载到内存中,更新记录,并将更改发送到持久性存储。 如果记录数太大,iOS会由于缺乏资源而急救。 即使运行OS X的设备可能有执行请求的资源,它也会很慢并且会占用大量内存。

另一种方法是分批更新记录,但这也需要大量时间和资源。 在iOS 7上,这是iOS开发人员唯一的选择。 自从iOS 8和OS X Yosemite以来,情况已不再如此。

2.解决方案

在iOS 8或更高版本以及OS X Yosemite或更高版本上,可以直接与持久性存储进行对话并告诉您要更改的内容。 这通常涉及更新属性。 苹果称此功能为批量更新。

有很多陷阱需要提防。 Core Data可以为您做很多事情,在使用批处理更新之前,您甚至可能没有意识到。 验证是一个很好的例子。 由于Core Data直接在永久存储(例如SQLite数据库)上执行批量更新,因此Core Data无法对您写入永久存储的数据执行任何验证。 这意味着您要负责确保不将无效数据添加到持久性存储中。

什么时候使用批量更新? Apple建议仅​​在传统方法过于占用资源或时间的情况下才使用此功能。 如果您需要将数百或数千封电子邮件标记为已读,则批处理更新是iOS 8及更高版本和OS X Yosemite及更高版本的最佳解决方案。

3.它如何运作?

为了说明批处理更新是如何工作的,我建议我们重新访问Done ,它是一个管理任务列表的简单Core Data应用程序。 我们将在导航栏中添加一个按钮,将列表中的每个项目标记为已完成。

步骤1:Projet设置

GitHub下载或克隆项目,然后在Xcode 7中打开它。在模拟器中运行该应用程序,并添加一些待办事项。

添加待办事项

步骤2:创建栏按钮项

打开ViewController.swift和申报财产, checkAllButton ,类型UIBarButtonItem顶部。

import UIKit
import CoreData

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, NSFetchedResultsControllerDelegate {

    let ReuseIdentifierToDoCell = "ToDoCell"
    
    @IBOutlet weak var tableView: UITableView!
    
    var managedObjectContext: NSManagedObjectContext!
    
    var checkAllButton: UIBarButtonItem!
    
    ...

}

ViewController类的viewDidLoad()方法中初始化长条按钮项,并将其设置为导航项的左长条按钮项。

// Initialize Check All Button
checkAllButton = UIBarButtonItem(title: "Check All", style: .Plain, target: self, action: "checkAll:")

// Configure Navigation Item
navigationItem.leftBarButtonItem = checkAllButton

步骤3:实现checkAll(_:)方法

checkAll(_:)方法非常简单,但是需要注意一些警告。 在下面查看其实现。

func checkAll(sender: UIBarButtonItem) {
    // Create Entity Description
    let entityDescription = NSEntityDescription.entityForName("Item", inManagedObjectContext: managedObjectContext)
    
    // Initialize Batch Update Request
    let batchUpdateRequest = NSBatchUpdateRequest(entity: entityDescription!)
    
    // Configure Batch Update Request
    batchUpdateRequest.resultType = .UpdatedObjectIDsResultType
    batchUpdateRequest.propertiesToUpdate = ["done": NSNumber(bool: true)]
    
    do {
        // Execute Batch Request
        let batchUpdateResult = try managedObjectContext.executeRequest(batchUpdateRequest) as! NSBatchUpdateResult
        
        // Extract Object IDs
        let objectIDs = batchUpdateResult.result as! [NSManagedObjectID]
        
        for objectID in objectIDs {
            // Turn Managed Objects into Faults
            let managedObject = managedObjectContext.objectWithID(objectID)
            managedObjectContext.refreshObject(managedObject, mergeChanges: false)
        }
        
        // Perform Fetch
        try self.fetchedResultsController.performFetch()
        
    } catch {
        let updateError = error as NSError
        print("\(updateError), \(updateError.userInfo)")
    }
}
创建批处理请求

我们首先为Item实体创建一个NSEntityDescription实例,然后使用它来初始化NSBatchUpdateRequest对象。 该NSBatchUpdateRequest类的子类NSPersistentStoreRequest

// Create Entity Description
let entityDescription = NSEntityDescription.entityForName("Item", inManagedObjectContext: managedObjectContext)

// Initialize Batch Update Request
let batchUpdateRequest = NSBatchUpdateRequest(entity: entityDescription!)

我们将批处理更新请求的结果类型设置为.UpdatedObjectIDsResultType ,它是NSBatchUpdateRequestResultType枚举的成员值。 这意味着批处理更新请求的结果将是一个数组,其中包含由批处理更新请求更改的记录的对象ID( NSManagedObjectID类的实例)。

// Configure Batch Update Request
batchUpdateRequest.resultType = .UpdatedObjectIDsResultType

我们还将填充批处理更新请求的propertiesToUpdate属性。 在此示例中,我们将propertiesToUpdate设置为包含一个键"done"且值为NSNumber(bool: true)的字典。 这意味着每个Item记录都将被设置为done ,这就是我们要做的。

// Configure Batch Update Request
batchUpdateRequest.propertiesToUpdate = ["done": NSNumber(bool: true)]
执行批量更新请求

即使批处理更新绕过托管对象上下文,也可以通过在NSManagedObjectContext实例上调用executeRequest(_:)来执行批处理更新请求。 此方法接受一个参数,即NSPersistentStoreRequest类的实例。 因为executeRequest(_:)是一个throwing方法,所以我们在do-catch语句中执行该方法。

do {
    // Execute Batch Request
    let batchUpdateResult = try managedObjectContext.executeRequest(batchUpdateRequest) as! NSBatchUpdateResult
    
} catch {
    let updateError = error as NSError
    print("\(updateError), \(updateError.userInfo)")
}
更新托管对象的上下文

即使我们将批处理更新请求移交给托管对象上下文,托管对象上下文也不知道由于执行批处理更新请求而导致的更改。 如前所述,它绕过了托管对象的上下文。 这样可以批量更新其功能和速度。 要解决此问题,我们需要做两件事:

  • 将由批处理更新更新的受管对象变成错误
  • 告诉获取的结果控制器执行获取以更新用户界面

这是我们在do-catch语句的do子句中的checkAll(_:)方法的后几行中dodo-catch 。 如果批量更新请求成功,则从NSBatchUpdateResult对象中提取NSManagedObjectID实例的数组。

// Extract Object IDs
let objectIDs = batchUpdateResult.result as! [NSManagedObjectID]

然后,我们遍历objectIDs数组,向托管对象上下文查询相应的NSManagedObject实例,然后通过调用refreshObject(_:mergeChanges:)将托管对象作为第一个参数传入,从而将其变为故障。 为了迫使被管理对象出现故障,我们将false作为第二个参数传递。

// Extract Object IDs
let objectIDs = batchUpdateResult.result as! [NSManagedObjectID]

for objectID in objectIDs {
    // Turn Managed Objects into Faults
    let managedObject = managedObjectContext.objectWithID(objectID)
    managedObjectContext.refreshObject(managedObject, mergeChanges: false)
}
获取更新的记录

最后一步是告诉获取结果控制器执行获取操作以更新用户界面。 如果不成功,则在do-catch语句的catch子句中捕获错误。

do {
    // Execute Batch Request
    let batchUpdateResult = try managedObjectContext.executeRequest(batchUpdateRequest) as! NSBatchUpdateResult
    
    // Extract Object IDs
    let objectIDs = batchUpdateResult.result as! [NSManagedObjectID]
    
    for objectID in objectIDs {
        // Turn Managed Objects into Faults
        let managedObject = managedObjectContext.objectWithID(objectID)
        managedObjectContext.refreshObject(managedObject, mergeChanges: false)
    }
    
    // Perform Fetch
    try self.fetchedResultsController.performFetch()
    
} catch {
    let updateError = error as NSError
    print("\(updateError), \(updateError.userInfo)")
}

尽管对于轻松操作而言,这似乎很麻烦且相当复杂,但请记住,我们绕过了Core Data堆栈。 换句话说,我们需要照顾一些Core Data通常为我们完成的整理工作。

步骤4:建立并执行

生成项目并在模拟器或物理设备上运行应用程序。 单击或点击右侧的栏按钮项,以检查列表中的每个待办事项。

检查所有待办事项

结论

批处理更新是Core Data框架的重要补充。 它不仅可以满足开发人员多年的需求,而且只要您牢记一些基本规则,就可以轻松实施。 在下一个教程中,我们将仔细研究批删除,这是最近才添加的Core Data框架的另一个功能。

翻译自: https://code.tutsplus.com/tutorials/core-data-and-swift-batch-updates--cms-25120

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值