iOS Interview Questions Part 5: Core Data 📗

Chetan Aggarwal
12 min readFeb 26, 2018

--

Main Queue Context is the application’s Single Source Of Truth. Marcus Zarra.

Time to dig in Core Data. If you have missed the previous one Part 4: UIKit, do check it out. Now lets get started!!! 💾 📀

Q: Can Persistent Store Coordinator have multiple Persistent Store?

Core Data Stack

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. It has a reference to a managed object model that describes the entities in the store or stores it manages.

In many applications you just have a single store, but in complex applications there may be several, each potentially containing different entities.

Q: Why we need multiple Persistent Store?

  • App has a fixed data set that is included as part of the bundle
  • Some of the data, app handles is sensitive information that we don’t wish to be persisted on disk
  • Have different storage requirements for different entities

You may have dealt with the first requirement by copying a file from your bundle into a writable location and using it as the base of your entire data store. You may have dealt with the second by manually deleting objects. A separate persistent store is a much better solution in both cases. Each persistent store has its own characteristics — it can be read-only, stored as binary or SQLite or in-memory (on OS X, an XML backing store is also available), or your own implementation of an NSIncrementalStore. It is possible to store different parts of your model in different persistent stores to take advantage of this flexibility.

Q: How we can add multiple Persistent Store?

With the help of Configuration in Managed Object Model we can achieve this. We can create multiple configurations and assign it to different persistence store.

We want one configuration per store, and each entity should be added to one configuration only (in addition to the default configuration). It is possible to have entities in multiple configurations, but in that case you have to manually assign each object to a store.

By creating one configuration per store and assigning each entity to a single configuration, we’ve enabled the core data frameworks to direct entities to different stores without needing any further interaction.

Q: Can we have relationship between entities of differenct Persistent store?

You must be careful not to create relationships from instances in one persistent store to instances in another, as this is not supported by Core Data. If you need to create a relationship between entities in different stores, you typically use fetched properties.

Q: How many Managed Object Model, a Persistent Store Coordinator can have?

We can have only one Persistent Store Coordinator for each model.

Q: Type of persistence store?

Apple Docs

Q: What are the Limitations of Persistent Store Security ?

Apple Docs says: Core Data makes no guarantees regarding the security of persistent stores from untrusted sources (as opposed to stores generated internally) and cannot detect whether files have been maliciously modified. The SQLite store offers slightly better security than the XML and binary stores, but it should not be considered inherently secure. It is possible for data archived in the metadata to be tampered with independently of the store data. To ensure data security, use a technology such as an encrypted disk image.

Q: What are Concurrency type in Core Data?

There are Two concurrency patterns — NSMainQueueConcurrencyType and NSPrivateQueueConcurrencyType.

NSMainQueueConcurrencyType is specifically used with your application interface and can only be used on the main queue of an application.

The NSPrivateQueueConcurrencyType configuration creates its own queue upon initialisation and can be used only on that queue. Because the queue is private and internal to the NSManagedObjectContext instance, it can only be accessed through the performBlock: and the performBlockAndWait: methods.

When you are using an NSPersistentContainer, the viewContext property is configured as a NSMainQueueConcurrencyType context and the contexts associated with performBackgroundTask: and newBackgroundContext are configured as NSPrivateQueueConcurrencyType.

Q: Is CoreData equals to SQLite or some wrapper?

No, Core Data is a framework for managing an object graph. SQLite is a relational database. SQLite is a database while Core Data is not. Core Data can use SQLite as its persistent store, but the framework itself is not a database.

Q: How to pass Manage Object between Managed Object Context on different queue?

We cannot pass them, since Managed Objects instances are not thread safe and are not intended to be passed between queues. Doing so can result in corruption of the data and termination of the application. When it is necessary to hand off a managed object reference from one queue to another, it must be done through NSManagedObjectID instances. You retrieve the managed object ID of a managed object by calling the objectID method on the NSManagedObject instance.

Q: How Core Data behave with multi threading?

Core Data expects to be run on a single thread. Some basic rules for accessing Core Data in a multithreaded application:

  • NSManagedObject instances should never be passed from one thread to another. If you need to pass a managed object from one thread to another, you use a managed object's objectID property.
  • You should never share managed object contexts between threads. This is a hard rule you shouldn’t break.
  • Even though the NSPersistentStoreCoordinator class isn't thread safe either, the class knows how to lock itself if multiple managed object contexts request access, even if these managed object contexts live and operate on different threads.

