BLOG

Core Data Asynchronous Fetching in iOS 8 and Swift

In my previous post, I displayed a new Core Data feature that allows developers to perform batch updates directly on the Persistent Store. This time, I’m going to show how to perform asynchronous fetches, a feature that developers have desired for a long time, but has finally become available in iOS 8 (and OS X 10.10 Yosemite).

An asynchronous fetch allows developers to execute a fetch request without blocking the Managed Object Context for the duration of the fetch. As an extra feature, the asynchronous fetch is cancelable by the user and provides progress reporting through NSProgress.

When you perform a standard fetch request using the executeFetchRequest:error: method, the call does not return immediately. Instead, the thread is blocked until the fetch is completed (i.e. the fetched objects populate the Managed Object Context). An asynchronous fetch works differently. Developers perform an asynchronous fetch using the executeRequest:error: method (the same method used for batch updates). This method immediately returns an NSAsynchronousFetchResult. Once the fetch is completed, a completion block is executed.

Asynchronous fetches are only supported by Managed Object Contexts using either the NSPrivateQueueConcurrencyType or the NSMainQueueConcurrencyType (ConfinementConcurrencyType is not supported). Additionally, in order for the Managed Object Context to be updated at the end of the asynchronous fetch, you must specify it to do so.

Here’s how it works. First, create an NSFetchRequest as you would do in a standard fetch. You can use sort descriptors and predicates to be more selective on your data. Then, create an NSAsynchronousFetchRequest using the standard fetch request. After that, pass the asynchronous fetch request to the Managed Object Context executing the executeRequest:error: method on that context. The context immediately returns an NSAsynchronousFetchResult. At the same time, the context sends the fetch to the store. Now, you can continue editing that Managed Object Context performing fetches, faults, etc.

NSAsynchronousFetchRequest is a new subclass of NSPersistentStoreRequest. You can create an NSAsynchronousFetchRequest instance initializing it with an instance of a NSFetchRequest and a completion block.

NSAsynchronousFetchResult is a new subclass of NSPersistentStoreResult. It provides results or errors after the completion. It’s returned immediately by the Managed Object Context when you call executeRequest:error.

Fetching, fetching, fetching

Ok, now let’s see how to implement an asynchronous fetch request. Begin by creating a new project using the Single-View Application template. Name it AsynchronousFetch. Choose Swift as programming language and, of course, select Core Data.

For brevity, I am going to simplify some of the extra work you should do in a real app. First, I create fake data as I did in the post on the Batch Updates. So, select the Asynchronous_Fetch.xcdatamodeld file and add a new entity Person with two attributes:

  • name of type string
  • age of type int16

Generate the class file for the Person entity. To generate fake data let’s add this chunk of code inside the application:didFinishLaunchingWithOptions: of the AppDelegate class and run it just once.

for _ in (0..<900000) {
    var person = NSEntityDescription.insertNewObjectForEntityForName("Person", 
    inManagedObjectContext: self.managedObjectContext!) as Person
    person.name = "Mary"
    person.age = Float(arc4random() % 100)
}

var error : NSError? = nil
if !self.managedObjectContext!.save(&error) {
    NSLog("Unresolved error \(error), \(error!.userInfo)")
    abort()
}

After executing the app once, the persistent store is populated with 900 thousands records. Now, comment the above lines of code to avoid having to execute them again.

In the same method of the AppDelegate class, add the following lines of code:

let vc = self.window!.rootViewController as ViewController
vc.moc = self.managedObjectContext

This will pass the managed object context instance to the view controller.

For this example this is not relevant, but you should modify the line of code where you create the Managed Object Context. Search the managedObjectContext method in the AppDelegate class and modify the line:

var managedObjectContext = NSManagedObjectContext()

with the following line:

var managedObjectContext =
        NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)

Now, let’s move into the ViewController class. First, we need a property to hold the Managed Object Context created in the AppDelegate. So, add this property:

var moc: NSManagedObjectContext?

Next, let’s override the viewDidAppear: method, by adding the following method to the ViewController class:

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

}

After calling it on super, let’s create a fetch request for the entity Person:

let fetchRequest = NSFetchRequest()
let entity = NSEntityDescription.entityForName("Person", 
            inManagedObjectContext: self.moc!)
fetchRequest.entity = entity

After this, we can create an asynchronous fetch request:

let asyncFetch = NSAsynchronousFetchRequest(fetchRequest: fetchRequest) { 
    (result:NSAsynchronousFetchResult!) -> Void in

    if result.finalResult.count > 0 {
        // do here what you want with the data  
    }
    NSLog("Done.")
}

As you can see, we are using the previously created fetch request to create the asynchronous fetch request object. The closure will be executed when the asynchronous fetch completes.

Since we want to report the progress of the fetch to the UI, let’s add a UIProgressView to the view of the view controller. Open the storyboard and add a progress view from the object library. Don’t forget to add autolayout. Create an outlet for the progress view:

@IBOutlet weak var progressView: UIProgressView!

