Sunday, June 17, 2012

Tutorial: Concurrency with Core Data Tutorial

I thought that all of the important Core Data articles were scattered in so many places and so I thought I should make a good set of notes. None of the text below reflect my own words, and they are taken directly from the Apple articles in the links. I had set out to start using Core Data in multiple threads, but then I realized my understanding of the theory of Core Data was weak, and so I thought I should build a solid understanding before I started programming.

Core Data Core Competencies

Core Data
You use Core Data to manage the model (in the model-view-controller sense of the word) objects in your application. Core Data is an object-graph management and persistence framework. Among other things, it:

  • Allows you to efficiently fetch model objects from a persistent store and save changes back to the store.
  • Provides an infrastructure for tracking changes to your model objects. It gives you automatic support for undo and redo, and for maintaining reciprocal relationships between objects.
  • Allows you to maintain disjoint sets of edits of your model objects. Disjoint sets are useful if you want to, for example, allow the user to make edits in one view that may be discarded without affecting data displayed in another view.
  • Allows you to keep just a subset of your model objects in memory at any given time. This is useful for keeping the memory footprint of your application as low as possible.
  • Has an infrastructure for data store versioning and migration. This infrastructure lets you easily upgrade an old version of the data file to the current version.
To support this functionality, Core Data uses a schema called a managed object model that describes the entities in your application. 

Core Data Stack

A Core Data stack is composed of the following objects: one or more managed object contexts connected to a single persistent store coordinator which is in turn connected to one or more persistent stores. A stack contains all the Core Data components you need to fetch, create, and manipulate managed objects. Minimally it contains:
  • An external persistent store that contains saved records.
  • A persistent object store that maps between records in the store and objects in your application.
  • A persistent store coordinator that aggregates all the stores.
  • A managed object model that describes the entities in the stores.
  • A managed object context that provides a scratch pad for managed objects.

Managed Object
A managed object is a model object (in the model-view-controller sense) that represents a record from a persistent store. A managed object is an instance of NSManagedObject or a subclass of NSManagedObject. A managed object is registered with a managed object context. In any given context, there is at most one instance of a managed object that corresponds to a given record in a persistent store.

A managed object has a reference to an entity description object that tells it what entity it represents. In this way,NSManagedObject can represent any entity—you don’t need a unique subclass per entity. You use a subclass if you want to implement custom behavior, for example to calculate a derived property value, or to implement validation logic.

Managed Object Context

A managed object context represents a single object space, or scratch pad, in a Core Data application. A managed object context is an instance of NSManagedObjectContext. Its primary responsibility is to manage a collection of managed objects. These managed objects represent an internally consistent view of one or more persistent stores. The context is a powerful object with a central role in the life-cycle of managed objects, with responsibilities from life-cycle management (including faulting) to validation, inverse relationship handling, and undo/redo.
From your perspective, the context is the central object in the Core Data stack. It’s the object you use to create and fetch managed objects, and to manage undo and redo operations. Within a given context, there is at most one managed object to represent any given record in a persistent store.

A context is connected to a parent object store. This is usually a persistent store coordinator, but may be another managed object context. When you fetch objects, the context asks its parent object store to return those objects that match the fetch request. Changes that you make to managed objects are not committed to the parent store until you save the context.
In some applications, you may have just a single context. In others, however, you might have more than one. You might want to maintain discrete sets of managed objects and edits to those objects; or you might want to perform a background operation using one context while allowing the user to interact with objects in another.
Persistent Store Coordinator
A persistent store coordinator associates persistent object stores and a managed object model, and presents a facade to managed object contexts such that a group of persistent stores appears as a single aggregate store. A persistent store coordinator is an instance of NSPersistentStoreCoordinator. It has a reference to a managed object model that describes the entities in the store or stores it manages.
Fetch Request
A fetch request tells a managed object context the entity of the managed objects that you want to fetch; optionally, it specifies other aspects such as constraints on the values the objects' properties must have and the order you want the objects returned in. A fetch request is an instance of NSFetchRequest. The entity it specifies is represented by an instance of NSEntityDescription; any constraints are represented by an NSPredicate object, and the ordering by an array of one or more instances of NSSortDescriptor. These are akin to the table name, WHERE clause, and ORDER BY clauses of a database SELECT statement respectively.

Persistent Store
A persistent store is a repository in which managed objects may be stored. You can think of a persistent store as a database data file where individual records each hold the last-saved values of a managed object. Core Data offers three native file types for a persistent store: binary, XML, and SQLite. You can implement your own store type if you want Core Data to interoperate with a custom file format or server. Core Data also provides an in-memory store that lasts no longer than the lifetime of a process.

Managed Object Model 
A managed object model is a set of objects that together form a blueprint describing the managed objects you use in your application. A model allows Core Data to map from records in a persistent store to managed objects that you use in your application. It is a collection of entity description objects (instances of NSEntityDescription). An entity description describes an entity (which you can think of as a table in a database) in terms of its name, the name of the class used to represent the entity in your application, and what properties (attributes and relationships) it has.