Q: What is lazy loading, how does this relate to core data ?

When you execute a fetch command, Core Data fetches only instances of the entity you specify. In some situations (see Faulting Limits the Size of the Object Graph), the destination of a relationship is represented by a fault. Core Data automatically resolves (fires) the fault when you access data in the fault. This lazy loading of the related objects is much better for memory use, and much faster for fetching objects related to rarely used (or very large) objects. It can also, however, lead to a situation where Core Data executes separate fetch requests for a number of individual objects, which incurs a comparatively high overhead. For example, consider this model:

You might fetch a number of Employees and ask each in turn for their Department’s name, as shown in the following code fragment.

let employeesFetch = NSFetchRequest<EmployeeMO>(entityName: “Employee”)
do {
let fetchedEmployees = try moc.executeFetchRequest(employeeFetch)
for employee in fetchedEmployees {
print(“\(employee.name) -> \(employee.department!.name)”)
}
} catch {
fatalError(“Failed to fetch employees: \(error)”)
}

This code might lead to the following behavior:

Jack -> Sales [fault fires]
Jill -> Marketing [fault fires]
Benjy -> Sales
Gillian -> Sales
Hector -> Engineering [fault fires]
Michelle -> Marketing

Here, there are four round trips to the persistent store (one for the original fetch of Employees and three for individual Departments). These trips represent a considerable overhead on top of the minimum two trips to the persistent store.

There are two techniques you can use to mitigate this effect — batch faulting and prefetching.

Source: Apple Docs.

Q: How to read only a few properties of an entity ?

This can be achieved by propertiesToFetch instance property of Core Data.

Q: How to Fetch Distinct Values ?

Sometimes you don’t want to fetch actual managed objects; instead, you just want to retrieve — for example — the largest or smallest value of a particular attribute, or distinct values for a given attribute. On iOS, you can use NSExpressionDescription objects to specify a function for a fetch request, and setReturnsDistinctResults: to return unique values.

Apple Docs.

Q: What is a fetchedResultController ?

A controller that you use to manage the results of a Core Data fetch request and display data to the user.

Apple Doc.

Q: How to synchronize contexts ?

Your managed object context objects should listen for the NSManagedObjectContextDidSaveNotification to be notified when any context performs a save. When that occurs, you need each managed object context to call mergeChangesFromContextDidSaveNotification: with the notification that is posted from saving. This will merge all saved changed from one MOC to all of your others.

Check this out.

Q: What is NSFetchRequest ?

NSFetchRequest is the class responsible for fetching from Core Data. Fetch requests are both powerful and flexible. You can use fetch requests to fetch a set of objects meeting the provided criteria, individual values and more.

Q: Explain NSPersistentContainer ?

A container that encapsulates the Core Data stack in your app. It simplifies the creation and management of the Core Data stack by handling the creation of the managed object model (NSManagedObjectModel), persistent store coordinator (NSPersistentStoreCoordinator), and the managed object context (NSManagedObjectContext).

Q: Explain NSFetchedResultsController ?

NSFetchedResultsController is a controller, but it’s not a view controller. It has no user interface. Its purpose is to make developer’s lives easier by abstracting away much of the code needed to synchronize a table view with a data source backed by Core Data.

Set up an NSFetchedResultsController correctly, and your table will mimic its data source without you have to write more than a few lines of code.

Q: How to store other data type in core data ?

You can encrypt individual properties in your Core Data model entities by making them transformable properties, then creating an NSValueTransformer subclass which will encrypt and decrypt the data for that property.

Transformable properties like this are very easy to use, because you read and write to them as normal, while the encryption / decryption goes on behind the scenes.

Q: What are SQLite limits ?

  • We need to define the relations between the tables. Define the schema of all the tables.
  • We have to manually write queries to fetch data.
  • We need to query results and then map those to models.
  • Queries are very fast.

Q: What is Realm benefits ?

  • An open-source database framework.
  • Implemented from scratch.
  • Zero copy object store.
  • Fast.

Q: What are delete rules in Core data?

A relationship’s delete rule specifies what should happen if an attempt is made to delete the source object.

Deny: If there is at least one object at the relationship destination (employees), do not delete the source object (department). For example, if you want to remove a department, you must ensure that all the employees in that department are first transferred elsewhere; otherwise, the department cannot be deleted.

Nullify: Remove the relationship between the objects, but do not delete either object. This only makes sense if the department relationship for an employee is optional, or if you ensure that you set a new department for each of the employees before the next save operation.