Connect the progress view and the outlet. The progress view will show the progress of the fetch. To do so, we need to create an instance of NSProgress and make it observable.

Before creating the asynchFetch constant (see above), add the following lines of code:

var progress = NSProgress(totalUnitCount: 1)
progress.addObserver(self, 
                    forKeyPath: "fractionCompleted", 
                    options: NSKeyValueObservingOptions.Initial, 
                    context: ProgressObserverContext)

Here, the first line creates an instance of NSProgress. The total unit count is 1, because the fetch is a stream operation and, since you don’t know how many objects you’re going to retrieve, you need to set its value to 1. The second line makes the view controller the observer of the progress instance. The fractionCompleted property is the observed property. The ProgressObserverContext represents the context used by the observer. You can define it before the ViewController class definition

let ProgressObserverContext = UnsafeMutablePointer<Void>()

After the asyncFetch constant, add the following lines of code:

progress.becomeCurrentWithPendingUnitCount(1)
self.moc!.performBlock { // 1
    var error : NSError?
    var results = self.moc!.executeRequest(asyncFetch, 
                error: &error) as NSAsynchronousFetchResult
}
progress.resignCurrent()

Notice that line 1 (the performBlock: method) is not needed here, because we are using a single managed context. Here, I am adding this line, just to make sure that, if you are using two or more managed contexts in your app, you don’t forget to use it.

Finally, to make the fractionCompleted property KVO compliant, we need to implement the observeValueForKeyPath:ofObject:change:context: method:

override func observeValueForKeyPath(keyPath: String!,
                    ofObject object: AnyObject!, 
                    change: [NSObject : AnyObject]!, 
                    context: UnsafeMutablePointer<Void>) {
    if context == ProgressObserverContext {
        NSOperationQueue.mainQueue().addOperationWithBlock() {
            var progress = object as NSProgress
            self.progressView.progress = Float(progress.fractionCompleted)
            NSLog("%f", self.progressView.progress)
        }
    } else {
        super.observeValueForKeyPath(keyPath, 
                ofObject: object, 
                change: change, 
                context: context)
    }
}

Now, it’s ready to run.

Conclusion

Asynchronous fetching is a very powerful feature. Primarily because, it allows developers to continue to use the managed object context while the asynchronous fetch is executing. Together with the new batch updates functionality, asynchronous fetching adds interesting ways to work with managed object contexts and persistent stores.

Core Data Batch Updates in iOS 8 and Swift

Core Data, one of the most important Cocoa frameworks, received new interesting functionalities in iOS 8 and OS X 10.10.

Today, I am going to show you how to perform batch updates of the data contained in the Persistent Store. This will allow you to modify one or more properties of your entities with no need of loading the data into the Managed Object Context. Instead, batch updates are directly performed in the Persistent Store.

Read More

Singletons in Swift

In this post, I will demonstrate one particular way of creating singletons in Swift. But, before starting, let me just say: Swift is a very powerful programming language that allows developers to construct the same functionality in multiple ways. Therefore, the following example is just one way of building a singleton in Swift.

Generally, I discourage the use of singletons, as instantiating an object that will last forever is not good design. Instead, I prefer letting ARC do the memory management and letting ARC decide when to release an object or keep it alive. Additionally, there’s always an alternative way to build what you are trying to do with a singleton.

Read More

Objective-C selectors in Swift

I was building new exercises in Swift—Apple’s new development language—for our upcoming iOS training class in San Francisco, and when combining Swift and Cocoa Touch, I discovered something really interesting.

In particular, for this tutorial, I will examine methods that require a selector as the argument, such as: performSelector:, respondsToSelector: or performSelector:withObject:afterDelay:.

Read More

Teaching Swift—Apple’s new development language

This year, the WWDC was amazing. The shear amount of new stuff is overwhelming, and I still can’t believe that most of my wish list is now covered.

This year’s biggest surprise, however, which I was not really expecting (I guess nobody was), was Apple’s introduction of a new programming language—Swift. But now, Swift is here, and we have to deal with it.

Read More

WWDC 2014 wish list for developers

Every year, before WWDC, there’s a lot of buzz. Transforming technologies are on our minds, and everyone is asking—what’s going to be the next big thing, as technology and change are seemingly synonymous.

Read More

UIKit Dynamics, Core Animation Layers and Autolayout Constraints

Recently, we have been busy with interesting consulting work, and have not had a lot of time to write new blog posts. We appreciate the many emails, asking for more, but we have been fighting time and finalizing projects. Now, however, one of our projects is nearly finished. So, I found a couple of hours to write this post about combining UIKit Dynamics and other UIKit APIs.

Read More

Biometrics: identity theft or individual security?

The iPhone 5s Touch ID™ has changed the standard for smartphone security. Apple’s innovative technology, which was initiated by the purchase of AuthenTech in 2012, enables instant access and personalized security, suddenly making it feel antiquated and overly involved to remember and enter a password into our smartphone.

Read More

Designed and developed in California © 2008-2014 iNVASIVECODE INC