Persistent Object Store
A persistent object store maps between objects in your application and records in a persistent store. There are different classes of persistent object store for the different file types that Core Data supports. You can also implement your own if you want to support a custom file type.
Mapping Model
A Core Data mapping model describes the transformations that are required to migrate data described by a source managed object model to the schema described by a destination model. When you make a new version of a managed object model, you need to migrate persistent stores from the old schema to the new.

Summary of Concurrency Programming Guide
There needs to be a way for applications to take advantage of a variable number of computer cores. The amount of work performed by a single application also needs to be able to scale dynamically to accommodate changing system conditions. And the solution has to be simple enough so as to not increase the amount of work needed to take advantage of those cores.

The Move Away from Threads:
Instead of relying on threads, Mac OS X and iOS take an asynchronous design approach to solving the concurrency problem. In Mac OS X and iOS allows you to perform any task asynchronously without having to manage the threads yourself.

One of the technologies for starting tasks asynchronously is Grand Central Dispatch (GCD). This technology takes the thread management code you would normally write in your own applications and moves that code down to the system level. All you have to do is define the tasks you want to exectute and add them to an appropriate dispatch queue. GCD takes care of creating the needed threads and of scheduling tasks to run on those threads. Because the thread management is now part of the system, GCD provides a holistic approach to task management and execution, providing better efficiency than traditional threads.

Operation queues are Objective-C objects that act very much like dispatch queues. You define the tasks you want to execute and then add them to an operation queue, which handles the scheduling and execution of those tasks. Like GCD, operation queues handle all of the thread management for you, ensuring that tasks are executed as quickly and efficiently as possible on the system.

Dispatch queues are a C-based mechanism for executing custom tasks. A dispatch queue executes tasks either serially or concurrently but always in a first-in, first-out order.

Dispatch queues have other benefits:
● They provide a straightforward and simple programming interface.
● They offer automatic and holistic thread pool management.
● They provide the speed of tuned assembly.
● They are much more memory efficient (because thread stacks do not linger in application memory).
● They do not trap to the kernel under load.
● The asynchronous dispatching of tasks to a dispatch queue cannot deadlock the queue.
● They scale gracefully under contention.
● Serial dispatch queues offer a more efficient alternative to locks and other synchronization primitives.

The tasks you submit to a dispatch queue must be encapsulated inside either a function or a block object. Block objects are a C language feature introduced in Mac OS X v 10.6 and iOS 4.0 that are similar to function pointers conceptually, but have some addition benefits.

Dispatch sources are a C-based mechanism for processing specific types of system events asynchronously. A dispatch source encapsulates information about particular type of system event and submits a specific block object or function to a dispatch queue whenever the event occurs.

An operation queue is the Cocoa equivalent of a concurrent dispatch queue and is implemented by the NSOperationQueue class. Whereas dispatch queues always execute tasks first-in, first-out order, operation queues take other factors into account when determining the execution order of tasks.

You can use dispatch sources to monitor the following types of events:

● Timers
● Signal handlers
● Descriptor-related events
● Process-related events
● Mach port events
● Custom events that you trigger

Before you even consider redesigning your code to support concurrency, you should ask yourself whether doing so is necessary. Concurrency can improve the responsiveness of your code by ensuring that your main thread is free to respond to user events. It can even improve the efficiency of your code by leveraging more cores to do more work in the same amount of time. However, it also adds overhead and increases the overall complexity of your code, making it harder to write and debug your code. 

Tips for Improving Efficiency:

● Consider computing values directly within your task if memory usage is a factor.
● Identify serial tasks early and do what you can to make them more concurrent.
● Avoid using locks. 
● Rely on the system frameworks whenever possible.

Core Data Programming Guide

Summary of Core Data Programming Guide
1. There are several situations in which performing operating with Core Data on a background thread or thread queues beneficial, in particular if you want to ensure that your application's user interface remain responsive while Core Data is undertaking a long-running task.

The pattern recommended for concurrent programming with Core Data is thread confinement: each thread must have its own entirely private managed object context.

There are two possible ways to adopt the pattern:

1. Create a separate managed object context for each thread and share a single persistent store coordinator.

2. Create a separate managed object context and persistent store coordinator for each thread.

This approach provides for greater concurrency at the expense of greater complexity (particular if you need to communicate changes between different contexts) and increase memory usage.

Threaded Core Data
Note: You can use threads, serial operations queues, or dispatch queues for concurrency. For the sake of conciseness, this article uses "thread" throughout to refer to refer to any to these.

  • Blocks simplify function callbacks. 
  • * is a pointer to a function. i.e. int (*cmpr)(int, int)
  • ^ is a pointer to a block. i.e. int(^cmpr)(int, int)
  • A block is a chunk of executable code. The caret introduces a block literal and the curly braces enclose statements that make up the body of the block. The most common way to use a block is to pass it a method that in turn calls the block. 
  • In practice, blocks are most useful when you pass them as parameters to methods that in turn call the block. 
  • In practice, it's more convenient to use inline blocks rather than assigning the block to a typed variable and then passing it to the method.
Great Objective-C Programming Resources Here:

Programming Blocks and Uses for Blocks in C/Objective-C

Example Code:

No comments :