iOS*_*eek 5 import json core-data ios swift
我正在尝试导入大约 80k 对象的大型数据集。我正在尝试效仿苹果的例子
\n\n我有两个问题:
\n\n // taskContext.performAndWait runs on the URLSession\'s delegate queue\n // so it won\xe2\x80\x99t block the main thread.\nRun Code Online (Sandbox Code Playgroud)\n\n但就我而言,我没有使用 URLSession 来获取 JSON。该文件与应用程序捆绑在一起。在这种情况下,如何确保导入不会阻塞主线程。我应该创建一个自定义队列吗?有什么例子吗?
\n\n\n\n所以我想要实现的是:
\n\nContactBook请不要导入任何内容,因为我们已经导入了 JSON。ContactBook则创建一个并将所有 70kContact对象导入contacts到ContactBook. 这应该像示例中那样批量发生,并且不应该阻塞 UI。我尝试过的:
\n\nprivate func insertContactbookIfNeeded() {\n let fetch: NSFetchRequest<Contactbook> = ContactBook.fetchRequest()\n let contactBookCount = (try? context.count(for: fetch)) ?? 0\n\n if contactBookCount > 0 {\n return\n }\n\n let contacts = Bundle.main.decode([ContactJSON].self, from: "contacts.json")\n\n // Process records in batches to avoid a high memory footprint.\n let batchSize = 256\n let count = contacts.count\n\n // Determine the total number of batches.\n var numBatches = count / batchSize\n numBatches += count % batchSize > 0 ? 1 : 0\n\n for batchNumber in 0 ..< numBatches {\n\n // Determine the range for this batch.\n let batchStart = batchNumber * batchSize\n let batchEnd = batchStart + min(batchSize, count - batchNumber * batchSize)\n let range = batchStart..<batchEnd\n\n // Create a batch for this range from the decoded JSON.\n let contactsBatch = Array(contacts[range])\n\n // Stop the entire import if any batch is unsuccessful.\n if !importOneBatch(contactsBatch) {\n assertionFailure("Could not import batch number \\(batchNumber) range \\(range)")\n return\n }\n }\n}\n\nprivate func importOneBatch(_ contactsBatch: [ContactJSON]) -> Bool {\n\n var success = false\n\n // Create a private queue context.\n let taskContext = container.newBackgroundContext()\n taskContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy\n\n // NOT TRUE IN MY CASE: (Any suggestion ??)\n // taskContext.performAndWait runs on the URLSession\'s delegate queue\n // so it won\xe2\x80\x99t block the main thread. \n\n print("isMainThread: \\(Thread.isMainThread)") // prints true\n\n taskContext.performAndWait {\n let fetchRequest: NSFetchRequest<ContactBook> = ContactBook.fetchRequest()\n fetchRequest.returnsObjectsAsFaults = true\n fetchRequest.includesSubentities = false\n\n let contactBookCount = (try? taskContext.count(for: fetchRequest)) ?? 0\n\n var contactBook: ContactBook?\n\n if contactBookCount > 0 {\n do {\n contactBook = try taskContext.fetch(fetchRequest).first\n } catch let error as NSError {\n assertionFailure("can\'t fetch the contactBook \\(error)")\n }\n } else {\n contactBook = ContactBook(context: taskContext)\n }\n\n guard let book = contactBook else {\n assertionFailure("Could not fetch the contactBook")\n return\n }\n\n // Create a new record for each contact in the batch.\n for contactJSON in contactsBatch {\n\n // Create a Contact managed object on the private queue context.\n let contact = Contact(context: taskContext)\n // Populate the Contact\'s properties using the raw data.\n contact.name = contactJSON.name\n contact.subContacts = NSSet(array: contactJSON.subContacts { subC -> Contact in\n let contact = Contact(context: taskContext)\n contact.name = subC.name\n })\n book.addToContacts(contact)\n }\n\n // Save all insertions and deletions from the context to the store.\n if taskContext.hasChanges {\n do {\n try taskContext.save()\n } catch {\n print("Error: \\(error)\\nCould not save Core Data context.")\n return\n }\n // Reset the taskContext to free the cache and lower the memory footprint.\n taskContext.reset()\n }\n\n success = true\n }\n return success\n}\nRun Code Online (Sandbox Code Playgroud)\n\n问题是,这非常慢,因为在每个批次中,我都会获取工作簿(在每次迭代中都会变得更大),以便能够在通讯录中插入新批次的联系人。有没有一种有效的方法来避免在每个批次中获取工作簿?还有什么建议可以让它更快吗?增加批量大小?创建后台队列?
\n\n更新:
\n\n我尝试创建一个 ContactBook 一次insertWordbookIfNeeded 并将其传递给importOneBatch每次迭代,但我得到:
Thread 1: Exception: "Illegal attempt to establish a relationship \n\'contactBook\' between objects in different contexts\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
762 次 |
| 最近记录: |