从核心数据开始!难以用简单的语言表达[第二部分]

在本文中,我想进一步揭示Core Data的功能。本文是续篇我真的希望我能想到,核心数据不是众多关系数据库之一,而是一个非常强大的工具,可以成为任何自重的IOS开发人员的武器。

好吧,让我们开始吧!

今天,我们来看一下使用两个NSManageObjectContext和NSFetchedResultsController。

两个NSManageObjectContext,为什么需要这样做?


如果您的应用程序主动使用通过其接收数据的任何API,并且您希望将此数据保存在某处,那么Core Data是一个绝佳的选择。您可能会遇到什么问题?第一个也是最明显的-数据量如此之大,以至于当您尝试保存它们时,我们的应用程序将冻结一段时间,这将影响用户的体验。不能在这里省去普通的GCD,因为独立地,这里提到的我们的Core Data Stack是同步工作的,并且对NSManageObjectContext的任何访问都必须等到循环结束。

但是这里可以使用在后台线程中运行的私有NSManageObjectContext。为了调用它,您必须首先联系我们的NSPersistentContainer。

初始化将如下所示:

lazy var persistentContainer: NSPersistentContainer = {
    let container = NSPersistentContainer(name: "Preset")
    container.loadPersistentStores { (persistent, error) in
        if let error = error {
            fatalError("Error: " + error.localizedDescription)
        }
    }
    container.viewContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy
    container.viewContext.shouldDeleteInaccessibleFaults = true
    container.viewContext.automaticallyMergesChangesFromParent = true
    return container
}()

合并政策


在这里,您可以指定我们的NSManageObjectContext的合并策略。在这里,我们明确指出核心数据在发生数据冲突时应如何表现。

MergePolicy选项:

  1. NSRollbackMergePolicy-发生冲突时,放弃所有更改,直到发生更改为止
  2. NSOverwriteMergePolicy-保存新值,无论数据如何
  3. NSMergeByPropertyStoreTrumpMergePolicy-按属性保存更改的对象属性,在这种情况下,将以保存的数据为准
  4. NSMergeByPropertyObjectTrumpMergePolicy-按属性保存更改的对象属性,在这种情况下,以新数据为准

AutomaticallyMergesChangesFromParent-表示我们的上下文是否将自动合并数据,
然后创建一个新的上下文:

let context = persistentContainer.viewContext
let context = persistentContainer.newBackgroundContext()

现在我们有两个NSManageObjectContext。第一个用于UI,并在主线程上运行,第二个具有privateQueueConcurrencyType,用于在后台工作。

我们将使用它来下载数据。

let object = NSEntityDescription.insertNewObject(forEntityName: "Name", into: context)
saveChanges(with: context)

在这里,我们创建实体,然后可以为其分配必要的属性,然后调用save方法,如下所示:

func saveChanges(with context: NSManagedObjectContext) {
        context.performAndWait {
            if context.hasChanges {
                do {
                    try context.save()
                } catch {
                    context.rollback()
                }
            }
            context.reset()
        }
    }

有两种方法可供选择:

  • performAndWait-在上下文线程上同步执行操作
  • 执行-异步对上下文流执行操作


NSFetchedResultsController


NSFetchedResultsController-执行某些请求并向用户显示必要数据的控制器。

lazy var fetchedResultsController: NSFetchedResultsController<Pack> = {
        let fetchRequest = NSFetchRequest<Pack>(entityName:"Pack")
        fetchRequest.fetchBatchSize = 20
        fetchRequest.sortDescriptors = [NSSortDescriptor(key: "name", ascending:true)]
        let controller = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)

        controller.delegate = self
        do {
            try controller.performFetch()
        } catch {
            print(error.localizedDescription)
        }
        return controller
    }()

NSFetchedResultsController有很多配置,我们将分析其中的几个:

提取限制
FetchLimit —

草图偏移
FetchOffset — . 2, .

FetchbatchSize
FetchBatchSize — . Table/CollectionView 5 , 7 , .

FetchbatchSize
FetchBatchSize — .

SortDescriptor
SortDescriptor — , .

ReturnObjectsAsFaults
ReturnsObjectsAsFaults — , , , PersistentStore RawCache

目前,我们有一个NSFetchedResultsController,它将在表中显示我们的数据。为了更新数据,您需要调用委托方法:

extension ViewController: NSFetchedResultsControllerDelegate {
    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
       collectionView.reloadData()
    }
}

当我们对上下文进行任何更改时,此委托方法将起作用。在此实现中,这发生在我们将数据保存在privateContext中之后。此时,将触发委托方法并更新数据。

常规数据库中的一些操作和核心数据就成为任何iOS开发人员的强大武器。

编码愉快!

All Articles