Swift中的NSBatchUpdateRequest及其优势

在此博客中,我们将学习实现NSBatchUpdateRequest Swift 3.x版本在iOS 8中引入的Core Data的说明。 我们还将关注内存使用情况和执行时间。 我还制作了有关此主题的视频教程。 请检查博客末尾的链接。

iOS 8和更高版本以及OS X Yosemite和更高版本,我们可以直接与持久性存储进行交互并更新属性。 根据Apple的说法,这是批量更新。 因此,在不浪费更多时间的情况下,让我们深入了解Xcode中的代码部分。

创建一个新项目,并确保选中使用核心数据复选框。 创建项目后,转到。 xcdatamodeld文件并创建一个名为Student的实体。 我们还将创建它的两个属性, studentNamestudentRollNo

每当我们尝试从编辑器创建NSManagedObject类时,在Swift 3.x中都会出现一个奇怪的错误- 具有相同名称的文件名redeclaration 。 因此,为了解决该问题,请选择实体,然后在“ 数据检查器”部分中转到“ 类” 。 如下图所示,将Module更改为Current Product Module ,将CodegenManual / None

然后,最后单击“编辑器”,然后单击“ 创建NSManagedObject子类”。

因此,我们已经准备好模型子类。 在这里,它们看起来像。

Student + CoreDataClass.swift

 进口基金会 
导入CoreData
 公共班学生:NSManagedObject { 
  } 

Student + CoreDataProperties.swift

 进口基金会 
导入CoreData
 扩展学生{ 
  @nonobjc公共类func fetchRequest()-> NSFetchRequest <学生{ 
返回NSFetchRequest (entityName:“ Student”);
}
  @NSManaged公共var studentName:字符串? 
@NSManaged公共var studentRollNo:Int64
}

现在转到视图控制器,我们将在核心数据中添加50,000个学生记录。 让我们来看一下ViewController.swift。 我们将需要一个AppDelegate共享对象和Core Data context

 导入UIKit 
导入CoreData
 类ViewController:UIViewController { 
 让appDelegate = UIApplication.shared.delegate为!  AppDelegate 
  let context =(UIApplication.shared.delegate as!AppDelegate).persistentContainer.viewContext 
 覆盖func viewDidLoad(){ 
super.viewDidLoad()
}

用于插入50,000条记录的功能。 我将学生姓名作为当前日期和卷编号作为for循环的序列值(从1到50,000)插入。

  func insert(){ 

为我in 1…50000 {

让学生= NSEntityDescription.insertNewObject(forEntityName:“ Student”,into:context)为! 学生
student.studentName =“ \(日期())”
student.studentRollNo = Int64(i)
}
  appDelegate.saveContext() 
}

我们将在viewDidLoad调用此insert函数

 覆盖func viewDidLoad(){ 
super.viewDidLoad()
  //它将打印由核心数据print(appDelegate.persistentContainer.persistentStoreDescriptions)生成的sqlite文件的实际存储 
 插入() 
}

print(appDelegate.persistentContainer.persistentStoreDescriptions)将打印的实际路径。 sqlite文件是。

它将打印如下路径:

  /Users/rajan/Library/Developer/CoreSimulator/Devices/B8BD5017–4BD0–47F7-B840-BE9464817392/data/Containers/Data/Application/2B0E7289–1A4C-4F78-AD00–72285B3FA5F9/Library/Application%20Support/yourProjectName.sqlite 

我们可以导航到该路径,并可以使用称为SQLite ManagerFirefox简单附件 。 您可以从Firefox的附件中下载它。

单击“ SQLite管理器”,选择“连接到数据库”(黄色文件夹图标),然后导航到控制台上打印到.sqlite文件的路径。

导航到.sqlite文件路径

打开.sqlite文件

您将看到50,000个学生条目。 现在我们插入了记录,将注释掉insert函数并立即进行更新。

我们将创建一个函数以在ViewController.swift中获取以毫秒为单位的时间

  func currentTimeMillis()-> Int64 { 
返回Int64(Date()。timeIntervalSince1970 * 1000)
}

现在,我们将创建两种更新方法,一种是批量更新,另一种是旧的传统方法。

  //传统方法 
func update(){
  let request:NSFetchRequest  = Student.fetchRequest() 
做{
让我们开始= currentTimeMillis()
让searchResults =试试context.fetch(request)
适用于searchResults {
student.studentName =“拉詹”
}
  appDelegate.saveContext() 
  print(“差异为\(currentTimeMillis()-开始)”) 
} {
}
}
  //使用NSBatchUpdateRequest 
func updateWithBatch(){
  let request = NSBatchUpdateRequest(entityName:“学生”) 
request.propertiesToUpdate = [“ studentName”:“ Rajan Maheshwari”]
request.resultType = .updatedObjectsCountResultType

做{
让我们开始= currentTimeMillis()
让结果=尝试context.execute(request)作为! NSBatchUpdateResult
  //将打印受影响/更新的行数 
打印(result.result!)
 打印(“成功”) 
print(“差异为\(currentTimeMillis()-开始)”)
}赶上{
}
}

现在,我们将首先在viewDidLoad调用update函数。 这会将50,000名学生的名字更改为Rajan 。 确保注释insert功能。

 覆盖func viewDidLoad(){ 
super.viewDidLoad()
  //插入() 
update()
}

结果如下:

它花费了53.8 MB774毫秒 。 数据库也会更新

现在,通过调用updateWithBatch使用NSBatchUpdateRequest进行updateWithBatch 。 注释掉updateinsert方法。 它将名称从Rajan更新为Rajan Maheshwari

 覆盖func viewDidLoad(){ 
super.viewDidLoad()
  //插入() 
// update()
  updateWithBatch() 
}

结果是:

它花费了大约22.4 MB的时间 ,仅用了91毫秒 。 数据库也将更新。

我们能看到区别吗?

  传统方法 
 内存-53.8 MB 
执行时间-774毫秒
  使用NSBatchUpdateRequest时 
 内存-22.4 MB 
执行时间-91毫秒
 这是使用NSBatchUpdateRequest的优势 

传统方法要求将每条记录加载到内存中,更新记录,并将更改发送到持久性存储。 因此,它将很慢并且消耗大量内存。

在使用NSBatchUpdateRequest情况下,它直接与持久性存储进行通信,然后在那里修改属性。 Apple建议仅​​在传统方法过于占用资源或时间的情况下才使用此功能。

因此,批处理请求易于实现,并且在我们即时更新成千上万的属性时非常有用。

影片教学:

有关我在iOS开发上的更多视频教程,请查看我的YouTube频道。