Core Data passing objectID to another thread - ios

I've tried Googling and searching SO, thinking it would be quite easy to find but I'm surprised there were little to no examples of my problem in Swift.
I have several threads and from what I've read, it's best to have a separate managed object context for each thread. If I want to access an object from another context, I should pass around the objectID.
My question is, how should I pass the objectID to the context in a new thread?
Below is how the construction of my situation is:
func doSomething(context: NSManagedObjectContext) {
let person = Persons(context: context) // NSManagedObject
dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_USER_INITIATED.value), 0)) {
let background = (UIApplication.sharedApplication().delegate as! AppDelegate).cdh.backgroundContext!
Birthdays(context: background, person) // NSManagedObject
saveContext(background)
}
}
Birthdays has a one to one relationship with Persons. If I execute this code it will give me an error saying:
Illegal attempt to establish a relationship 'person1' between objects in different contexts
Obviously because they are in separated contexts. So I tried to get the objectID of person1 by let personsObjectID = person1.objectID, but I don't know how I should be using it to pass it to the other thread. Any help is appreciated.

Seems like the only thing I needed to do was to add:
let person = background.objectWithID(orders.objectID as! Persons
If I've understood it correctly, objectWithID fetches the object from the store and puts it in the context, returning the managed object. It would be nice if someone could verify this if it's true.
func doSomething(context: NSManagedObjectContext) {
let person = Persons(context: context) // NSManagedObject
dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_USER_INITIATED.value), 0)) {
let background = (UIApplication.sharedApplication().delegate as! AppDelegate).cdh.backgroundContext!
let person = background.objectWithID(orders.objectID as! Persons
Birthdays(context: background, person) // NSManagedObject
saveContext(background)
}
}

Hendrik, you are correct, you should use objectWithID to instantiate the NSManagedObject on the required context.

Related

Working with Core Data (multiple ViewControllers)