Cascade: Delete the objects at the destination of the relationship when you delete the source. For example, if you delete a department, fire all the employees in that department at the same time.

No Action: Do nothing to the object at the destination of the relationship. For example, if you delete a department, leave all the employees as they are, even if they still believe they belong to that department.

Q: How to do Core Data Migrations?

A persistent store is tied to a particular version of the data model. It keeps a reference to the identifier of the data model. If the data model changes, we need to tell Core Data how to migrate the data of the persistent store to the new data model version.

Q: Lightweight VS Heavy migrations ?

Lightweight migrations: require very little work from our end. It is recommended to choose a lightweight migration over a heavy migration due too substantially low cost. It is less powerful than heavy migrations since it entertain less changes. For example, a lightweight migration lets you add or rename attributes and entities, but you cannot modify the type of an attribute or the relationships between existing entities.

To Support lightweight migrations to the CoreDataManager class, we need to make a minor change. we pass in a dictionary of options with two keys to addPersistentStore(ofType:configurationName:at:options:):

  • NSInferMappingModelAutomaticallyOption: If the value of this key is set to true, Core Data attempts to infer the mapping model for the migration based on the data model versions of the data model.
  • NSMigratePersistentStoresAutomaticallyOption: By setting the value of this key to true, we tell Core Data to automatically perform a migration if it detects an incompatibility.

Heavy migrations are powerful, but that power comes at a cost. It require a lot of work and testing to make sure the migration completes successfully and, more importantly, without data loss.It is used when we make changes that Core Data cannot automatically infer for us by comparing versions of the data model. Core Data will then need a mapping model to understand how the versions of the data model relate to one another. To implement it we need to create custom mapping model.

Q: What is the best way to do multi threading in Core Data ?

The best way, according to Marcus Zarra, is not the fastest, but it is by far the easiest and most maintainable. It relies on API’s that Apple introduced with iOS 6, which allows to define child MOCs and also specify a MOC’s concurrency type. The design that Zarra presents is based on how NSManagedDocument works and uses:

  • A single persistent store coordinator.
  • A private MOC which is the only one that actually accesses the PSC.
  • A main MOC associated to the UI that is a child of the private MOC.
  • Multiple child MOCs that are specific to secondary threads.
Source: Infoq

The nice thing about this design is that all changes in a child MOC will automatically propagate to its parent MOC, thus doing away with the need for merging.

The main drawback of this design is its slowness, although only by a few percents, says Zarra. A tricky issue with it is that if too many async operations are carried through, there may be ripple effects on the UI, since its associated MOC will receive multiple changes in sequence that might not be coherent with one another. An important detail about this design is that it is best not to reuse child MOCs, which are cheap to create. On the other hand, long-lived child MOCs should be manually kept in sync with the main MOC, since changes are propagated only from child MOCs to their parent and not the other way round.

Q: What is ideal Core data Stack ?

Ideal Core Data Stack:

Core Data Stack

The managed object context linked to the persistent store coordinator isn’t associated with the main thread. Instead, it lives and operates on a background thread. When the private managed object context saves its changes, the write operation is performed on that background thread.

The private managed object context has a child managed object context, which serves as the main managed object context of the application. The concept of parent and child managed object contexts is key in this scenario.

In most scenarios, a managed object context is associated with a persistent store coordinator. When such a managed object context saves its changes, it pushes them to the persistent store coordinator which further pushes the changes to the persistent store, a SQLite database for example.

A child managed object context doesn’t have a reference to a persistent store coordinator. Instead, it keeps a reference to another managed object context, a parent managed object context. When a child managed object context saves its changes, it pushes them to the parent managed object context. In other words, when a child managed object context saves its changes, the persistent store coordinator is unaware of the save operation. It is only when the parent managed object context performs a save operation that the changes are pushed to the persistent store coordinator and subsequently to the persistent store.

Because no write operations are performed when a child managed object context saves its changes, the thread on which the operation is performed isn’t blocked by a write operation. That is why the main managed object context of the application is the child managed object context of a managed object context that operates on a background thread.

Thank you for reading 🧑🏻‍💻

Be sure to clap 👏🏼 and follow 🚶🏻‍♂️

Questions❓Feedback 📫 — please drop you comments 💭

If you like this article, feel free to share it with your friends 📨

Follow me: Linkedin | X(Twitter) | Github 🤝🏼

--

--

Responses (3)