There is 1 thing I don't completely understand about working with CoreData (and I can't find a good answer to my question): how do you use CoreData in an app with multiple UIViewcontrollers ?
At the moment I was playing around with core data in multiple controllers and I typed this in each VC:
let app = UIApplication.sharedApplication().delegate as! AppDelegate
let context = app.managedObjectContext
let entity = NSEntityDescription.entityForName("EntityName", inManagedObjectContext: context)!
let entityName = EntityName(entity: entity, insertIntoManagedObjectContext: context)
But I don't think this is the best practice for working with CoreData on multiple controllers (side question: does this have an impact on my app's preformance?). What is the most preferred way?
Do I create a managed object context in each viewcontroller?
(Lots of copy-paste, like I'm doing now)
Do I create a singleton for the creation of CoreData ? I've read somewhere that this was not the preferred way
Do I pass the managed object context to the next controller using
segues (or set a public context variable in the app delegate's function '*didFinishLaunchingWithOptions*')?
Something else?
Thanks in advance!
3-> Setting a public main queue MOC is a good practice. Because main queue is a serial queue.
1-> Using the main queue MOC only for fetching and creating child MOC for each editing is a good practice. Because editing MOCs that can be fetched may cause conflicts.
2-> You can try creating a singleton instance for getting the shared main queue MOC and define some functions that create child context for editing.
4-> But actually theres no best practice for abstract situations.
I think so.
What you're trying to do is to avoid code duplication. Therefore just bring the code into one single function and place it somewhere. It could be an extension on UIViewControler or AppDelegate or just a helper function
This is how an extension on UIViewController would look like:
extension UIViewController
{
func doCoreDataWork()
{
let app = UIApplication.sharedApplication().delegate as! AppDelegate
let context = app.managedObjectContext
let entity = NSEntityDescription.entityForName("EntityName", inManagedObjectContext: context)!
let entityName = EntityName(entity: entity, insertIntoManagedObjectContext: context)
}
}
then call doCoreDataWork() from any view controller.
And no, it has nothing to do with performance

Where should NSManagedObjectContext be created?

I've recently been learning about Core Data and specifically how to do inserts with a large number of objects. After learning how to do this and solving a memory leak problem that I met, I wrote the Q&A Memory leak with large Core Data batch insert in Swift.
After changing NSManagedObjectContext from a class property to a local variable and also saving inserts in batches rather than one at a time, it worked a lot better. The memory problem cleared up and the speed improved.
The code I posted in my answer was
let batchSize = 1000
// do some sort of loop for each batch of data to insert
while (thereAreStillMoreObjectsToAdd) {
// get the Managed Object Context
let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
managedObjectContext.undoManager = nil // if you don't need to undo anything
// get the next 1000 or so data items that you want to insert
let array = nextBatch(batchSize) // your own implementation
// insert everything in this batch
for item in array {
// parse the array item or do whatever you need to get the entity attributes for the new object you are going to insert
// ...
// insert the new object
let newObject = NSEntityDescription.insertNewObjectForEntityForName("MyEntity", inManagedObjectContext: managedObjectContext) as! MyManagedObject
newObject.attribute1 = item.whatever
newObject.attribute2 = item.whoever
newObject.attribute3 = item.whenever
}
// save the context
do {
try managedObjectContext.save()
} catch {
print(error)
}
}
This method seems to be working well for me. The reason I am asking a question here, though, is two people (who know a lot more about iOS than I do) made comments that I don't understand.
#Mundi said:
It seems in your code you are using the same managed object context,
not a new one.
#MartinR also said:
... the "usual" implementation is a lazy property which creates the
context once for the lifetime of the app. In that case you are reusing
the same context as Mundi said.
Now I don't understand. Are they saying I am using the same managed object context or I should use the same managed object context? If I am using the same one, how is it that I create a new one on each while loop? Or if I should be using just one global context, how do I do it without causing memory leaks?
Previously, I had declared the context in my View Controller, initialized it in viewDidLoad, passed it as a parameter to my utility class doing the inserts, and just used it for everything. After discovering the big memory leak is when I started just creating the context locally.
One of the other reasons I started creating the contexts locally is because the documentation said:
First, you should typically create a separate managed object context
for the import, and set its undo manager to nil. (Contexts are not
particularly expensive to create, so if you cache your persistent
store coordinator you can use different contexts for different working
sets or distinct operations.)
What is the standard way to use NSManagedObjectContext?
Now I don't understand. Are they saying I am using the same managed
object context or I should use the same managed object context? If I
am using the same one, how is it that I create a new one on each while
loop? Or if I should be using just one global context, how do I do it
without causing memory leaks?
Let's look at the first part of your code...
while (thereAreStillMoreObjectsToAdd) {
let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
managedObjectContext.undoManager = nil
Now, since it appears you are keeping your MOC in the App Delegate, it's likely that you are using the template-generated Core Data access code. Even if you are not, it is highly unlikely that your managedObjectContext access method is returning a new MOC each time it is called.
Your managedObjectContext variable is merely a reference to the MOC that is living in the App Delegate. Thus, each time through the loop, you are merely making a copy of the reference. The object being referenced is the exact same object each time through the loop.
Thus, I think they are saying that you are not using separate contexts, and I think they are right. Instead, you are using a new reference to the same context each time through the loop.
Now, your next set of questions have to do with performance. Your other post references some good content. Go back and look at it again.
What they are saying is that if you want to do a big import, you should create a separate context, specifically for the import (Objective C since I have not yet made time to learn Swift).
NSManagedObjectContext moc = [[NSManagedObjectContext alloc]
initWithConcurrencyType:NSPrivateQueueConcurrencyType];
You would then attach that MOC to the Persistent Store Coordinator. Using performBlock you would then, in a separate thread, import your objects.
The batching concept is correct. You should keep that. However, you should wrap each batch in an auto release pool. I know you can do it in swift... I'm just not sure if this is the exact syntax, but I think it's close...
autoreleasepool {
for item in array {
let newObject = NSEntityDescription.insertNewObjectForEntityForName ...
newObject.attribute1 = item.whatever
newObject.attribute2 = item.whoever
newObject.attribute3 = item.whenever
}
}
In pseudo-code, it would all look something like this...
moc = createNewMOCWithPrivateQueueConcurrencyAndAttachDirectlyToPSC()
moc.performBlock {
while(true) {
autoreleasepool {
objects = getNextBatchOfObjects()
if (!objects) { break }
foreach (obj : objects) {
insertObjectIntoMoc(obj, moc)
}
}
moc.save()
moc.reset()
}
}
If someone wants to turn that pseudo-code into swift, it's fine by me.
The autorelease pool ensures that any objects autoreleased as a result of creating your new objects are released at the end of each batch. Once the objects are released, the MOC should have the only reference to objects in the MOC, and once the save happens, the MOC should be empty.
The trick is to make sure that all object created as part of the batch (including those representing the imported data and the managed objects themselves) are all created inside the autorelease pool.
If you do other stuff, like fetching to check for duplicates, or have complex relationships, then it is possible that the MOC may not be entirely empty.
Thus, you may want to add the swift equivalent of [moc reset] after the save to ensure that the MOC is indeed empty.
This is a supplemental answer to #JodyHagins' answer. I am providing a Swift implementation of the pseudocode that was provided there.
let managedObjectContext = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.PrivateQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = (UIApplication.sharedApplication().delegate as! AppDelegate).persistentStoreCoordinator // or wherever your coordinator is
managedObjectContext.performBlock { // runs asynchronously
while(true) { // loop through each batch of inserts
autoreleasepool {
let array: Array<MyManagedObject>? = getNextBatchOfObjects()
if array == nil { break }
for item in array! {
let newEntityObject = NSEntityDescription.insertNewObjectForEntityForName("MyEntity", inManagedObjectContext: managedObjectContext) as! MyManagedObject
newObject.attribute1 = item.whatever
newObject.attribute2 = item.whoever
newObject.attribute3 = item.whenever
}
}
// only save once per batch insert
do {
try managedObjectContext.save()
} catch {
print(error)
}
managedObjectContext.reset()
}
}
These are some more resources that helped me to further understand how the Core Data stack works:
Core Data Stack in Swift – Demystified
My Core Data Stack

iOS - Core Data Stack as singleton with main NSManagedObjectContext

I've seen many tutorials and they really help me with understand parent-child managed object context and other things related to this. I am ready to start using it in my app but I have a question. Why nobody use singleton for keeping main managed object context. I guess it would be much better to extract Core Data related objects from AppDelegate and set it to own class right? Something like in this Tutorial at raywenderlich.com. But they still instantiate CoreDataStack class (no problem with this, singleton must be instantiate too) and when it's need they set managedObjectContext in prepareForSegue (and set it to first view controller from AppDelegate). Why not to remove this need and just use singleton CoreDataStack and have possible to use managedObjectContext in each controller if needed?
Second and bonus question: I think it's better to have less code in controller and more in other classes. I think it helps with readability. So what if I move this code from controller and set it for example to CoreDataStack class or some other class that helps with Core Data requests and responses:
func surfJournalFetchRequest() -> NSFetchRequest {
let fetchRequest =
NSFetchRequest(entityName: "JournalEntry")
fetchRequest.fetchBatchSize = 20
let sortDescriptor =
NSSortDescriptor(key: "date", ascending: false)
fetchRequest.sortDescriptors = [sortDescriptor]
return fetchRequest
}
I know it's possible but is it better? If you get app codes from me would it be better if in controller it would be one line CoreDataStack.fetchRequest("JournalEntry", sortedKey: "date")?
And what about if I take this code and insert it to singleton and created function with closure? I would created child managed context in singleton and do needed operations in there and in controller I would just changed UI:
func exportCSVFile() {
navigationItem.leftBarButtonItem = activityIndicatorBarButtonItem()
let privateContext = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
privateContext.persistentStoreCoordinator = coreDataStack.context.persistentStoreCoordinator
privateContext.performBlock { () -> Void in
var fetchRequestError:NSError? = nil
let results = privateContext.executeFetchRequest(self.surfJournalFetchRequest(), error: &fetchRequestError)
if results == nil {
println("ERROR: \(fetchRequestError)")
}
let exportFilePath = NSTemporaryDirectory() + "export.csv"
let exportFileURL = NSURL(fileURLWithPath: exportFilePath)!
NSFileManager.defaultManager().createFileAtPath(exportFilePath, contents: NSData(), attributes: nil)
var fileHandleError: NSError? = nil
let fileHandle = NSFileHandle(forWritingToURL: exportFileURL, error: &fileHandleError)
if let fileHandle = fileHandle {
for object in results! {
let journalEntry = object as! JournalEntry
fileHandle.seekToEndOfFile()
let csvData = journalEntry.csv().dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
fileHandle.writeData(csvData!)
}
fileHandle.closeFile()
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.navigationItem.leftBarButtonItem =
self.exportBarButtonItem()
println("Export Path: \(exportFilePath)")
self.showExportFinishedAlertView(exportFilePath)
})
} else {
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.navigationItem.leftBarButtonItem = self.exportBarButtonItem()
println("ERROR: \(fileHandleError)")
})
}
}
}
I just want to be sure that my aproach would be okay and would be better than original. Thanks
I built my first core data app with a singleton pattern. It seemed logical for me because there is only one core data stack anyway. I was very wrong, the singleton pattern turned into a big mess quickly. I added more and more code to bend the singleton stack to something that works. In the end I gave up and I invested the time to replace the singleton mess with dependency injection.
Here are some of the problems I encountered before I dumped the singleton:
Since the app kept important data, my users requested a backup functionality. To restore from a backup I switched the sqlite file and then I would just create a new Core Data stack. Doing this in a clean way is next to impossible if you use a pull-pattern to get the managedObjectContext from a singleton. So my way to switch the Core Data stack was to tell the user that they have to restart the app. Followed by an exit(). Not the most elegant way to handle this.
After Apple added childContexts I decided to get rid of undo managers and context rollbacks, because that never worked 100% for me. But changing my editing viewControllers so they use child contexts which are discarded when the user hits cancel, was an incredible painful act because I now had a mix of singleton contexts and viewController local contexts in one viewController.
For editing the targets of relationships I had editViewControllers inside editViewController. Because I created the edit context inside the edit viewControllers I ended up saving data to the main context that shouldn't have been saved. It's a bit complicated to explain, but the second viewController saved stuff like new objects to the main context even if the user in the outer edit viewController hit cancel. Which always lead to orphaned objects. So I added more code to bend the singleton in a way that would make it less of a singleton.
I also had a CSV import function and I wanted to preview the data to the user before they press "Import". I build a totally new infrastructure for that. First I parsed the CSV into a data structure that basically duplicated my core data classes. Then I build a viewController to display these non core data classes, with even more code duplication. I would only start to create core data objects when the user pressed import.
After I got rid of the singleton pattern I could reuse the existing data display viewController. I would just give it a different context, in this case an in-memory context that contained the data that will be imported. Much cleaner, less duplicated code.
I guess some of these problems were not really the singletons fault. I was just very inexperienced.
But I still would strongly recommend against singleton core data.
would be one line CoreDataStack.fetchRequest("JournalEntry", sortedKey: "date")?
You don't need a singleton for this. Stuff like this should be in the NSManagedObject subclass you create for JournalEntry.
And what about if I take this code and insert it to singleton and created function with closure? I would created child managed context in singleton and do needed operations in there and in controller I would just changed UI:
And why don't you create a method that doesn't require internal state at all?
class func export(#context: NSManagedObjectContext, toCSVAtPath path: String,
progress: ((current: Int, totalCount: Int) -> Void)?,
completion: ((success: Bool, error: NSError?) -> Void)?) {
Much more flexible.

Swift CoreData Edit/Update entity, when there is only 1 instance of it

This question seems to have been asked a lot already. But I havn't been able to find a swift solution.
I have an entity named "User" which there should only ever be one of. So after it has been created for the first time. I need to edit/update it's values rather than creating more.
I did find a video on it on youtube. Which is the attempt provided below. However it doesn't work.
This is my code in the viewController Class before viewDidLoad()
// Core data setup
let context = (UIApplication.sharedApplication().delegate as AppDelegate).managedObjectContext!
var newUser : User? = nil
var results = NSArray()
var hasAccount = Bool()
Here's my code in viewDidLoad()
println(newUser)
// Core data fetching
var request = NSFetchRequest(entityName: "User")
request.returnsObjectsAsFaults = false
results = context.executeFetchRequest(request, error: nil)!
if results.count > 0 {
hasAccount = true
var res = results[0] as NSManagedObject
println(res.valueForKeyPath("email")!)
}
else {
println("No Account")
}
I use the above code, to figure out if there is already something in the User entity, (then setting hasAccount to "true"). However, if you happen to know a better way to do this. it would be very appreciated!
I printed out "newUser" in hopes that I could make it print the User object. So I could just check if newUser != nil { do this } However all my attempts of getting "User" outside of the above workaround has failed.
Now the code that I havn't been able to get to work in any way is this:
let ent = NSEntityDescription.entityForName("User", inManagedObjectContext: context)
if hasAccount == false {
println("Creating a new User Object")
let newUser = User(entity: ent!, insertIntoManagedObjectContext: context)
newUser.firstName = firstNameTextField.text
newUser.lastName = lastNameTextField.text
newUser.email = emailTextField.text
newUser.password = passwordTextField.text
newUser.accountType = 0
context.save(nil)
} else {
println("Updating existing User Object")
newUser?.firstName = firstNameTextField.text
newUser?.lastName = lastNameTextField.text
newUser?.email = emailTextField.text
newUser?.password = passwordTextField.text
newUser?.accountType = 0
context.save(nil)
}
println(newUser)
The part that's creating a new User object. Should work. (However untested since I moved it into an if statement)
But the part that's supposed to update the entity, doesn't work. I know it runs due to the println.
But it doesn't change the User Entity.
Any help would be greatly appreciated!
Let me start by saying that Core Data is an incredibly powerful framework for persisting and maintaining object graphs. That being said it does, unfortunately, require a large amount of effort just to get started. For this particular reason I typically recommend to beginners looking at MagicalRecord. It's a delightful library that removes almost all of the boiler plate code required setting up the stack and maintaining and creating contexts.
Mattt Thompson (I do miss his writing) wrote an insightful post regarding when you should consider CoreData versus NSKeyedArchiver etc. Always handy to keep for reference.
I broke my solution up into two parts, in the first part I reviewed your original question just to give you some basic pointers. The last part I deal with MagicalRecord as I really feel that it might be better suited for you given its lighter learning curve. We are here to ship apps after all, learn Core Data as you get deeper into iOS.
Question Review
Before I dive into things I want to explore some of the mistakes we can rectify with your solution so you can understand why its not working.
// Core data setup
let context = (UIApplication.sharedApplication().delegate as AppDelegate).managedObjectContext!
I know Apple throw the context into the AppDelegate but its a really messy hack and I typically find its best to have a CoreData singleton somewhere that wraps your contexts. Its nice to stay true to the singular responsibility principle, the App Delegate is responsible for handling App Events and instantiating the ViewController hierarchy. NOT for managing the core data stack.
var newUser : User? = nil
var results = NSArray()
This is swift, why not var results:[AnyObject] = []
var hasAccount = Bool()
you mean, var hasAccount = false....
But lets fast forward, you don't need to define all these variables upfront, anyone reading your code has to scan so many lines before they actually get to the root of what you are trying to achieve. Lets clean it up:
// Core data fetching
let userRequest = NSFetchRequest(entityName: "User")
userRequest.fetchLimit = 1
if let user = context.executeFetchRequest(request, error: nil)?.first as? User {
//now we have a user
} else {
//no user
}
One of the big gotchas that newcomers don't realize is that an NSManagedObjectContext save operation only saves one level up. If that context descends directly from the persistent store then your changes will be saved to disk but if it isn't, that save needs to recursively call save on that contexts parent etc. Here's the documentation:
If a context’s parent store is a persistent store coordinator, then
changes are committed to the external store. If a context’s parent
store is another managed object context, then save: only updates
managed objects in that parent store. To commit changes to the
external store, you must save changes in the chain of contexts up to
and including the context whose parent is the persistent store
coordinator.
So if your context has a parentContext then your save operation will never be saving the user to disk:)
Enter MagicalRecord
Getting started with Magical Record is incredibly simple:
MagicalRecord.setupCoreDataStackWithAutoMigratingSqliteStoreNamed(MyCoreDataStoreName)
This typically goes in your App Delegate. They also have tons of amazing categories on most Core Data classes for common Core Data operations as well as some well thought out infrastructure for handling multi-threading issues.
So now you want to establish a record in your database that there should only be one. Before you get started with that you must make sure that there is also only one object responsible for accessing this user attribute, or in the very least you make sure that only one object can create this user attribute.
For simplicities sake lets call this class the UserManager. The user manager will be responsible for managing all the operations we want to perform with our user. For now it just needs to make sure that when we access it, that there is always one in the database.
class UserManager {
class var sharedManager : UserManager {
struct Static {
static let instance : UserManager = UserManager()
}
return Static.instance
}
func currentUser() -> CurrentUser {
if let user = CurrentUser.MR_findFirst() as? CurrentUser {
return user
} else {
let user = CurrentUser.MR_createEntity() as CurrentUser
user.managedObjectContext!.MR_saveToPersistentStoreAndWait()
return user
}
}
}
Now we have a singleton that will always guarantee that we have one user in the database. You also mentioned that you want to be able to update your user, a naive implementation could be added to our UserManager:
func updateUser(userUpdateHandler: ((user: CurrentUser) -> Void)) {
MagicalRecord.saveWithBlock { (context) -> Void in
let user = self.currentUser()
userUpdateHandler(user: user)
//as the app grows you could probably post a notification
//here so any interested parties could update their info
//if the user changes....
}
}
Calling this from you View Controller is trivial:
//the updateUser function isn't called
//on the main thread so we need to capture
//the values from the UI so we can safely use
//them in the background
let firstName = firstNameTextField.text
let lastName = lastNameTextField.text
let email = emailTextField.text
let password = passwordTextField.text
UserManager.sharedManager.updateUser { (user) -> Void in
user.firstName = firstName
user.lastName = lastName
user.email = email
user.password = password
user.accountType = 0
}
And voila, you have now implemented a pretty standard set of functions to deal with a user in your app.

NSFetchedResultsController plus NSBatchUpdateRequest equals NSMergeConflict. What do I do wrong?

I got a NSFetchedResultsController that I set up using a NSManagedObjectContext. I perform a fetch using this context.
I have as well a NSBatchUpdateRequest that I set up using the same NSManagedObjectContext. I execute the request using the same NSManagedObjectContext.
When I perform the request with the NSBatchUpdateRequest, I can see that all my data have been updated.
If I restart the app, any fetch using NSFetchedResultsController is working as well.
THe problem is when I'm not restarting the app and that I do both operations one after one, I got a NSMergeConflict (0x17427a900) for NSManagedObject (0x1740d8d40) with objectID '0xd000000001b40000... error when I call the method save from my context.
I know that the problem comes from concurrent change on the same data but I don't know what is the solution? One might be to go through the NSMergePolicy class, but I doubt that's a clean way to solve my problem.
What should I do? Have two different contexts ? (how?)
Well it seems I might have found how to do it, but if you see anything wrong, please let me know.
When you do a batch update, you have the possibility to get as a result, whether nothing, the number of rows that were updated or a list of object IDs that were updated. You have to choose the last one.
Once you perform executeRequest from the context, you need to get the list of object IDs, loop through all of them to get every NSManagedObject into Faults thanks to the method objectWithID of the context object. If you don't know what Faults object are in Core Data, here is the explanation.
With every NSManagedObject you get, you need to refresh the context using its method refreshObject.
Once you've done that, you need to perform again the performFetch of your fetchedResultsController to come back to where you were before the batch update.
Tell me if I'm wrong somewhere.
Here is the code:
let batchUpdate = NSBatchUpdateRequest(entityName: "myEntity")
batchUpdate.propertiesToUpdate = ["myPropertieToUpdate" : currency.amountToCompute]
batchUpdate.affectedStores = managedContext.persistentStoreCoordinator?.persistentStores
batchUpdate.resultType = .UpdatedObjectIDsResultType
var batchError: NSError?
let batchResult = managedContext.executeRequest(batchUpdate, error: &batchError) as NSBatchUpdateResult?
if let result = batchResult {
println("Records updated \((result.result as [NSManagedObjectID]).count)")
// Extract Object IDs
let objectIDs = result.result as [NSManagedObjectID]
for objectID in objectIDs {
// Turn Managed Objects into Faults
let nsManagedObject: NSManagedObject = managedContext.objectWithID(objectID)
if let managedObject = nsManagedObject as NSManagedObject? {
managedContext.refreshObject(managedObject, mergeChanges: false)
}
}
// Perform Fetch
var error: NSError? = nil
if !fetchedResultsController.performFetch(&error) {
println("error: + \(error?.localizedDescription), \(error!.userInfo)")
}
} else {
println("Could not update \(batchError), \(batchError!.userInfo)")
}
EDIT:
Here are two links for more explanations:
http://code.tutsplus.com/tutorials/ios-8-core-data-and-batch-updates--cms-22164
http://www.bignerdranch.com/blog/new-in-core-data-and-ios-8-batch-updating/

Resources