Quantcast
Channel: Envato Tuts+ Code - Mobile Development
Viewing all 1836 articles
Browse latest View live

Managing Private Pods With CocoaPods

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-25137

Most of us use open source libraries on a daily basis. With CocoaPods, managing dependencies in a Cocoa project is virtually painless. In some situations, however, a project depends on a library or framework that is closed source, not publicly available. You can still use CocoaPods in such situations. CocoaPods works great for both closed and open source libraries.

To make this work, you need to create a private specs repository. Once you've set one up, you don't even notice the difference between public and private dependencies, because CocoaPods takes care of the nitty gritty details for you. In this tutorial, you'll learn how to set up a private specs repository to manage private libraries.

1. Introduction

If you've only used CocoaPods for managing public pods, then you may not know that CocoaPods can handle multiple specs repositories. If no specs repository is specified in the project's Podfile, CocoaPods falls back to the master specs repository.

If you specify a dependency in your project's Podfile, CocoaPods searches by default in the master specs repository. Take a look at the following two examples. Both examples generate the same result. The difference is that we explicitly specify the source of the specs repository in the second Podfile.

If you've never created or contributed to a pod, then you may be wondering what a specs repository is? A specs repository is nothing more than a repository that contains a collection of pod specifications, files with a .podspec or .podspec.json extension.

As the name suggests, the specs repository doesn't contain the source files for the pods. You can browse the CocoaPods master specs repository on GitHub. If CocoaPods is installed on your machine, however, then a copy of the master specs repository is already present on your machine.

During the installation process, CocoaPods clones the master specs repository to your home folder. You can find it at ~/.cocoapods/repos/master.

2. Creating a Specs Repository

I usually use GitHub for hosting Git repositories so that's the platform I'll be using for this tutorial. It doesn't matter where you host the specs repository as long as it's accessible by everyone on your team.

You can create a free GitHub account to follow along, but keep in mind that you can only create public repositories with a free account. If you have a library that you want to open source, then it's recommended to publish the pod spec to the master specs repository, which is managed by the CocoaPods team. You don't gain anything by creating a separate public specs repository.

The first thing we need to do is create a private repository on GitHub for the private specs that we're going to add later. I've named mine tutspods. GitHub will suggest to clone the repository to your machine, but that isn't necessary. CocoaPods will clone the specs repository for you once you've added it to CocoaPods. That's what we'll do in the next step.

3. Adding the Repository to CocoaPods

The next step is telling CocoaPods about the specs repository we just created. You do this by executing the following command from the command line.

You may notice that the command is similar to adding a remote to a Git repository. Make sure that you remember the name you give the specs repository, tutspods in this case. We'll be needing it a bit later.

Whenever you add a specs repository, CocoaPods clones the repository to your machine. You can verify this by navigating to ~/.cocoapods/repos. The directory should now contain two specs repositories, the master specs repository and the tutspods specs repository. Apart from a .git folder, the tutspods directory is empty since we haven't added any specs yet.

4. Creating a Private Pod

Not too long ago, Andy Obusek wrote a great tutorial about creating your first pod. If you've never created a pod—public or private—then I recommend reading Andy's article first. I won't repeat what Andy wrote in this tutorial.

As an example, I've created a tiny library, TSPTableView, which contains a special UITableView subclass. To create a pod spec for the library, run the following command in the root of the library.

By running the above command, CocoaPods creates a file named TSPTableView.podspec. Open the file in a text editor and fill out the required fields. When you're done, run pod spec lint to validate the pod spec. If the pod spec doesn't pass validation, you won't be able to push the spec to the specs repository.

5. Pushing the Spec to the Specs Repository

If the pod spec passes validation, it's time to push it to the private specs repository you created earlier. You do this by executing the following command from the command line.

It's key that you use the same name you previously used to add the private specs repository to CocoaPods. The last argument is the path to the pod spec you're pushing to the specs repository.

6. Using the Private Pod

We can now use TSPTableView in a new project. Create a project in Xcode and add a Podfile at the root of the project by running pod init from the command line. This is what the Podfile could look like when you're finished.

Run pod install from the command line to install the dependencies listed in the project's Podfile. Did you also run into a problem? I see the following error.

The output tells us that CocoaPods first updates the local specs repositories. This means that the repositories in the ~/.cocoapods/repos directory are updated, pulling in any changes.

CocoaPods does this to ensure that it has the latest version of the specs that are stored in the repositories. If we take a look at the ~/.cocoapods/repos/tutspods directory, we can see that the pod spec for the TSPTableView pod is there like we expected. Why can't CocoaPods find the pod spec for TSPTableView?

The solution is simple. At the top of the Podfile, we need to specify which specs repositories CocoaPods searches to resolve the dependencies listed in the project's Podfile. This is what the Podfile should look like to remedy our issue.

Run pod install one more time to install the dependencies listed in the project's Podfile. The command should now finish successfully as shown below. I'm currently using CocoaPods 0.38.2 so the output may be slightly different if you're using a different version of CocoaPods.

Note that the order in which you list the specs repositories in the Podfile is important. For example, if you've forked a public pod, modified it, and created a private pod for the fork with the same name, you will have a naming collision.

This isn't a problem for CocoaPods, because it will use the first pod it can find with the specified name. In general, you should put the private specs repository at the top to make sure CocoaPods searches that one first, falling back to the public specs repository if necessary.

Conclusion

CocoaPods is a great tool that I wouldn't be able to work without. I hope this tutorial has shown you how powerful CocoaPods is and how easy it is to create and manage private pods with CocoaPods.

2015-10-28T18:33:12.163Z2015-10-28T18:33:12.163ZBart Jacobs

What Is a Core Data Fault?

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-25157

Faults are an essential component of Core Data. Even though the term sounds ominous, faults are inherent to the life cycle of a Core Data record. In this tutorial, you'll learn what faults are, how to handle them, and how to debug issues related to faulting.

Prerequisites

Core Data is an advanced topic so I'm going to assume that you're already familiar with Xcode and iOS development. Even though I'll be using the Swift programming language for this tutorial, everything in this tutorial is also applicable to Objective-C.

Wat Is a Fault?

Core Data is very good at what it does thanks to the hard work of Apple's Core Data team. Core Data is highly optimized to keep its memory footprint low without sacrificing performance. Faulting is one of the techniques Core Data uses to consume as little memory as possible.

Faulting isn't unique to Core Data. A similar technique is used in many other frameworks, such as Ember and Ruby on Rails. The idea is simple, only load data when it's needed. To make faulting work, Core Data does a bit of magic under the hood by creating custom subclasses at compile time that represent the faults. Let's see how this works with an example.

I've created a simple sample application to work with. Download the Xcode project from GitHub and open it in Xcode. The project uses Swift 2.1, which means that you need Xcode 7.1 or higher to satisfy the compiler.

The data model contains two entities, List and Item. A list can have zero or more items and an item is always linked to a list. It's a classic example of a one-to-many relationship.

Data Model

Run the application and populate the persistent store, a SQLite database, with some data by creating a few lists and items. Quit the application when you're finished.

Firing Faults

You should now have an application with some data. Let's see how faults work in practice by adding some print statements. Open ListsViewController.swift and look for prepareForSegue(_:sender:). In this method, we fetch the list the user has selected in the table view. Uncomment the print statements in prepareForSegue(_:sender:) as shown in the implementation below.

Run the application and tap one of the lists in the lists view controller. The example is only interesting if you tap a list that has one or more items associated with it. Let's inspect the output of the print statements step by step.

The first thing to note is the class name, Faulting.List. This is what we expect since the module is named Faulting and the class is named List. In Swift, the complete class name of a class is made up of the module's name and the class's name.

The output in the console also shows the name of the entity, List, and a dictionary of data. The name attribute is set to List 6 while the items attribute is marked as a relationship fault. This is the first type of fault in Core Data. Core Data understands that there's no need to load the relationship. Instead, it marks the relationship as a fault. The second print statement confirms this as you can see below.

The third print statement, however, is more interesting. It prints the number of items associated with the list.

Core Data can only do this by firing the relationship fault. It asks the persistent store for the items associated with the list. This, however, is only part of the story as illustrated by the fourth print statement.

We no longer see a relationship fault, but we still see a fault. What is that about? Core Data can only give us the number of items for the list by firing or resolving the relationship fault. However, this doesn't mean that Core Data resolves the items of the relationship. The output in the console confirms this.

We can see that the records for the items are there, including the identifier Core Data uses internally. The data dictionary, however, is marked as a fault. Again, Core Data only gives us what we ask for. Fortunately, the nitty gritty details are handled by Core Data.

Let's dig a little deeper and fetch one of the items from the list. We do this by calling anyObject() on the items object. We print the resulting item in the fifth print statement.

The output shouldn't surprise you. The output confirms that we're dealing with an Item entity. Unsurprisingly, the data dictionary is still marked as a fault. In the sixth print statement, we print the name attribute of the item.

Because we ask for the value of an attribute of the record, Core Data fires the fault to give us that value. It fetches the data for the item and populates the data dictionary. The seventh print statement confirms these findings.

The data dictionary contains the name attribute as well as the list relationship. The eighth and last print statement shows that the relationship fault of the list object is resolved.

Unable to Fulfill a Fault

I decided to write this article to explain a problem many developers using Core Data run into at one point or another, firing a fault that cannot be fulfilled. The problem is simple. Let's assume you have a list with a number of items and, at some point, the user deletes the list. What happens to the items of that list? What happens if Core Data attempts to fire the list relationship of one of the items that belonged to that list? Let's find out.

Let's revisit the project you've downloaded from GitHub. Open Faulting.xcdatamodeld, the project's data model. Select the items relationship of the List entity and open the Data Model Inspector on the right. What's of interest to us is the Delete Rule, which is currently set to Cascade. This means that every item of the list is deleted when the list is deleted. This makes sense since we don't want to have abandoned items that aren't associated with a list.

Delete Rule Cascade

Select the list relationship of the Item entity and open the Data Model Inspector. The Delete Rule of this relationship is set to Nullify. This means that the destination of the relationship, the list object, is set to null when the destination record, the item, is deleted. This is the default delete rule for a relationship.

Delete Rule Nullify

Run the application, create a few lists and items, and tap the Items button at the top left to show every item you've created. Tap Cancel in the top left, delete one of the lists, and tap the Items button again to see what's changed. As expected, the items associated with the deleted list have also been deleted by Core Data. This is no magic. Core Data simply executes the delete rules we defined in the data model.

We can conclude that the relationships are set up correctly for this type of application. But what happens if we don't configure the delete rules correctly. Open the data model and set the delete rule of both relationships, items and list, to No Action. Launch the application again and create a few lists and items. If you delete a list and tap the Items button in the top left to see every item in the persistent store, the items associated with the deleted list should still be there. They weren't deleted even though the list to which they belong has been removed.

Tap one of the lists and see what happens. If you are running the application on iOS 8, then the application will crash due to an uncaught exception. If you are running the application on iOS 9, then you will only see an error in the console. Stop scratching your head and let's figure this out together.

Object Inaccessible

Even though the application crashes on iOS 8, the output we see in the console is clear and to the point.

The first thing to notice is that the application crashed due to an uncaught exception. What's more important for our discussion, however, is the reason the exception was thrown. Core Data tells us that it was unable to fulfill a fault for a relationship. The relationship Core Data refers to is the list relationship of the item we tapped in the table view.

If you look at the implementation of tableView(tableView:didSelectRowAtIndexPath:), then you'll understand why Core Data threw an exception. In this method, we fetch the item the user tapped and print the name of the list to the console.

Because the list relationship is a fault, Core Data needs to fire the fault to resolve it. This means that Core Data asks the persistent store for the list record. The problem is that the record is no longer in the persistent store, which is why an exception was thrown.

Delete Inaccessible Faults

Up until iOS 9, this has always been the default behavior. As of iOS 9, Core Data no longer throws an exception. Instead, it logs a cryptic message to the console. Despite the message being unclear, it still contains the reason of the problem.

The gist is that Core Data no longer throws an exception when it is unable to fulfill a fault. The somewhat good news is that your application no longer crashes if you don't catch the exception.

The reason for not throwing an exception on iOS 9 is due to the introduction of a new property, shouldDeleteInaccessibleFaults, and a new method, shouldHandleInaccessibleFault(_:forObjectID:triggeredByProperty:), on the NSManagedObjectContext class. I won't cover these additions in this tutorial.

What you need to remember is that iOS 9, by default, sets the shouldDeleteInaccessibleFaults to true. This means that an inaccessible managed object is marked as deleted and its properties are zeroed out. If shouldDeleteInaccessibleFaults is set to false, Core Data reverts to the old behavior by throwing an exception.

Of course, the shouldDeleteInaccessibleFaults property goes hand in hand with shouldHandleInaccessibleFault(_:forObjectID:triggeredByProperty:). If you override this method, you can handle inaccessible objects more elegantly.

Handling Faults

When you encounter an exception due to Core Data not being able to fulfill a fault, you may think Core Data is being a bit aggressive. This reaction is quite common for people new to the framework. The truth is that the developer is at fault. Core Data was designed with a specific set of goals in mind and faulting is an essential component to realize these goals.

Despite their name, faults should always be fulfillable. If a fault cannot be fulfilled, then that means the data model isn't set up correctly or the application isn't respecting the rules set out by the Core Data framework.

In the Core Data Programming Guide, Apple lists a number of scenarios that may lead to faults that can no longer be fulfilled. The most common scenarios are incorrectly configured relationships (delete rules) and deleting a managed object while the application still has a strong reference to that managed object.

Be warned, there are other possible scenarios. From my experience, developers often run into similar issues due to a problem with the Core Data stack. For example, if the application keeps a strong reference to a managed object and, at  some point, deallocates the managed object context of that managed object, then Core Data is no longer able to fulfill any faults for that managed object. I hope you understand that this shouldn't happen if you play by Core Data's rules.

Conclusion

Core Data faults are incredibly useful and a key component of Apple's persistence framework. I hope this article has taught you how to deal with faults and where to look for if you run into faults that cannot be fulfilled. If you have any questions, feel free to leave them in the comments below or reach out to me on Twitter.

2015-10-30T17:45:49.000Z2015-10-30T17:45:49.000ZBart Jacobs

Using Gradle Build Variants

$
0
0

Introduction

One of the key features of Android Studio is the integration of Gradle as an Android build system. While the overall purpose of a build system is to take source code and construct an installable file for your users, an APK in the case of Android, Gradle provides a lot more functionality.

Gradle handles dependency management, such as local JAR files, native .so files and libraries hosted on Maven. It also allows for easy configuration of project properties and it enables developers to create different versions of their applications in a fairly simple way. The last item, known as build variants, is what you will learn about in this article.

1. What Are Build Variants?

Build variants are specific builds that you can produce from Gradle, based around shared core source code. While a standard app may have a debug and release build type, you can expand on this by adding flavor dimensions.

Flavor dimensions allow you to use the folder structure of your project to change how individual builds look and act for your users. This enables developers to easily produce multiple similar apps with different styles and configuration.

2. Setting Up Build Variants in Gradle

You can get started by going into your project's build.gradle file and adding a flavorDimensions item inside of the android build node.

This defines what dimensions your build variants can use. Each build that you produce needs to have a product flavor from each of the dimensions. This means that if you only need one dimension for your apps, which is a common scenario, then you can change your flavorDimensions line to only define one dimension.

Below the flavorDimensions definition, you can define the productFlavors. For this example, we will keep things simple and define two flavors per dimension.

Each build that you create will need a unique applicationId in order to differentiate it from the other builds. Since any application that you build will have at least one flavor from each dimension, you only need to define the applicationId in each node for one dimension.

Now that you have defined everything for your build variants in build.gradle, you can open the Build Variants panel in the lower left corner of Android Studio to see what variants are available to build.

You'll notice that each flavor you add grows the number of variants exponentially. Also note that buildTypes of debug and release are thrown into the matrix of dimensions.

Build Variants in Android Studio

3. Using the Project Structure

While you can now install different versions of your app, there's nothing distinguishing them from one another. This is where you really get to use the Gradle build system to your advantage.

Gradle uses the folder structure of a project to determine what files will be used for compiling an app. In your project structure under app/src/, you'll see the main directory. This is where all of your Java source and core resources live. You can add additional directories alongside main to reflect the product flavors of your apps in order to add customized resources for each build variant.

Any resource that exist in a product flavor that is also defined in main will automatically take precedence.

Add Resources for Product Flavors

We can view that in action by looking at main/res/values/colors.xml. If your project doesn't already have a colorPrimary value defined, go ahead and define it. If you started with a new empty project to follow along with this article, then you should see a predefined value of #3F51B5. Running the application should show the colorPrimary value as the color for the Toolbar in the app.

Using a Build Variant

If you create a new colors.xml file under green/src/values/, you can override the colorPrimary attribute with a different value. In this case, let's use #00FF00.

When your file is created and the color is set, go back into the Build Variants panel in Android Studio and select the oneGreenDebug build variant. You can then compile and run that variant of the app.

Building the onGreeDebug Build Variant

Even though the green variant has colored the toolbar green, the other properties from main aren't overridden. This allows you to set up your common properties in main and only change what should be different.

Not only does this work for colors, but you can change anything that exists within the resources folders, such as strings, styles, dimensions, and integers. When combined with annotated resource folders, such as values-xhdpi for higher pixel density devices, you'll be able to finely control what the user sees from your app in order to ensure they have the best experience possible.

As an added bonus, since you have different applicationId values set for each of the color dimensions, you can install multiple versions of the same app on a device.

Conclusion

Gradle is a powerful tool that not only constructs APKs, but allows you to have fine-grained control over customizing your builds. In this article you have learned how to create build variants of your application with different resources so that you can easily produce multiple similar apps in a fraction of the time it would take to build each individually.

While Gradle is still a fairly new build system, it has already demonstrated that it is an incredibly useful build system that every Android developer should be comfortable with.

2015-11-02T16:45:53.000Z2015-11-02T16:45:53.000ZPaul Trebilcox-Ruiz

Using Gradle Build Variants

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-25005

Introduction

One of the key features of Android Studio is the integration of Gradle as an Android build system. While the overall purpose of a build system is to take source code and construct an installable file for your users, an APK in the case of Android, Gradle provides a lot more functionality.

Gradle handles dependency management, such as local JAR files, native .so files and libraries hosted on Maven. It also allows for easy configuration of project properties and it enables developers to create different versions of their applications in a fairly simple way. The last item, known as build variants, is what you will learn about in this article.

1. What Are Build Variants?

Build variants are specific builds that you can produce from Gradle, based around shared core source code. While a standard app may have a debug and release build type, you can expand on this by adding flavor dimensions.

Flavor dimensions allow you to use the folder structure of your project to change how individual builds look and act for your users. This enables developers to easily produce multiple similar apps with different styles and configuration.

2. Setting Up Build Variants in Gradle

You can get started by going into your project's build.gradle file and adding a flavorDimensions item inside of the android build node.

This defines what dimensions your build variants can use. Each build that you produce needs to have a product flavor from each of the dimensions. This means that if you only need one dimension for your apps, which is a common scenario, then you can change your flavorDimensions line to only define one dimension.

Below the flavorDimensions definition, you can define the productFlavors. For this example, we will keep things simple and define two flavors per dimension.

Each build that you create will need a unique applicationId in order to differentiate it from the other builds. Since any application that you build will have at least one flavor from each dimension, you only need to define the applicationId in each node for one dimension.

Now that you have defined everything for your build variants in build.gradle, you can open the Build Variants panel in the lower left corner of Android Studio to see what variants are available to build.

You'll notice that each flavor you add grows the number of variants exponentially. Also note that buildTypes of debug and release are thrown into the matrix of dimensions.

Build Variants in Android Studio

3. Using the Project Structure

While you can now install different versions of your app, there's nothing distinguishing them from one another. This is where you really get to use the Gradle build system to your advantage.

Gradle uses the folder structure of a project to determine what files will be used for compiling an app. In your project structure under app/src/, you'll see the main directory. This is where all of your Java source and core resources live. You can add additional directories alongside main to reflect the product flavors of your apps in order to add customized resources for each build variant.

Any resource that exist in a product flavor that is also defined in main will automatically take precedence.

Add Resources for Product Flavors

We can view that in action by looking at main/res/values/colors.xml. If your project doesn't already have a colorPrimary value defined, go ahead and define it. If you started with a new empty project to follow along with this article, then you should see a predefined value of #3F51B5. Running the application should show the colorPrimary value as the color for the Toolbar in the app.

Using a Build Variant

If you create a new colors.xml file under green/src/values/, you can override the colorPrimary attribute with a different value. In this case, let's use #00FF00.

When your file is created and the color is set, go back into the Build Variants panel in Android Studio and select the oneGreenDebug build variant. You can then compile and run that variant of the app.

Building the onGreeDebug Build Variant

Even though the green variant has colored the toolbar green, the other properties from main aren't overridden. This allows you to set up your common properties in main and only change what should be different.

Not only does this work for colors, but you can change anything that exists within the resources folders, such as strings, styles, dimensions, and integers. When combined with annotated resource folders, such as values-xhdpi for higher pixel density devices, you'll be able to finely control what the user sees from your app in order to ensure they have the best experience possible.

As an added bonus, since you have different applicationId values set for each of the color dimensions, you can install multiple versions of the same app on a device.

Conclusion

Gradle is a powerful tool that not only constructs APKs, but allows you to have fine-grained control over customizing your builds. In this article you have learned how to create build variants of your application with different resources so that you can easily produce multiple similar apps in a fraction of the time it would take to build each individually.

While Gradle is still a fairly new build system, it has already demonstrated that it is an incredibly useful build system that every Android developer should be comfortable with.

2015-11-02T16:45:53.000Z2015-11-02T16:45:53.000ZPaul Trebilcox-Ruiz

Core Data and Swift: Core Data Stack

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-25065

Introduction

The Core Data framework has been around for many years. It's used in thousands of applications and by millions of people, both on iOS and OS X. Core Data is maintained by Apple and is very well documented. It's a mature framework that has proven it's value over and over.

Even though Core Data relies heavily on the Objective-C runtime and integrates neatly with the Core Foundation framework, you can easily use the framework in your Swift projects. The result is an easy to use framework for managing an object graph that is elegant to use and incredibly efficient in terms of memory usage.

1. Prerequisites

The Core Data framework isn't difficult per se, but if you're new to iOS or OS X development, then I recommend you first go through our series about iOS development. It teaches you the fundamentals of iOS development and, at the end of the series, you will have enough knowledge to take on more complex topics, such as Core Data.

As I said, Core Data isn't as complex or difficult to pick up as most developers think. However, I've learned that a solid foundation is critical to get up to speed with Core Data. You need to have a proper understanding of the Core Data API to avoid bad practices and make sure you don't run into problems using the framework.

Every component of the Core Data framework has a specific purpose and function. If you try to use Core Data in a way it wasn't designed for, you will inevitably end up struggling with the framework.

What I cover in this series on Core Data is applicable to iOS 7+ and OS X 10.10+, but the focus will be on iOS. In this series, I will work with Xcode 7.1 and Swift 2.1. If you prefer Objective-C, then I recommend reading my earlier series on the Core Data framework.

2. Learning Curve

The Core Data framework can seem daunting at first, but the API is intuitive and concise once you understand how the various pieces of the puzzle fit together. And that's exactly why most developers run into problems using the framework. They try to use Core Data before they've seen that proverbial puzzle, they don't know how the pieces of the puzzle fit together and relate to one another.

In this article, I will help you become familiar with the Core Data stack. Once you understand the key players of the Core Data stack, the framework will feel less daunting and you will even start to enjoy and appreciate the framework's well-crafted API.

In contrast to frameworks like UIKit, which you can use without understanding the framework in its entirety, Core Data requires a proper understanding of its building blocks. It's important to set aside some time to become familiar with the framework, which we'll do in this tutorial.

3. What Is Core Data?

Developers new to the Core Data framework often confuse it with and expect it to work as a database. If there's one thing I hope you'll remember from this series, it is that Core Data isn't a database and you shouldn't expect it to act like one.

What is Core Data if it isn't a database? Core Data is the model layer of your application in the broadest sense possible. It's the Model in the Model-View-Controller pattern that permeates the iOS SDK.

Core Data isn't the database of your application nor is it an API for persisting data to a database. Core Data is a framework that manages an object graph. It's as simple as that. Core Data can persist that object graph by writing it to disk, but that isn't the primary goal of the framework.

4. Core Data Stack

As I mentioned earlier, the Core Data stack is the heart of Core Data. It's a collection of objects that make Core Data tick. The key objects of the stack are the managed object model, the persistent store coordinator, and one or more managed object contexts. Let's start by taking a quick look at each component.

NSManagedObjectModel

The managed object model represents the data model of the application. Even though Core Data isn't a database, you can compare the managed object model to the schema of a database, that is, it contains information about the models or entities of the object graph, what attributes they have, and how they relate to one another.

The NSManagedObjectModel object knows about the data model by loading one or more data model files during its initialization. We'll take a look at how this works in a few moments.

NSPersistentStoreCoordinator

As its name indicates, the NSPersistentStoreCoordinator object persists data to disk and ensures the persistent store(s) and the data model are compatible. It mediates between the persistent store(s) and the managed object context(s) and also takes care of loading and caching data. That's right. Core Data has caching built in.

The persistent store coordinator is the conductor of the Core Data orchestra. Despite its important role in the Core Data stack, you will rarely interact with it directly.

NSManagedObjectContext

The NSManagedObjectContext object manages a collection of model objects, instances of the NSManagedObject class. It is possible for an application to have multiple managed object contexts. Each managed object context is backed by a persistent store coordinator.

You can see a managed object context as a workbench on which you work with your model objects. You load them, you manipulate them, and save them on that workbench. Loading and saving are mediated by the persistent store coordinator. You can have multiple workbenches, which is useful if your application is multithreaded, for example.

While a managed object model and persistent store coordinator can be shared across threads, managed object contexts should never be accessed from a thread different than the one they were created on. We'll discuss multithreading in more detail later in this series.

5. Exploring the Core Data Stack

Step 1: Project Setup

Let's explore the Core Data stack in more detail by taking a look at an example. Create a new project in Xcode 7 by selecting New > Project... from the File menu. Choose the Single View Application template from the list of iOS > Application templates on the left.

Project Setup

Name the project Core Data, set Language to SwiftDevices to iPhone, and check the checkbox labeled Use Core Data. Tell Xcode where you'd like to store the project files and click Create.

Project Configuration

Step 2: Overview

By default, Apple puts code related to Core Data in the application's delegate class, the AppDelegate class in our example. Open AppDelegate.swift and let's start exploring the implementation of the AppDelegate class.

At the top of AppDelegate.swift, you should see an import statement for the Core Data framework.

The AppDelegate class further contains four lazy stored properties:

  • applicationDocumentsDirectory of type NSURL
  • managedObjectModel of type NSManagedObjectModel
  • managedObjectContext of type NSManagedObjectContext
  • persistentStoreCoordinator of type NSPersistentStoreCoordinator

The first property, applicationDocumentsDirectory, is nothing more than a helper for accessing the application's Documents directory. The implementation is pretty simple as you can see below. The NSFileManager class is used to fetch the location of the application's Documents directory.

The remaining three lazy stored properties are more interesting and directly related to the Core Data framework. We're first going to explore the managedObjectContext property.

Step 3: Managed Object Context

The class you'll use most often, apart from NSManagedObject, when interacting with Core Data is NSManagedObjectContext.

Note that the NSManagedObjectContext object is instantiated and configured in a closure. In the closure, we first get a reference to the persistent store coordinator. We then instantiate the NSManagedObjectContext, passing in .MainQueueConcurrencyType as the first argument. You'll learn more about concurrency types later in this series. By passing in .MainQueueConcurrencyType, we indicate that the managed object context will do its work using the queue of the main thread.

Before we return the managed object context, we set the object's persistentStoreCoordinator property. Without a persistent store coordinator, a managed object context is useless. That wasn't too difficult. Was it?

In summary, the managed object context manages a collection of model objects, instances of the NSManagedObject class, and keeps a reference to a persistent store coordinator. Keep this in mind while reading the rest of this article.

Step 4: Persistent Store Coordinator

As we saw a moment ago, the persistentStoreCoordinator property is accessed during the configuration of the managed object context. Take a look at the implementation of the persistentStoreCoordinator property, but don't let it scare you. It's actually not that complicated.

You will almost always want to store Core Data's object graph to disk and Apple's implementation of the persistentStoreCoordinator property uses a SQLite database to accomplish this. This is a common scenario for Core Data applications.

In the closure of the persistentStoreCoordinator property, we start by instantiating an instance of the NSPersistentStoreCoordinator class, passing in the managed object model as an argument. We'll explore the managedObjectModel property in a moment.

As you can see, creating an NSPersistentStoreCoordinator object is easy. However, a persistent store coordinator is of little use if it doesn't have any persistent stores to manage. In the remainder of the closure, we attempt to load a persistent store and add it to the persistent store coordinator.

We start by specifying the location of the store on disk, using the applicationDocumentsDirectory property we saw earlier. The result, an NSURL object, is passed to the addPersistentStoreWithType(_:configuration:URL:options:) method of the NSPersistentStoreCoordinator class. As the method's name indicates, the method adds a persistent store to the persistent store coordinator. The method accepts four arguments.

We first specify the store type, NSSQLiteStoreType in this example. Core Data also supports binary stores (NSBinaryStoreType) and an in-memory store (NSInMemoryStoreType).

The second argument tells Core Data which configuration to use for the persistent store. We pass in nil, which tells Core Data to use the default configuration. The third argument is the location of the store, which is stored in url.

The fourth argument is a dictionary of options that lets us alter the behavior of the persistent store. We'll revisit this aspect later in this series and pass in nil for now.

Because addPersistentStoreWithType(_:configuration:URL:options:) is a throwing method, we wrap the method call in a do-catch statement. If no errors pop up, this method returns an NSPersistentStore object. We don't keep a reference to the persistent store, because we don't need to interact with it once it's added to the persistent store coordinator.

If adding the persistent store fails, though, it means that there's a problem with the persistent store of the application and we need to take the necessary steps to resolve the problem. When this happens and why it happens is the subject of a future installment of this series.

In the catch clause, we log any errors to the console and abort is invoked. You should never call abort in a production environment, because it crashes the application. We will implement a less aggressive solution later in this series.

Step 5: Managed Object Model

The third and final piece of the puzzle is the managed object model. Let's take a look at the implementation of the managedObjectModel property.

The implementation is very easy. We store the location of the application's model in modelURL and use it during the instantiation of the managed object model.

Because the initializer, init(contentsOfURL:), returns an optional, we force unwrap it before returning the result. Isn't that dangerous? Yes and no. It's not recommended to force unwrap optionals. However, failing to initialize the managed object model means that the application is unable to find the data model in the application's bundle. If that happens, then something went wrong that is beyond the control of the application.

At this point, you're probably wondering what that model is modelURL is pointing to and what the file with the .momd extension is. To answer these questions, we need to find out what else Xcode has created for us during the project's setup.

In the Project Navigator on the left, you should see a file named Core_Data.xcdatamodeld. This is the data model of the application that's compiled to an .momd file. It's that .momd file that the managed object model uses to create the application's data model.

Core Data Model

It is possible to have several data model files. The NSManagedObjectModel class is perfectly capable of merging multiple data models into one, that is one of the more powerful and advanced features of Core Data.

The Core Data framework also supports data model versioning as well as migrations. This ensures that the data stored in the persistent store(s) doesn't get corrupted. We will cover versioning and migrations later in this series.

The data model file in your project is empty at the moment, which means that your data model contains no entities. We'll remedy this in the next tutorial that will focus exclusively on the data model.

6. Putting It All Together

Before we wrap up this article, I'd like to show you a diagram that illustrates the three components of the Core Data stack.

Core Data Stack

The above diagram is a visual representation of what we explored in the example project a moment ago. The NSPersistentStoreCoordinator object is the brain of the application's Core Data stack. It talks to one or more persistent stores and makes sure data is saved, loaded, and cached.

The persistent store coordinator knows about the data model, the schema of the object graph if you like, through the NSManagedObjectModel object. The managed object model creates the application's data model from one or more .momd files, binary representations of the data model.

Last but not least, the application accesses the object graph through one or more instances of the NSManagedObjectContext class. A managed object context knows about the data model through the persistent store coordinator, but it doesn't know or keep a reference to the managed object model. There is no need for such a reference.

The managed object context asks the persistent coordinator for data and tells it to save data when necessary. This is all done for you by the Core Data framework and your application rarely needs to talk to the persistent store coordinator directly.

Conclusion

In this article, we covered the key players of the Core Data stack, the persistent store coordinator, the managed object model, and the managed object context. Make sure you understand the role of each component and, more importantly, how they work together to make Core Data do its magic.

In the next installment of this series, we dive into the data model. We take a look at the data model editor in Xcode and we create a few entities, attributes, and relationships.

2015-11-04T17:45:15.000Z2015-11-04T17:45:15.000ZBart Jacobs

Core Data and Swift: Data Model

$
0
0

Introduction

In the first article of this series, we learned about the Core Data stack, the heart of a Core Data application. We explored the managed object context, the persistent store coordinator, and the managed object model.

This article focuses on the data model of a Core Data application. We zoom in on Xcode's data model editor and we take a look at entities, attributes, and relationships.

Prerequisites

What I cover in this series on Core Data is applicable to iOS 7+ and OS X 10.10+, but the focus will be on iOS. In this series, I will work with Xcode 7.1 and Swift 2.1. If you prefer Objective-C, then I recommend reading my earlier series on the Core Data framework.

1. Data Model Editor

Start by downloading the project from the previous tutorial or clone the repository from GitHub. Open the project in Xcode and, in the Project Navigator, search for Core_Data.xcdatamodeld. Xcode automatically shows the data model editor when the project's data model is selected.

The Core Data Model Editor in Xcode

2. Entities

Before we explore the editor's user interface, we need to create an entity to work with. At the bottom of the data model editor, click the Add Entity button. This will add an entity with name Entity. It will show up in the Entities section on the left of the data model editor. Change the entity's name to Person by double-clicking it in the Entities section.

Adding an Entity to the Core Data Model

"What is an entity?" you may be wondering. To bring back the database analogy, an entity is comparable to a table in a database. When you select the Person entity, you see that an entity can have attributes, relationships, and fetched properties. Don't worry about fetched properties for now, they're a more advanced feature of the framework.

3. Attributes

Give the Person entity an attribute by clicking the plus button at the bottom of the Attributes table. Double-click the attribute's name and set it to first. From the Type drop-down menu, select String. If we compare this to a table in a database, the Person table now has a column first of type String.

Adding an Attribute to an Entity in the the Core Data Model

Even though I don't want to confuse you by comparing entities with tables of a database, it makes it easier to understand what entities and attributes are. In fact, if you use a SQLite database as the backing store of your application, Core Data will create a table for you to store the data of the Person entity. However, this is something we don't have to and should not need to worry about. Remember that Core Data is not a database.

The same goes for relationships. How Core Data keeps track of relationships is something we don't need to worry about. In fact, Core Data makes sure relationships are only loaded when the application needs them. This is something we'll revisit later in this series.

Add two more attributes to the Person entity, last of type String and age of type Integer 16. The type you choose for numbers is not important at this point. It tells Core Data how it should structure the persistent store and optimize it for performance.

Attribute Options

The attribute of an entity can be configured through the Data Model Inspector. Select the first attribute of the Person entity and open the inspector on the right. The Data Model Inspector lets you configure the selected attribute. At this point, we're only interested in a few settings, OptionalAttribute Type, and Default Value.

Optional

Marking an attribute as optional means that the attribute can be empty or left blank for a record. In our example, however, we want to make sure every Person record has a first name. With the first attribute selected, uncheck Optional to mark it as required. New attributes are optional by default.

Marking an attribute as required has consequences though. If we save a Person record without a valid first name, Core Data will throw an error. This means that we need to make sure that the record's first attribute is set before saving it.

Attribute Type

The attribute type is important for several reasons. It tells Core Data in what format it should save the attribute and it will also return the attribute's data to us in the specified format. Each attribute type has a different set of configuration options. Change the attribute type of the first attribute to Date to see the configuration options for an attribute of type Date.

Default Value

Several attribute types, such as String and Date, have a Default Value field you can set. This is convenient, for example, if an attribute is required and you want to ensure the attribute for a record has a valid value when it's inserted in the database.

Note that the default value is only used when a new record is created. If an existing Person record, for example, is updated by setting the first attribute to nil, then Core Data won't populate the first attribute with the default value. Instead Core data will throw an error, because we marked the first attribute as required.

4. Relationships

Core Data really shines when you start working with relationships between entities. Let's see how this works by adding a second entity named Address. The Address entity has four attributes of type Stringstreetnumbercity, and country.

Relationships between entities have a number of defining characteristics, the name, the destination, the cardinality of the relationship, the inverse relationship, and the relationship's delete rule.

Let's explore relationships in more detail by creating a relationship between the Person and Address entities.

Name, Destination, and Optionality

Create a relationship by selecting the Person entity and clicking the plus button at the bottom of the Relationships table. Name the relationship address and set the Destination to the Address entity. This indicates that each person record can be associated with an address record.

Adding a Relationship to an Entity in the the Core Data Model

As with attributes, relationships are optional by default. This means that no validation error will be thrown if a person record has no relationship with an address record. Let's change this by unchecking the Optional checkbox in the Data Model Inspector on the right.

Inverse Relationship

At the moment, the person can have a relationship with an address record. However, if the person has an address record associated with it, the address record does not know about the person record, because the relationship is one-way at the moment—from Person to Address. Most relationships in Core Data, however, are two-way, both entities know about the relationship.

Let's create the inverse relationship from the Address entity to the Person entity by selecting the Address entity and creating a relationship named person with the Person entity as its destination.

Adding an Inverse Relationship to an Entity in the the Core Data Model

Even though we created the inverse relationship between Address and Person, Xcode gives us a few warnings telling us Person.address should have an inverse and Address.person should have an inverse. Did we do something wrong?

Core Data isn't clever enough to know which relationship is the inverse relationship of which relationship. This is easy to fix though. Select the Person entity and set the Inverse of the address relationship to person, the person relationship. If you now select the Address entity, you'll see that the inverse of the address relationship has already been set to the person relationship.

Data Model Graph

When the data model gains in complexity, relationships can become confusing and unclear. Xcode has your back covered though. The data model editor has two styles, table and graph. In the bottom right of the editor, you should see a toggle, Editor Style, that lets you switch between the two styles. Click the button on the right to switch to the graph style.

Toggling the Style of the Editor

The graph style shows you the object graph we've created so far. It shows us the entities we've created, their attributes, and their relationships. One of the most useful features, however, is the visual representation of the relationships between the entities of the data model. A line with an arrow at each end connects Person and Address, symbolizing their two-way relationship.

Graph Style

To-Many Relationships

The relationships we've created so far are to-one relationships, a person can have one address and vice versa. However, it's possible that several people live at the same address. How would we include this extra information in the data model?

A relationship's cardinality specifies if it's a to-one or to-many relationship. Let's change the person relationship of the Address entity to make it a to-many relationship. Select the person relationship of the Address entity, change its name to persons to reflect the to-many relationship, and set the relationship Type to To Many in the inspector on the right.

Adding a To-Many Relationship to an Entity in the the Core Data Model

The name of the relationship isn't important, but it shows that it's a to-many relationship. Notice that the data model graph updates automatically. The relationship endpoint to the Person entity has two arrows to symbolize the to-many nature of the relationship.

Many-To-Many Relationships

Wait a minute. Isn't it possible that a person is associated with more than one address? A person can have a work address and a home address. Right? Core Data solves this by creating a many-to-many relationship. Select the address relationship of the Person entity, change its name to addresses, and set the relationship Type to To Many. The data model graph shows the updated relationship as a line with two arrows on both ends.

Adding a Many-To-Many Relationship to an Entity in the the Core Data Model

Reflexive Relationships

The way Core Data implements relationships is very flexible. The destination entity of a relationship can even be the same as the source entity. This is known as a reflexive relationship. It's also possible to have multiple relationships of the same type with different names. A person, for example, can have a mother and a father. Both relationships are reflexive with the only difference being the name of the relationship.

Delete Rules

What happens when the record on one end of the relationship is deleted? If you were to think about Core Data as a database, then the answer would be obvious. Core Data, however, isn't a database.

Assume you have an Account entity with a to-many relationship to a User entity. In other words, an account can have many users and each user belongs to one account. What happens when you delete a user? What happens when you delete an account? In Core Data, each relationship has a delete rule that makes it clear what happens in these situations.

Delete rules make sure you don't have to worry about explicitly updating the persistent store when a record is deleted. Core Data takes care of this to ensure the object graph remains in a consistent state.

Select  the addresses relationship of the Person entity and open the inspector on the right. The Delete Rule menu has four options, No ActionNullifyCascade, and Deny.

No Action

If you select No Action, Core Data doesn't update or notify the source record of the relationship. This means that the source record of the relationship still thinks it has a relationship with the record that was deleted. This is rarely what you want.

Nullify

This option sets the destination of the relationship to null when the destination record is deleted. This is the default delete rule of a relationship. You could apply this delete rule if, for example, a relationship is optional.

Cascade

If the relationship from Person to Address is set to Cascade, deleting a person record will also delete any address records that are associated with the person record. This is useful, for example, if a relationship is required and the record cannot or shouldn't exist without the relationship. A user, for example, shouldn't exist if it's not associated with an account.

Deny

In a sense, Deny is the inverse of Cascade. For example, if we have an Account entity that has a to-many relationship with a User entity with its delete rule set to Deny, an account record can only be deleted if it has no user records associated with it. This ensures that no user records exist without an account record.

Conclusion

In this tutorial, we've taken a closer look at the data model used by a Core Data application. You should now be familiar with entities, attributes, and relationships, and you should be able to create them using Xcode's data model editor.

Core Data is very good at managing relationships and Xcode's data model editor makes it easy to create and manage relationships between entities. Relationships between entities are powerful and easy to configure. Delete rules ensure that the object graph Core Data manages remains healthy and in a consistent state.

In the next article, we get our hands dirty and start working with Core Data. You'll learn how to create, read, update, and delete records, and become familiar with NSManagedObject and NSFetchRequest.

2015-11-05T17:45:55.000Z2015-11-05T17:45:55.000ZBart Jacobs

Core Data and Swift: Data Model

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-25067

Introduction

In the first article of this series, we learned about the Core Data stack, the heart of a Core Data application. We explored the managed object context, the persistent store coordinator, and the managed object model.

This article focuses on the data model of a Core Data application. We zoom in on Xcode's data model editor and we take a look at entities, attributes, and relationships.

Prerequisites

What I cover in this series on Core Data is applicable to iOS 7+ and OS X 10.10+, but the focus will be on iOS. In this series, I will work with Xcode 7.1 and Swift 2.1. If you prefer Objective-C, then I recommend reading my earlier series on the Core Data framework.

1. Data Model Editor

Start by downloading the project from the previous tutorial or clone the repository from GitHub. Open the project in Xcode and, in the Project Navigator, search for Core_Data.xcdatamodeld. Xcode automatically shows the data model editor when the project's data model is selected.

The Core Data Model Editor in Xcode

2. Entities

Before we explore the editor's user interface, we need to create an entity to work with. At the bottom of the data model editor, click the Add Entity button. This will add an entity with name Entity. It will show up in the Entities section on the left of the data model editor. Change the entity's name to Person by double-clicking it in the Entities section.

Adding an Entity to the Core Data Model

"What is an entity?" you may be wondering. To bring back the database analogy, an entity is comparable to a table in a database. When you select the Person entity, you see that an entity can have attributes, relationships, and fetched properties. Don't worry about fetched properties for now, they're a more advanced feature of the framework.

3. Attributes

Give the Person entity an attribute by clicking the plus button at the bottom of the Attributes table. Double-click the attribute's name and set it to first. From the Type drop-down menu, select String. If we compare this to a table in a database, the Person table now has a column first of type String.

Adding an Attribute to an Entity in the the Core Data Model

Even though I don't want to confuse you by comparing entities with tables of a database, it makes it easier to understand what entities and attributes are. In fact, if you use a SQLite database as the backing store of your application, Core Data will create a table for you to store the data of the Person entity. However, this is something we don't have to and should not need to worry about. Remember that Core Data is not a database.

The same goes for relationships. How Core Data keeps track of relationships is something we don't need to worry about. In fact, Core Data makes sure relationships are only loaded when the application needs them. This is something we'll revisit later in this series.

Add two more attributes to the Person entity, last of type String and age of type Integer 16. The type you choose for numbers is not important at this point. It tells Core Data how it should structure the persistent store and optimize it for performance.

Attribute Options

The attribute of an entity can be configured through the Data Model Inspector. Select the first attribute of the Person entity and open the inspector on the right. The Data Model Inspector lets you configure the selected attribute. At this point, we're only interested in a few settings, OptionalAttribute Type, and Default Value.

Optional

Marking an attribute as optional means that the attribute can be empty or left blank for a record. In our example, however, we want to make sure every Person record has a first name. With the first attribute selected, uncheck Optional to mark it as required. New attributes are optional by default.

Marking an attribute as required has consequences though. If we save a Person record without a valid first name, Core Data will throw an error. This means that we need to make sure that the record's first attribute is set before saving it.

Attribute Type

The attribute type is important for several reasons. It tells Core Data in what format it should save the attribute and it will also return the attribute's data to us in the specified format. Each attribute type has a different set of configuration options. Change the attribute type of the first attribute to Date to see the configuration options for an attribute of type Date.

Default Value

Several attribute types, such as String and Date, have a Default Value field you can set. This is convenient, for example, if an attribute is required and you want to ensure the attribute for a record has a valid value when it's inserted in the database.

Note that the default value is only used when a new record is created. If an existing Person record, for example, is updated by setting the first attribute to nil, then Core Data won't populate the first attribute with the default value. Instead Core data will throw an error, because we marked the first attribute as required.

4. Relationships

Core Data really shines when you start working with relationships between entities. Let's see how this works by adding a second entity named Address. The Address entity has four attributes of type Stringstreetnumbercity, and country.

Relationships between entities have a number of defining characteristics, the name, the destination, the cardinality of the relationship, the inverse relationship, and the relationship's delete rule.

Let's explore relationships in more detail by creating a relationship between the Person and Address entities.

Name, Destination, and Optionality

Create a relationship by selecting the Person entity and clicking the plus button at the bottom of the Relationships table. Name the relationship address and set the Destination to the Address entity. This indicates that each person record can be associated with an address record.

Adding a Relationship to an Entity in the the Core Data Model

As with attributes, relationships are optional by default. This means that no validation error will be thrown if a person record has no relationship with an address record. Let's change this by unchecking the Optional checkbox in the Data Model Inspector on the right.

Inverse Relationship

At the moment, the person can have a relationship with an address record. However, if the person has an address record associated with it, the address record does not know about the person record, because the relationship is one-way at the moment—from Person to Address. Most relationships in Core Data, however, are two-way, both entities know about the relationship.

Let's create the inverse relationship from the Address entity to the Person entity by selecting the Address entity and creating a relationship named person with the Person entity as its destination.

Adding an Inverse Relationship to an Entity in the the Core Data Model

Even though we created the inverse relationship between Address and Person, Xcode gives us a few warnings telling us Person.address should have an inverse and Address.person should have an inverse. Did we do something wrong?

Core Data isn't clever enough to know which relationship is the inverse relationship of which relationship. This is easy to fix though. Select the Person entity and set the Inverse of the address relationship to person, the person relationship. If you now select the Address entity, you'll see that the inverse of the address relationship has already been set to the person relationship.

Data Model Graph

When the data model gains in complexity, relationships can become confusing and unclear. Xcode has your back covered though. The data model editor has two styles, table and graph. In the bottom right of the editor, you should see a toggle, Editor Style, that lets you switch between the two styles. Click the button on the right to switch to the graph style.

Toggling the Style of the Editor

The graph style shows you the object graph we've created so far. It shows us the entities we've created, their attributes, and their relationships. One of the most useful features, however, is the visual representation of the relationships between the entities of the data model. A line with an arrow at each end connects Person and Address, symbolizing their two-way relationship.

Graph Style

To-Many Relationships

The relationships we've created so far are to-one relationships, a person can have one address and vice versa. However, it's possible that several people live at the same address. How would we include this extra information in the data model?

A relationship's cardinality specifies if it's a to-one or to-many relationship. Let's change the person relationship of the Address entity to make it a to-many relationship. Select the person relationship of the Address entity, change its name to persons to reflect the to-many relationship, and set the relationship Type to To Many in the inspector on the right.

Adding a To-Many Relationship to an Entity in the the Core Data Model

The name of the relationship isn't important, but it shows that it's a to-many relationship. Notice that the data model graph updates automatically. The relationship endpoint to the Person entity has two arrows to symbolize the to-many nature of the relationship.

Many-To-Many Relationships

Wait a minute. Isn't it possible that a person is associated with more than one address? A person can have a work address and a home address. Right? Core Data solves this by creating a many-to-many relationship. Select the address relationship of the Person entity, change its name to addresses, and set the relationship Type to To Many. The data model graph shows the updated relationship as a line with two arrows on both ends.

Adding a Many-To-Many Relationship to an Entity in the the Core Data Model

Reflexive Relationships

The way Core Data implements relationships is very flexible. The destination entity of a relationship can even be the same as the source entity. This is known as a reflexive relationship. It's also possible to have multiple relationships of the same type with different names. A person, for example, can have a mother and a father. Both relationships are reflexive with the only difference being the name of the relationship.

Delete Rules

What happens when the record on one end of the relationship is deleted? If you were to think about Core Data as a database, then the answer would be obvious. Core Data, however, isn't a database.

Assume you have an Account entity with a to-many relationship to a User entity. In other words, an account can have many users and each user belongs to one account. What happens when you delete a user? What happens when you delete an account? In Core Data, each relationship has a delete rule that makes it clear what happens in these situations.

Delete rules make sure you don't have to worry about explicitly updating the persistent store when a record is deleted. Core Data takes care of this to ensure the object graph remains in a consistent state.

Select  the addresses relationship of the Person entity and open the inspector on the right. The Delete Rule menu has four options, No ActionNullifyCascade, and Deny.

No Action

If you select No Action, Core Data doesn't update or notify the source record of the relationship. This means that the source record of the relationship still thinks it has a relationship with the record that was deleted. This is rarely what you want.

Nullify

This option sets the destination of the relationship to null when the destination record is deleted. This is the default delete rule of a relationship. You could apply this delete rule if, for example, a relationship is optional.

Cascade

If the relationship from Person to Address is set to Cascade, deleting a person record will also delete any address records that are associated with the person record. This is useful, for example, if a relationship is required and the record cannot or shouldn't exist without the relationship. A user, for example, shouldn't exist if it's not associated with an account.

Deny

In a sense, Deny is the inverse of Cascade. For example, if we have an Account entity that has a to-many relationship with a User entity with its delete rule set to Deny, an account record can only be deleted if it has no user records associated with it. This ensures that no user records exist without an account record.

Conclusion

In this tutorial, we've taken a closer look at the data model used by a Core Data application. You should now be familiar with entities, attributes, and relationships, and you should be able to create them using Xcode's data model editor.

Core Data is very good at managing relationships and Xcode's data model editor makes it easy to create and manage relationships between entities. Relationships between entities are powerful and easy to configure. Delete rules ensure that the object graph Core Data manages remains healthy and in a consistent state.

In the next article, we get our hands dirty and start working with Core Data. You'll learn how to create, read, update, and delete records, and become familiar with NSManagedObject and NSFetchRequest.

2015-11-05T17:45:55.000Z2015-11-05T17:45:55.000ZBart Jacobs

Core Data and Swift: Managed Objects and Fetch Requests

$
0
0

With everything about Cora Data data models still fresh in your mind, it's time to start working with Core Data. In this article, we meet NSManagedObject, the class you'll interact with most when working with Core Data. You'll learn how to create, read, update, and delete records.

You'll also get to know a few other Core Data classes, such as NSFetchRequest and NSEntityDescription. Let me start by introducing you to NSManagedObject, your new best friend.

Prerequisites

What I cover in this series on Core Data is applicable to iOS 7+ and OS X 10.10+, but the focus will be on iOS. In this series, I will work with Xcode 7.1 and Swift 2.1. If you prefer Objective-C, then I recommend reading my earlier series on the Core Data framework.

1. Managed Objects

Instances of NSManagedObject represent a record in Core Data's backing store. Remember, it doesn't matter what that backing store looks like. However, to revisit the database analogy, an NSManagedObject instance contains the information of a row in a database table.

The reason Core Data uses NSManagedObject instead of NSObject as its base class for modeling records will make more sense a bit later. Before we start working with NSManagedObject, we need to know a few things about this class.

NSEntityDescription

Each NSManagedObject instance is associated with an instance of NSEntityDescription. The entity description includes information about the managed object, such as the entity of the managed object as well its attributes and relationships.

NSManagedObjectContext

A managed object is also linked to an instance of NSManagedObjectContext. The managed object context to which a managed object belongs, monitors the managed object for changes.

2. Creating a Record

With the above in mind, creating a managed object is pretty straightforward. To make sure a managed object is properly configured, it is recommended to use the designated initializer for creating new NSManagedObject instances. Let's see how this works by creating a new person object.

Open the project from the previous article or clone the repository from GitHub. Because we won't be building a functional application in this article, we'll do most of our work in the application delegate class, AppDelegate. Open AppDelegate.swift and update the implementation of application(_:didFinishLaunchingWithOptions:) as shown below.

The first thing we do, is creating an instance of the NSEntityDescription class by invoking entityForName(_:inManagedObjectContext:). We pass the name of the entity we want to create a managed object for, "Person", and an NSManagedObjectContext instance.

Why do we need to pass in a NSManagedObjectContext object? We specify the name that we want to create a managed object for, but we also need to tell Core Data where it can find the data model for that entity. Remember that a managed object context is tied to a persistent store coordinator and a persistent store coordinator keeps a reference to a data model. When we pass in a managed object context, Core Data asks its persistent store coordinator for its data model to find the entity we're looking for.

In the second step, we invoke the designated initializer of the NSManagedObject class, init(entity:insertIntoManagedObjectContext:). We pass in the entity description and an NSManagedObjectContext instance. Wait? Why do we need to pass in another NSManagedObjectContext instance? Remember what I wrote earlier. A managed object is associated with an entity description and it lives in a managed object context, which is why we tell Core Data which managed object context the new managed object should be linked to.

This isn't too complex. Is it? We've now created a new person object. How do we change its attributes or define a relationship? This is done by leveraging key-value coding. To change the first name of the new person object we just created we do the following:

If you're familiar with key-value coding, then this should look very familiar. Because the NSManagedObject class conforms to the NSKeyValueCoding protocol, we set an attribute by invoking setValue(_:forKey:). It's that simple.

One downside of this approach is that you can easily introduce bugs by misspelling an attribute or relationship name. Also, attribute names are not autocompleted by Xcode like, for example, property names are. This problem is easy to solve, but that's something we'll take a look at a bit later in this series.

Before we continue our exploration of NSManagedObject, let's set the age attribute of newPerson to 44.

3. Saving a Record

Even though we now have a new person instance, Core Data hasn't saved the person to its backing store yet. At the moment, the managed object we created only lives in the managed object context in which it was inserted. To save the person object to the backing store, we need to save the changes of the managed object context by calling save() on it.

The save() method is a throwing method and returns a boolean to indicate the result of the save operation. Take a look at the following code block for clarification.

Build and run the application to see if everything works as expected. Did you also run into a crash? What did the console output tell you? Did it look similar to the output below?

Xcode tells us that it expected an NSDate instance for the first attribute, but we passed in a String. If you open the Core Data model we created in the previous article, you'll see that the type of the first attribute is indeed Date. Change it to String and run the application one more time.

Another crash? Even though this is a more advanced topic, it's important to understand what's going on.

Data Model Compatibility

The output in Xcode's console should look similar to the output shown below. Note that the error is different from the previous one. Xcode tells us that the model to open the store is incompatible with the one used to create the store. How did this happen?

When we first launched the application a few moments ago, Core Data inspected the data model and, based on that model, created a store for us, a SQLite database in this case. Core Data is clever though. It makes sure that the structure of the backing store and that of the data model are compatible. This is vital to make sure that we get back from the backing store what we expect and what we put there in the first place.

During the first crash, we noticed that our data model contained a mistake and we changed the type of the first attribute from Date to String. In other words, we changed the data model even though Core Data had already created the backing store for us based on the incorrect data model.

After updating the data model, we launched the application again and ran into the second crash. One of the things Core Data does when it creates the Core Data stack is making sure the data model and the backing store—if one exists—are compatible. That was not the case in our example hence the crash.

How do we solve this? The easy solution is to remove the application from the device or from the simulator, and launch the application again. However, this is something you cannot do if you already have an application in the App Store that people are using. In that case, you make use of migrations, which is something we'll discuss in a future article.

Because we don't have millions of users using our application, we can safely remove the application from our test device and run it again. If all went well, the new person is now safely stored in the store, the SQLite database Core Data created for us.

Inspecting the Backing Store

You can verify that the save operation worked by taking a look inside the SQLite database. If you ran the application in the simulator, then navigate to /Users/<USER>/Library/Developer/CoreSimulator/Devices/<DEVICE_ID>/data/Containers/Data/Application/<APPLICATION_ID>/Documents/SingleViewCoreData.sqlite. Because the location of application data changes with every release of Xcode, the above path is only valid for Xcode 7.

Open the SQLite database and inspect the table named ZPERSON. The table should have one record, the one we inserted a minute ago.

Contents of the SQLite Database

You should keep two things in mind. First, there's no need to understand the database structure. Core Data manages the backing store for us and we don't need to understand its structure to work with Core Data. Second, never access the backing store directly. Core Data is in charge of the backing store and we need to respect that if we want Core Data to do its job well. If we start interacting with the SQLite database—or any other store type—there is no guarantee Core Data will continue to function properly. In short, Core Data is in charge of the store so leave it alone.

4. Fetching Records

Even though we'll take a close look at NSFetchRequest in the next article, we need the NSFetchRequest class to ask Core Data for information from the object graph it manages. Let's see how we can fetch the record we inserted earlier using NSFetchRequest.

After initializing the fetch request, we create an NSEntityDescription object and assign it to the entity property of the fetch request. As you can see, we use the NSEntityDescription class to tell Core Data what entity we're interested in.

Fetching data is handled by the NSManagedObjectContext class. We invoke executeFetchRequest(_:), passing in the fetch request. Because executeFetchRequest(_:) is a throwing method, we wrap the method call in a do-catch statement.

The method returns an array of results if the fetch request is successful. Note that Core Data always returns an array if the fetch request is successful, even if we expect one result or if Core Data didn't find any matching records.

Run the application and inspect the output in Xcode's console. Below you can see what was returned, an array with one object of type NSManagedObject. The entity of the object is Person.

To access the attributes of the record, we make use of key-value coding like we did earlier. It's important to become familiar with key-value coding if you plan to work with Core Data.

You may be wondering why I log the person object before and after logging the person's name. This is actually one of the most important lessons of this article. Take look at the output below.

The first time we log the person object to the console, we see data: <fault>. The second time, however, data contains the contents of the object's attributes and relationships. Why is that? This has everything to do with faulting, a key concept of Core Data.

5. Faulting

The concept that underlies faulting isn't unique to Core Data. If you've ever worked with Active Record in Ruby on Rails, then the following will certainly ring a bell. The concept isn't identical, but similar from a developer's perspective.

Core Data tries to keep its memory footprint as low as possible and one of the strategies it uses to accomplish this is faulting. When we fetched the records for the Person entity a moment ago, Core Data executed the fetch request, but it didn't fully initialize the managed objects representing the fetched records.

What we got back is a fault, a placeholder object representing the record. The object is of type NSManagedObject and we can treat it as such. By not fully initializing the record, Core Data keeps its memory footprint low. It's not a significant memory saving in our example, but imagine what would happen if we fetched dozens, hundreds, or even thousands of records.

Faults are generally nothing that you need to worry about. The moment you access an attribute or relationship of a managed object, the fault is fired, which means that Core Data changes the fault into a realized managed object. You can see this in our example and that's also the reason why the second log statement of the person object doesn't print a fault to the console.

Faulting is something that trips up many newcomers and I therefore want to make sure you understand the basics of this concept. We'll learn more about faulting later in this series. If you want to learn more about Core Data faults, then you may want to read this in-depth look at faulting in Core Data.

6. Updating Records

Updating records is just as simple as creating a new record. You fetch the record, change an attribute or relationship, and save the managed object context. Because the managed object, the record, is linked to a managed object context, the latter is aware of any changes, insertions, updates, and deletes. When the managed object context is saved, everything is propagated to the backing store by Core Data.

Take a look at the following code block in which we update the record we fetched by changing the person's age and saving the changes.

You can verify that the update was successful by taking another look at the SQLite store like we did earlier.

Updating a Record in the Backing Store

7. Deleting Records

Deleting a record follows the same pattern. We tell the managed object context that a record needs to be deleted from the persistent store by invoking deleteObject(_:) and passing the managed object that needs to be deleted.

In our project, delete the person object we fetched earlier by passing it to the managed object context's deleteObject(_:) method. Note that the delete operation isn't committed to the backing store until we call save() on the managed object context.

You can verify that the delete operation was successful by taking another look at the SQLite store.

Deleting a Record from the Backing Store

Conclusion

In this tutorial, we've covered a lot more than just creating, fetching, updating, and deleting records. We've touched on a few important concepts on which Core Data relies, such as faulting and data model compatibility.

In the next installment of this series, you'll learn how to create and update relationships, and we take an in-depth look at the NSFetchRequest class. We'll also start using NSPredicate and NSSortDescriptor to make our fetch requests flexible, dynamic, and powerful.

2015-11-06T17:45:22.000Z2015-11-06T17:45:22.000ZBart Jacobs

Core Data and Swift: Managed Objects and Fetch Requests

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-25068

With everything about Cora Data data models still fresh in your mind, it's time to start working with Core Data. In this article, we meet NSManagedObject, the class you'll interact with most when working with Core Data. You'll learn how to create, read, update, and delete records.

You'll also get to know a few other Core Data classes, such as NSFetchRequest and NSEntityDescription. Let me start by introducing you to NSManagedObject, your new best friend.

Prerequisites

What I cover in this series on Core Data is applicable to iOS 7+ and OS X 10.10+, but the focus will be on iOS. In this series, I will work with Xcode 7.1 and Swift 2.1. If you prefer Objective-C, then I recommend reading my earlier series on the Core Data framework.

1. Managed Objects

Instances of NSManagedObject represent a record in Core Data's backing store. Remember, it doesn't matter what that backing store looks like. However, to revisit the database analogy, an NSManagedObject instance contains the information of a row in a database table.

The reason Core Data uses NSManagedObject instead of NSObject as its base class for modeling records will make more sense a bit later. Before we start working with NSManagedObject, we need to know a few things about this class.

NSEntityDescription

Each NSManagedObject instance is associated with an instance of NSEntityDescription. The entity description includes information about the managed object, such as the entity of the managed object as well its attributes and relationships.

NSManagedObjectContext

A managed object is also linked to an instance of NSManagedObjectContext. The managed object context to which a managed object belongs, monitors the managed object for changes.

2. Creating a Record

With the above in mind, creating a managed object is pretty straightforward. To make sure a managed object is properly configured, it is recommended to use the designated initializer for creating new NSManagedObject instances. Let's see how this works by creating a new person object.

Open the project from the previous article or clone the repository from GitHub. Because we won't be building a functional application in this article, we'll do most of our work in the application delegate class, AppDelegate. Open AppDelegate.swift and update the implementation of application(_:didFinishLaunchingWithOptions:) as shown below.

The first thing we do, is creating an instance of the NSEntityDescription class by invoking entityForName(_:inManagedObjectContext:). We pass the name of the entity we want to create a managed object for, "Person", and an NSManagedObjectContext instance.

Why do we need to pass in a NSManagedObjectContext object? We specify the name that we want to create a managed object for, but we also need to tell Core Data where it can find the data model for that entity. Remember that a managed object context is tied to a persistent store coordinator and a persistent store coordinator keeps a reference to a data model. When we pass in a managed object context, Core Data asks its persistent store coordinator for its data model to find the entity we're looking for.

In the second step, we invoke the designated initializer of the NSManagedObject class, init(entity:insertIntoManagedObjectContext:). We pass in the entity description and an NSManagedObjectContext instance. Wait? Why do we need to pass in another NSManagedObjectContext instance? Remember what I wrote earlier. A managed object is associated with an entity description and it lives in a managed object context, which is why we tell Core Data which managed object context the new managed object should be linked to.

This isn't too complex. Is it? We've now created a new person object. How do we change its attributes or define a relationship? This is done by leveraging key-value coding. To change the first name of the new person object we just created we do the following:

If you're familiar with key-value coding, then this should look very familiar. Because the NSManagedObject class conforms to the NSKeyValueCoding protocol, we set an attribute by invoking setValue(_:forKey:). It's that simple.

One downside of this approach is that you can easily introduce bugs by misspelling an attribute or relationship name. Also, attribute names are not autocompleted by Xcode like, for example, property names are. This problem is easy to solve, but that's something we'll take a look at a bit later in this series.

Before we continue our exploration of NSManagedObject, let's set the age attribute of newPerson to 44.

3. Saving a Record

Even though we now have a new person instance, Core Data hasn't saved the person to its backing store yet. At the moment, the managed object we created only lives in the managed object context in which it was inserted. To save the person object to the backing store, we need to save the changes of the managed object context by calling save() on it.

The save() method is a throwing method and returns a boolean to indicate the result of the save operation. Take a look at the following code block for clarification.

Build and run the application to see if everything works as expected. Did you also run into a crash? What did the console output tell you? Did it look similar to the output below?

Xcode tells us that it expected an NSDate instance for the first attribute, but we passed in a String. If you open the Core Data model we created in the previous article, you'll see that the type of the first attribute is indeed Date. Change it to String and run the application one more time.

Another crash? Even though this is a more advanced topic, it's important to understand what's going on.

Data Model Compatibility

The output in Xcode's console should look similar to the output shown below. Note that the error is different from the previous one. Xcode tells us that the model to open the store is incompatible with the one used to create the store. How did this happen?

When we first launched the application a few moments ago, Core Data inspected the data model and, based on that model, created a store for us, a SQLite database in this case. Core Data is clever though. It makes sure that the structure of the backing store and that of the data model are compatible. This is vital to make sure that we get back from the backing store what we expect and what we put there in the first place.

During the first crash, we noticed that our data model contained a mistake and we changed the type of the first attribute from Date to String. In other words, we changed the data model even though Core Data had already created the backing store for us based on the incorrect data model.

After updating the data model, we launched the application again and ran into the second crash. One of the things Core Data does when it creates the Core Data stack is making sure the data model and the backing store—if one exists—are compatible. That was not the case in our example hence the crash.

How do we solve this? The easy solution is to remove the application from the device or from the simulator, and launch the application again. However, this is something you cannot do if you already have an application in the App Store that people are using. In that case, you make use of migrations, which is something we'll discuss in a future article.

Because we don't have millions of users using our application, we can safely remove the application from our test device and run it again. If all went well, the new person is now safely stored in the store, the SQLite database Core Data created for us.

Inspecting the Backing Store

You can verify that the save operation worked by taking a look inside the SQLite database. If you ran the application in the simulator, then navigate to /Users/<USER>/Library/Developer/CoreSimulator/Devices/<DEVICE_ID>/data/Containers/Data/Application/<APPLICATION_ID>/Documents/SingleViewCoreData.sqlite. Because the location of application data changes with every release of Xcode, the above path is only valid for Xcode 7.

Open the SQLite database and inspect the table named ZPERSON. The table should have one record, the one we inserted a minute ago.

Contents of the SQLite Database

You should keep two things in mind. First, there's no need to understand the database structure. Core Data manages the backing store for us and we don't need to understand its structure to work with Core Data. Second, never access the backing store directly. Core Data is in charge of the backing store and we need to respect that if we want Core Data to do its job well. If we start interacting with the SQLite database—or any other store type—there is no guarantee Core Data will continue to function properly. In short, Core Data is in charge of the store so leave it alone.

4. Fetching Records

Even though we'll take a close look at NSFetchRequest in the next article, we need the NSFetchRequest class to ask Core Data for information from the object graph it manages. Let's see how we can fetch the record we inserted earlier using NSFetchRequest.

After initializing the fetch request, we create an NSEntityDescription object and assign it to the entity property of the fetch request. As you can see, we use the NSEntityDescription class to tell Core Data what entity we're interested in.

Fetching data is handled by the NSManagedObjectContext class. We invoke executeFetchRequest(_:), passing in the fetch request. Because executeFetchRequest(_:) is a throwing method, we wrap the method call in a do-catch statement.

The method returns an array of results if the fetch request is successful. Note that Core Data always returns an array if the fetch request is successful, even if we expect one result or if Core Data didn't find any matching records.

Run the application and inspect the output in Xcode's console. Below you can see what was returned, an array with one object of type NSManagedObject. The entity of the object is Person.

To access the attributes of the record, we make use of key-value coding like we did earlier. It's important to become familiar with key-value coding if you plan to work with Core Data.

You may be wondering why I log the person object before and after logging the person's name. This is actually one of the most important lessons of this article. Take look at the output below.

The first time we log the person object to the console, we see data: <fault>. The second time, however, data contains the contents of the object's attributes and relationships. Why is that? This has everything to do with faulting, a key concept of Core Data.

5. Faulting

The concept that underlies faulting isn't unique to Core Data. If you've ever worked with Active Record in Ruby on Rails, then the following will certainly ring a bell. The concept isn't identical, but similar from a developer's perspective.

Core Data tries to keep its memory footprint as low as possible and one of the strategies it uses to accomplish this is faulting. When we fetched the records for the Person entity a moment ago, Core Data executed the fetch request, but it didn't fully initialize the managed objects representing the fetched records.

What we got back is a fault, a placeholder object representing the record. The object is of type NSManagedObject and we can treat it as such. By not fully initializing the record, Core Data keeps its memory footprint low. It's not a significant memory saving in our example, but imagine what would happen if we fetched dozens, hundreds, or even thousands of records.

Faults are generally nothing that you need to worry about. The moment you access an attribute or relationship of a managed object, the fault is fired, which means that Core Data changes the fault into a realized managed object. You can see this in our example and that's also the reason why the second log statement of the person object doesn't print a fault to the console.

Faulting is something that trips up many newcomers and I therefore want to make sure you understand the basics of this concept. We'll learn more about faulting later in this series. If you want to learn more about Core Data faults, then you may want to read this in-depth look at faulting in Core Data.

6. Updating Records

Updating records is just as simple as creating a new record. You fetch the record, change an attribute or relationship, and save the managed object context. Because the managed object, the record, is linked to a managed object context, the latter is aware of any changes, insertions, updates, and deletes. When the managed object context is saved, everything is propagated to the backing store by Core Data.

Take a look at the following code block in which we update the record we fetched by changing the person's age and saving the changes.

You can verify that the update was successful by taking another look at the SQLite store like we did earlier.

Updating a Record in the Backing Store

7. Deleting Records

Deleting a record follows the same pattern. We tell the managed object context that a record needs to be deleted from the persistent store by invoking deleteObject(_:) and passing the managed object that needs to be deleted.

In our project, delete the person object we fetched earlier by passing it to the managed object context's deleteObject(_:) method. Note that the delete operation isn't committed to the backing store until we call save() on the managed object context.

You can verify that the delete operation was successful by taking another look at the SQLite store.

Deleting a Record from the Backing Store

Conclusion

In this tutorial, we've covered a lot more than just creating, fetching, updating, and deleting records. We've touched on a few important concepts on which Core Data relies, such as faulting and data model compatibility.

In the next installment of this series, you'll learn how to create and update relationships, and we take an in-depth look at the NSFetchRequest class. We'll also start using NSPredicate and NSSortDescriptor to make our fetch requests flexible, dynamic, and powerful.

2015-11-06T17:45:22.000Z2015-11-06T17:45:22.000ZBart Jacobs

iOS 9: An Introduction to Multitasking on iPad

$
0
0

Introduction

With iOS 9, Apple introduced a number of multitasking capabilities for iPad. These include Slide OverSplit View, and Picture in Picture. If you are not familiar with these new features, here's a brief overview.

Slide Over

Slide Over is available on iPad Mini 2 and later, all iPad Air models, and iPad Pro. It allows for apps to slide in from the right side of the screen with the full height of the screen (in both orientations) and the approximate width of an iPhone screen.

Slide Over

Picture in Picture

Picture in Picture is available on all iPad models that support Slide Over. It allows for a video to continue being played in a small view while you work with other apps on iPad. This small view contains three buttons to control playback, return to full screen, play/pause, and close. The view can be resized or temporarily pushed off to the side of the screen.

Picture in Picture Video

Split View

Split View is available on iPad Mini 4, iPad Air 2, and iPad Pro. It allows iPad to run two fully functional apps side by side. The user can move the divider between the two apps to resize them.

Note that the app on the left is referred to as the primary application and the app on the right the secondary app. The primary application owns the status bar of the device and always takes up at least half of the screen. The primary app can be dismissed by the user, however, if they move the divider all the way to the left.

Split View

Prerequisites

This tutorial requires that you are running Xcode 7 or later on OS X Yosemite or later. It also assumes that you have learned about size classes and Auto Layout. If you are new to adaptive design, then I recommend reading Jordan Morgan's tutorial on adaptive design. You will also need to download the starter project from GitHub.

1. Slide Over and Split View

Configuration

By default, all apps that are created from any Xcode 7 template automatically support Slide Over and Split View. This is because your app is created with a LaunchScreen.storyboard file and a size class enabled Main.storyboard file.

For projects that were created with an earlier version of Xcode, you can enable Slide Over and Split View for your app by taking the following two steps.

Step 1

Create a LaunchScreen.storyboard file by selecting the iOS > User Interface > Launch Screen template. The launch screen will be displayed once your app has been launched from the home screen and while it's still loading.

Launch Screen Storyboard

Note that this storyboard replaces the static launch images that you would already have configured for your application.

Step 2

Ensure that your user interface is using size classes and Auto Layout. You can verify this by selecting the storyboard of your project, opening the File Inspector, and ticking the Use Auto Layout and Use Size Classes checkboxes in the Interface Builder Document section.

Storyboard Configuration

Note that you need to do this for every storyboard in your project. Now that you know how to configure an app correctly for Slide Over and Split View, it's time to learn about how to ensure your app works well alongside other apps.

Size Classes

For Slide Over, the current size class for your app when running will always be the same. When your app is the primary app it will have access to the full screen (regular width and height size class) and nothing will be different. When your app is opened via the Slide Over feature, your app will have a compact width and regular height size class regardless of orientation.

On an iPad that supports Split View, however, your app window can be resized at any moment and needs to be designed to fit these sizes. The following diagram shows the different configurations for Split View app sizes and the size classes associated with these.:

Size Classes diagram
Source: Apple's Adopting Multitasking Enhancements on iPad: Slide Over and Split View Quick Start Guide

As you can see, unless your app is the primary application and the device is in landscape orientation, as soon as your have to share the screen with another app your app will be forced into a compact width size class. Because this change in size is dependent on the user and can happen at any time, you app needs to be able to smoothly transition between different view sizes.

Note that on iPad Pro, when in landscape and 50/50 Split View mode, both apps are given a regular width horizontal size class as shown below.

iPad Pro Horizontal Size Class
Screenshot Taken From Completed Tutorial Application

Callback Methods

In order to account for these changes in size, the UIViewController class conforms to the two protocols, UITraitEnvironment and UIContentContainer.

UITraitEnvironment

This protocol contains a UITraitCollection property called traitCollection and a method for when this trait collection changes, traitCollectionDidChange(_:). This trait collection object allows you to find out specific details about the running state of your app, such as the display scale, current horizontal and vertical size classes, 3D touch (referred to as Force Touch by the API) capability, and current device type (iPhone/iPod Touch, iPad, Apple TV or Unspecified).

UIContentContainer

This protocol contains a preferredContentSize property as well as numerous methods for when the size or trait collection changes for the current container. We will take a closer look at two of the methods defined by the UIContentContainer protocol.

Open the starter project you downloaded from GitHub and navigate to ViewController.swift. Next, add the following methods to the class definition:

In the viewWillTransitionToSize(_:withTransitionCoordinator:) method, we update the viewWidth label to display the new width of the screen.

In the willTransitionToTraitCollection(_:withTransitionCoordinator:) method, we check to see which horizontal size class is being transitioned to and update the sizeClass label accordingly.

You may have noticed that both methods provide a UIViewControllerTransitionCoordinator parameter. This object is mainly used to work with animations between view controllers and it doesn't really relate to Split View multitasking as the system handles the animations. The UIViewControllerTransitionCoordinator parameter exists because these UIContentContainer protocol methods are not exclusive to Split View multitasking and can also be executed in other scenarios.

Run your app on a physical device or in the iPad Air 2 or iPad Pro simulator. Once the app has launched, drag in from the right side of the screen and select any of the apps in the list.

Select Slide Over App

Once the app has opened, press and hold on the small bar to the left of the just opened app as shown below.

Start Split Screen

Drag the divider that appears to the middle of the screen as shown in the following screenshot and release it.

Centered Split Screen divider

When your app fades back in, the two labels should update with the correct view width and horizontal size class.

Updated Labels

2. Picture in Picture Video

As with Slide Over and Split View, if you are using Xcode 7 or later, then your app will automatically support Picture in Picture. For audiovisual content, this is done by using the AVPlayerViewController class.

Before you can start using Picture in Picture, however, you need to enable a capability for your target. Select your target, open the Capabilities tab in the Project Navigator, enable Background Modes, and tick the checkbox labeled Audio, AirPlay and Picture in Picture.

Picture in Picture Capability

Run your app again and tap the Play Video button. The video I've included in the starter project will start playing. With the video playing, go to the home screen by pressing the home button on your device or Command-Shift-H if you're using the simulator.

Alternatively, you can press the small button in the bottom left corner to enter Picture in Picture mode. You will see that the video view minimizes and remains on the screen, complete with buttons to reopen, play/pause and close.

Picture in Picture Video

At this stage, you will notice that if you press on the button to begin viewing the video in full screen again, the app will open but the video playback view controller does not appear at all. You can change this behavior by conforming the view controller to the AVPlayerViewControllerDelegate protocol.

Start by making the ViewController class conform to the AVPlayerViewControllerDelegate protocol.

Next, replace prepareForSegue(_:sender:) with the following implementation:

Lastly, add the playerViewControllerShouldAutomaticallyDismissAtPictureInPictureStart(_: AVPlayerViewController) method of the AVPlayerViewControllerDelegate protocol to the ViewController class.

By implementing this method, we ensure that the video player view controller does not close when Picture in Picture mode is entered. Build and run your app again and you will see that, when reopening from Picture in Picture, the video will continue to play.

If you are not using an AVPlayerViewController to play your content, there are other ways in which you can support Picture in Picture video. If you are using an AVPlayerLayer to allow for a custom user interface around your video, you can create an AVPictureInPictureController object to support Picture in Picture. This is what such an implementation could look like:

3. Disabling iPad Multitasking

If, for some reason, you don't want your application to support Slide Over, Split View, or Picture in Picture, you can override the default behavior provided by Xcode and iOS.

Slide Over and Split View

For Slide Over and Split View, all you need to do is add the UIRequiresFullScreen key to your app's Info.plist file and set it to YES.

Picture in Picture

With the AVPlayerViewController class, you just need to set the allowsPictureInPicturePlayback property to false.

For Picture in Picture with an AVPlayerLayer object, you don't create an AVPictureInPictureController.

Lastly, for videos displayed through the web via a WKWebView, you need to set the allowsPictureInPicturePlayback property of the view's configuration to false.

Conclusion

You should now be confident in creating applications that support the new Slide Over, Split View, and Picture in Picture multitasking capabilities added to iPad on iOS 9. As you can see, these new features make the iPad a much more productive tool and they are very easy for developers to implement in their own applications.

As always, you can leave your comments and feedback in the comments below.

2015-11-09T16:15:19.000Z2015-11-09T16:15:19.000ZDavis Allie

iOS 9: An Introduction to Multitasking on iPad

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-25151

Introduction

With iOS 9, Apple introduced a number of multitasking capabilities for iPad. These include Slide OverSplit View, and Picture in Picture. If you are not familiar with these new features, here's a brief overview.

Slide Over

Slide Over is available on iPad Mini 2 and later, all iPad Air models, and iPad Pro. It allows for apps to slide in from the right side of the screen with the full height of the screen (in both orientations) and the approximate width of an iPhone screen.

Slide Over

Picture in Picture

Picture in Picture is available on all iPad models that support Slide Over. It allows for a video to continue being played in a small view while you work with other apps on iPad. This small view contains three buttons to control playback, return to full screen, play/pause, and close. The view can be resized or temporarily pushed off to the side of the screen.

Picture in Picture Video

Split View

Split View is available on iPad Mini 4, iPad Air 2, and iPad Pro. It allows iPad to run two fully functional apps side by side. The user can move the divider between the two apps to resize them.

Note that the app on the left is referred to as the primary application and the app on the right the secondary app. The primary application owns the status bar of the device and always takes up at least half of the screen. The primary app can be dismissed by the user, however, if they move the divider all the way to the left.

Split View

Prerequisites

This tutorial requires that you are running Xcode 7 or later on OS X Yosemite or later. It also assumes that you have learned about size classes and Auto Layout. If you are new to adaptive design, then I recommend reading Jordan Morgan's tutorial on adaptive design. You will also need to download the starter project from GitHub.

1. Slide Over and Split View

Configuration

By default, all apps that are created from any Xcode 7 template automatically support Slide Over and Split View. This is because your app is created with a LaunchScreen.storyboard file and a size class enabled Main.storyboard file.

For projects that were created with an earlier version of Xcode, you can enable Slide Over and Split View for your app by taking the following two steps.

Step 1

Create a LaunchScreen.storyboard file by selecting the iOS > User Interface > Launch Screen template. The launch screen will be displayed once your app has been launched from the home screen and while it's still loading.

Launch Screen Storyboard

Note that this storyboard replaces the static launch images that you would already have configured for your application.

Step 2

Ensure that your user interface is using size classes and Auto Layout. You can verify this by selecting the storyboard of your project, opening the File Inspector, and ticking the Use Auto Layout and Use Size Classes checkboxes in the Interface Builder Document section.

Storyboard Configuration

Note that you need to do this for every storyboard in your project. Now that you know how to configure an app correctly for Slide Over and Split View, it's time to learn about how to ensure your app works well alongside other apps.

Size Classes

For Slide Over, the current size class for your app when running will always be the same. When your app is the primary app it will have access to the full screen (regular width and height size class) and nothing will be different. When your app is opened via the Slide Over feature, your app will have a compact width and regular height size class regardless of orientation.

On an iPad that supports Split View, however, your app window can be resized at any moment and needs to be designed to fit these sizes. The following diagram shows the different configurations for Split View app sizes and the size classes associated with these.:

Size Classes diagram
Source: Apple's Adopting Multitasking Enhancements on iPad: Slide Over and Split View Quick Start Guide

As you can see, unless your app is the primary application and the device is in landscape orientation, as soon as your have to share the screen with another app your app will be forced into a compact width size class. Because this change in size is dependent on the user and can happen at any time, you app needs to be able to smoothly transition between different view sizes.

Note that on iPad Pro, when in landscape and 50/50 Split View mode, both apps are given a regular width horizontal size class as shown below.

iPad Pro Horizontal Size Class
Screenshot Taken From Completed Tutorial Application

Callback Methods

In order to account for these changes in size, the UIViewController class conforms to the two protocols, UITraitEnvironment and UIContentContainer.

UITraitEnvironment

This protocol contains a UITraitCollection property called traitCollection and a method for when this trait collection changes, traitCollectionDidChange(_:). This trait collection object allows you to find out specific details about the running state of your app, such as the display scale, current horizontal and vertical size classes, 3D touch (referred to as Force Touch by the API) capability, and current device type (iPhone/iPod Touch, iPad, Apple TV or Unspecified).

UIContentContainer

This protocol contains a preferredContentSize property as well as numerous methods for when the size or trait collection changes for the current container. We will take a closer look at two of the methods defined by the UIContentContainer protocol.

Open the starter project you downloaded from GitHub and navigate to ViewController.swift. Next, add the following methods to the class definition:

In the viewWillTransitionToSize(_:withTransitionCoordinator:) method, we update the viewWidth label to display the new width of the screen.

In the willTransitionToTraitCollection(_:withTransitionCoordinator:) method, we check to see which horizontal size class is being transitioned to and update the sizeClass label accordingly.

You may have noticed that both methods provide a UIViewControllerTransitionCoordinator parameter. This object is mainly used to work with animations between view controllers and it doesn't really relate to Split View multitasking as the system handles the animations. The UIViewControllerTransitionCoordinator parameter exists because these UIContentContainer protocol methods are not exclusive to Split View multitasking and can also be executed in other scenarios.

Run your app on a physical device or in the iPad Air 2 or iPad Pro simulator. Once the app has launched, drag in from the right side of the screen and select any of the apps in the list.

Select Slide Over App

Once the app has opened, press and hold on the small bar to the left of the just opened app as shown below.

Start Split Screen

Drag the divider that appears to the middle of the screen as shown in the following screenshot and release it.

Centered Split Screen divider

When your app fades back in, the two labels should update with the correct view width and horizontal size class.

Updated Labels

2. Picture in Picture Video

As with Slide Over and Split View, if you are using Xcode 7 or later, then your app will automatically support Picture in Picture. For audiovisual content, this is done by using the AVPlayerViewController class.

Before you can start using Picture in Picture, however, you need to enable a capability for your target. Select your target, open the Capabilities tab in the Project Navigator, enable Background Modes, and tick the checkbox labeled Audio, AirPlay and Picture in Picture.

Picture in Picture Capability

Run your app again and tap the Play Video button. The video I've included in the starter project will start playing. With the video playing, go to the home screen by pressing the home button on your device or Command-Shift-H if you're using the simulator.

Alternatively, you can press the small button in the bottom left corner to enter Picture in Picture mode. You will see that the video view minimizes and remains on the screen, complete with buttons to reopen, play/pause and close.

Picture in Picture Video

At this stage, you will notice that if you press on the button to begin viewing the video in full screen again, the app will open but the video playback view controller does not appear at all. You can change this behavior by conforming the view controller to the AVPlayerViewControllerDelegate protocol.

Start by making the ViewController class conform to the AVPlayerViewControllerDelegate protocol.

Next, replace prepareForSegue(_:sender:) with the following implementation:

Lastly, add the playerViewControllerShouldAutomaticallyDismissAtPictureInPictureStart(_: AVPlayerViewController) method of the AVPlayerViewControllerDelegate protocol to the ViewController class.

By implementing this method, we ensure that the video player view controller does not close when Picture in Picture mode is entered. Build and run your app again and you will see that, when reopening from Picture in Picture, the video will continue to play.

If you are not using an AVPlayerViewController to play your content, there are other ways in which you can support Picture in Picture video. If you are using an AVPlayerLayer to allow for a custom user interface around your video, you can create an AVPictureInPictureController object to support Picture in Picture. This is what such an implementation could look like:

3. Disabling iPad Multitasking

If, for some reason, you don't want your application to support Slide Over, Split View, or Picture in Picture, you can override the default behavior provided by Xcode and iOS.

Slide Over and Split View

For Slide Over and Split View, all you need to do is add the UIRequiresFullScreen key to your app's Info.plist file and set it to YES.

Picture in Picture

With the AVPlayerViewController class, you just need to set the allowsPictureInPicturePlayback property to false.

For Picture in Picture with an AVPlayerLayer object, you don't create an AVPictureInPictureController.

Lastly, for videos displayed through the web via a WKWebView, you need to set the allowsPictureInPicturePlayback property of the view's configuration to false.

Conclusion

You should now be confident in creating applications that support the new Slide Over, Split View, and Picture in Picture multitasking capabilities added to iPad on iOS 9. As you can see, these new features make the iPad a much more productive tool and they are very easy for developers to implement in their own applications.

As always, you can leave your comments and feedback in the comments below.

2015-11-09T16:15:19.000Z2015-11-09T16:15:19.000ZDavis Allie

Core Data and Swift: Relationships and More Fetching

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-25070

In the previous article, we learned about NSManagedObject and how easy it is to create, read, update, and delete records using Core Data. However, I didn't mention relationships in that discussion. Aside from a few caveats you need to be aware of, relationships are just as easy to manipulate as attributes. In this article, we will focus on relationships and we'll also continue our exploration of NSFetchRequest.

Prerequisites

What I cover in this series on Core Data is applicable to iOS 7+ and OS X 10.10+, but the focus will be on iOS. In this series, I will work with Xcode 7.1 and Swift 2.1. If you prefer Objective-C, then I recommend reading my earlier series on the Core Data framework.

1. Relationships

We've already worked with relationships in the Core Data model editor and what I'm about to tell you will therefore sound familiar. Relationships are, just like attributes, accessed using key-value coding. Remember that the data model we created earlier in this series defines a Person entity and an Address entity. A person is linked to one or more addresses and an address is linked to one or more persons. This is a many-to-many relationship.

To fetch the addresses of a person, we simply invoke valueForKey(_:) on the person, an instance of NSManagedObject, and pass in addresses as the key. Note that addresses is the key we defined in the data model. What type of object do you expect? Most people new to Core Data expect a sorted array, but Core Data returns a set, which is unsorted. Working with sets has its advantages as you'll learn later.

Creating Records

Enough with the theory, open the project from the previous article or clone it from GitHub. Let's start by creating a person and then link it to an address. To create a person, open AppDelegate.swift and update application(_:didFinishLaunchingWithOptions:) as shown below.

This should look familiar if you've read the previous article. Creating an address looks similar as you can see below.

Because every attribute of the Address entity is marked as optional, we don't need to assign a value to each attribute. In the example, we only set the record's street and city attributes.

Creating a Relationship

To link newAddress to newPerson, we invoke valueForKey(_:), passing in addresses as the key. The value that we pass in is an NSSet instance that contains newAddress. Take a look at the following code block for clarification.

We call save() on the managed object context of newPerson to propagate the changes to the persistent store. Remember that calling save() on a managed object context saves the state of the managed object context. This means that newAddress is also written to the backing store as well as the relationships we just defined.

You may be wondering why we didn't link newPerson to newAddress, because we did define an inverse relationship in the data model. Core Data creates this relationship for us. If a relationship has an inverse relationship, then Core Data takes care of this automatically. You can verify this by asking newAddress for its persons.

Fetching and Updating a Relationship

Updating a relationship isn't difficult either. The only caveat is that we need to add or remove elements from the immutable NSSet instance Core Data hands to us. To make this task easier, however, the NSKeyValueCoding protocol declares a convenience method mutableSetValueForKey(_:), which returns an NSMutableSet object. We can then simply add or remove an item from the collection to update the relationship.

Take a look at the following code block in which we create another address and associate it with newPerson. We do this by invoking mutableSetValueForKey(_:) on newPerson and adding otherAddress to the mutable set. There is no need to tell Core Data that we've updated the relationship. Core Data keeps track of the mutable set that it gave us and updates the relationship.

Deleting a Relationship

You can delete a relationship by invoking setValue(_:forKey:), passing in nil as the value and the name of the relationship as the key. In the next code snippet, we unlink every address from newPerson.

2. One-To-One and One-To-Many Relationships

One-To-One Relationships

Even though our data model doesn't define a one-to-one relationship, you've learned everything you need to know to work with this type of relationship. Working with a one-to-one relationship is identical to working with attributes. The only difference is that the value you get back from valueForKey(_:) and the value you pass to setValue(_:forKey:) is an NSManagedObject instance.

Let's update the data model to illustrate this. Open Core_Data.xcdatamodeld and select the Person entity. Create a new relationship and name it spouse. Set the Person entity as the destination and set the spouse relationship as the inverse relationship.

Add a One-To-One Relationship to Person

As you can see, it's possible to create a relationship in which the destination of the relationship is the same entity as the entity that defines the relationship. Also note that we always set the inverse of the relationship. As the Apple's documentation states, there are very few situations in which you want to create a relationship that doesn't have an inverse relationship.

Do you know what will happen if you were to build and run the application? That's right, the application would crash. Because we changed the data model, the existing backing store, a SQLite database in this example, is no longer compatible with the data model. To remedy this, remove the application from your device or the simulator and run the application. Don't worry though, we'll solve this problem more elegantly in a future installment using migrations.

If you can run the application without problems, then it's time for the next step. Head back to the application delegate class and add the following code block.

To set anotherPerson as the spouse of newPerson, we invoke setValue(_:forKey:) on newPerson and pass in anotherPerson and "spouse" as the arguments. We can achieve the same result by invoking setValue(_:forKey:) on anotherPerson, passing in newPerson and "spouse" as the arguments.

One-To-Many Relationships

Let's finish with a look at one-to-many relationships. Open Core_Data.xcdatamodeld, select the Person entity, and create a relationship named children. Set the destination to Person, set the type to To Many, and leave the inverse relationship empty for now.

Add a One-To-Many Relationship to Person

Create another relationship named father, set the destination to Person, and set the inverse relationship to children. This will automatically populate the inverse relationship of the children relationship we left blank a moment ago. We've now created a one-to-many relationship, that is, a father can have many children, but a child can only have one biological father.

Add a One-To-Many Relationship to Person

Head back to the application delegate and add the following code block. We create another Person record, set its attributes, and set it as a child of newPerson by asking Core Data for a mutable set for the key children and adding the new record to the mutable set.

The following code block accomplishes the same result by setting the father attribute of anotherChildPerson. The result is that newPerson becomes the father of anotherChildPerson and anotherChildPerson becomes a child of newPerson.

3. More Fetching

The data model of our sample application has grown quite a bit in terms of complexity. We've created one-to-one, one-to-many, and many-to-many relationships. We've seen how easy it is to create records, including relationships. If we also want to be able to pull that data from the persistent store, then we need to learn more about fetching. Let's start with a simple example in which we see how to sort the results returned by a fetch request.

Sort Descriptors

To sort the records we get back from the managed object context, we use the NSSortDescriptor class. Take a look at the following code snippet.

We initialize a fetch request by passing in the entity that we're interested in, Person. We then create an NSSortDescriptor object by invoking init(key:ascending:), passing in the attribute of the entity we'd like to sort by, first, and a boolean indicating whether the records need to be sorted in ascending or descending order.

We tie the sort descriptor to the fetch request by setting the sortDescriptors property of the fetch request. Because the sortDescriptors property is of type [NSSortDescriptor]?, it is possible to specify more than one sort descriptor. We'll take a look at this option in a moment.

The rest of the code block should look familiar. The fetch request is passed to the managed object context, which executes the fetch request when we invoke executeFetchRequest(_:). Remember that the latter is a throwing method, which means that we use the try keyword and execute the fetch request in a do-catch statement.

Run the application and inspect the output in Xcode's console. The output should look similar to what is shown below. As you can see, the records are sorted by their first name.

If you see duplicates in the output, then make sure to comment out the code we wrote earlier to create the records. Every time you run the application, the same records are created, resulting in duplicate records.

Like I mentioned, it is possible to combine multiple sort descriptors. Let's sort the records by their last name and age. We first set the key of the first sort descriptor to last. We then create another sort descriptor with a key of age and add it to the array of sort descriptors.

The output shows that the order of the sort descriptors in the array is important. The records are first sorted by their last name and then by their age.

Predicates

Sort descriptors are great and easy to use, but predicates are what really makes fetching powerful in Core Data. Sort descriptors tell Core Data how the records need to be sorted. Predicates tell Core Data what records you're interested in. The class we'll be working with is NSPredicate.

Let's start by fetching every member of the Doe family. This is very easy to do and the syntax will remind some of you of SQL.

We haven't changed much apart from creating an NSPredicate object by invoking init(format:arguments:) and tying the predicate to the fetch request by setting the latter's predicate property. Note that the init(format:arguments:) method accepts a variable number of arguments.

The predicate format string uses %K for the property name and %@ for the value. As stated in the Predicate Programming Guide%K is a variable argument substitution for a key path while %@ is a variable argument substitution for an object value. This means that the predicate format string of our example evaluates to last == "Doe".

If you run the application and inspect the output in Xcode's console, you should see the following result:

There are many operators we can use for comparison. In addition to = and ==, which are identical as far as Core Data is concerned, there's also >= and =><= and =>!= and <>, and > and <. I encourage you to experiment with these operators to learn how they affect the results of the fetch request.

The following predicate illustrates how we can use the >= operator to only fetch Person records with an age attribute greater than 30.

We also have operators for string comparison, CONTAINSLIKEMATCHESBEGINSWITH, and ENDSWITH. Let's fetch every Person record whose name CONTAINS the letter j.

If you run the application, the array of results will be empty since the string comparison is case sensitive by default. We can change this by adding a modifier like so:

You can also create compound predicates using the keywords ANDOR, and NOT. In the following example, we fetch every person whose first name contains the letter j and is younger than 30.

Predicates also make it very easy to fetch records based on their relationship. In the following example, we fetch every person whose father's name is equal to Bart.

The above predicate works as expected, because %K is a variable argument substitution for a key path, not just a key.

What you need to remember is that predicates enable you to query the backing store without you knowing anything about the store. Even though the syntax of the predicate format string is reminiscent of SQL in some ways, it doesn't matter if the backing store is a SQLite database or an in-memory store. This is a very powerful concept that isn't unique to Core Data. Rails's Active Record is another fine example of this paradigm.

There is much more to predicates than what I've shown you in this article. If you'd like to learn more about predicates, I suggest you take a peak at Apple's Predicate Programming Guide. We'll also work more with predicates in the next few articles of this series.

Conclusion

You now have a good grasp of the basics of Core Data and it's time to start working with the framework by creating an application that leverages Core Data's power. In the next article, we meet another important class of the Core Data framework, NSFetchedResultsController. This class will help us manage a collection of records, but you'll learn that it does quite a bit more than that.

2015-11-11T17:45:30.000Z2015-11-11T17:45:30.000ZBart Jacobs

Core Data and Swift: NSFetchedResultsController

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-25072

In the previous installments of this series, we covered the fundamentals of the Core Data framework. It's time we put our knowledge to use by building a simple application powered by Core Data.

In this tutorial, we'll also meet another star player of the Core Data framework, the NSFetchedResultsController class. The application that we're about to create manages a list of to-do items. With the application, we can add, update, and delete to-do items. You'll quickly learn that the NSFetchedResultsController class makes this very easy to do.

Prerequisites

What I cover in this series on Core Data is applicable to iOS 7+ and OS X 10.10+, but the focus will be on iOS. In this series, I will work with Xcode 7.1 and Swift 2.1. If you prefer Objective-C, then I recommend reading my earlier series on the Core Data framework.

1. Project Setup

Open Xcode, select New > Project... from the File menu, and choose the Single View Application template from the iOS > Application category.

Choosing the Single View Application Template

Name the project Done, set Language to Swift, and set Devices to iPhone. Because I'd like to show you how to create a Core Data application from scratch, make sure that the checkbox labeled Use Core Data is unchecked. Tell Xcode where you want to save the project and hit Create to create the project.

Configuring the Project

2. Core Data Setup

Open AppDelegate.swift and declare three lazy stored properties managedObjectModel of type NSManagedObjectModelmanagedObjectContext of type NSManagedObjectContext, and persistentStoreCoordinator of type NSPersistentStoreCoordinator. If you're confused by this step, then I recommend you revisit the first article of this series, which covers the Core Data stack in detail.

Note that I've also added an import statement for the Core Data framework at the top of AppDelegate.swift.

Remember that we use the lazy keyword to lazily set up the Core Data stack. This means that we instantiate the managed object context, the managed object model, and the persistent store coordinator the moment they are needed by the application. The following implementation should look very familiar.

There are three things you should be aware of. First, the data model, which we'll create next, will be named Done.momd. Second, we'll name the backing store Done and it will be a SQLite database. Third, if the backing store is incompatible with the data model, we invoke abort, killing the application. As I mentioned earlier in this series, while this is fine during development, you should never call abort in production. We'll revisit migrations and incompatibility issues later in this series.

While our application won't crash if you try to run it, the Core Data stack won't get properly set up. The reason is simple, we haven't created a data model yet. Let's take care of that in the next step.

3. Creating the Data Model

Select New > File... from the File menu and choose Data Model from the iOS > Core Data category.

Creating the Data Model

Name the file Done, double-check that it's added to the Done target, and tell Xcode where it needs to be saved.

Naming the Data Model

The data model is going to be very simple. Create a new entity and name it Item. Add three attributes to the entity, name of  type StringcreatedAt of type Date, and done of type Boolean.

Creating the Item Entity

Mark the attributes as required, not optional, and set the default value of the done attribute to NO.

Configuring the Done Attribute

The Core Data stack is set up and the data model is configured correctly. It's time to become familiar with a new class of the Core Data framework, the NSFetchedResultsController class.

4. Managing Data

This article isn't just about the NSFetchedResultsController class, it's about what the NSFetchedResultsController class does behind the scenes. Let me clarify what I mean by this.

If we were to build our application without the NSFetchedResultsController class, we would need to find a way to keep the application's user interface synchronized with the data managed by Core Data. Fortunately, Core Data has an elegant solution to this problem.

Whenever a record is insertedupdated, or deleted in a managed object context, the managed object context posts a notification through notification center. A managed object context posts three types of notifications:

  • NSManagedObjectContextObjectsDidChangeNotification: This notification is posted every time a record in the managed object context is inserted, updated, or deleted.
  • NSManagedObjectContextWillSaveNotification: This notification is posted by the managed object context before pending changes are committed to the backing store.
  • NSManagedObjectContextDidSaveNotification: This notification is posted by the managed object context immediately after pending changes have been committed to the backing store.

The contents of these notifications are identical, that is, the object property of the notification is the NSManagedObjectContext instance that posted the notification and the notification's userInfo dictionary contains the records that were insertedupdated, and deleted.

The gist is that it requires a fair amount of boilerplate code to keep the results of a fetch request up to date. In other words, if we were to create our application without using the NSFetchedResultsController class, we would have to implement a mechanism that monitored the managed object context for changes and update the user interface accordingly. Let's see how the NSFetchedResultsController can help us with this task.

5. Setting Up the User Interface

Working with the NSFetchedResultsController class is pretty easy. An instance of the NSFetchedResultsController class takes a fetch request and has a delegate object. The NSFetchedResultsController object makes sure that it keeps the results of the fetch request up to date by monitoring the managed object context the fetch request was executed by.

If the NSFetchedResultsController object is notified of any changes by the NSManagedObjectContext object of the fetch request, it notifies its delegate. You may be wondering how this is different from a view controller directly monitoring the NSManagedObjectContext object. The beauty of the NSFetchedResultsController class is that it processes the notifications it receives from the NSManagedObjectContext object and tells the delegate only what it needs to know to update the user interface in response to these changes. The methods of the NSFetchedResultsControllerDelegate protocol should clarify this.

The signatures of the above delegate methods reveal the true purpose of the NSFetchedResultsController class. On iOS, the NSFetchedResultsController class was designed to manage the data displayed by a UITableView or a UICollectionView. It tells its delegate exactly which records changed, how to update the user interface, and when to do this.

Don't worry if you're still unsure about the purpose or advantages of the NSFetchedResultsController class. It'll make more sense once we've implemented the NSFetchedResultsControllerDelegate protocol. Let's revisit our application and put the NSFetchedResultsController class to use.

Step 1: Populating the Storyboard

Open the project's main storyboard, Main.storyboard, select the View Controller Scene, and embed it in a navigation controller by selecting Embed In > Navigation Controller from the Editor menu.

Drag a UITableView object in the View Controller Scene, create an outlet in the ViewController class, and connect it in the storyboard. Don't forget to make the ViewController class conform to the UITableViewDataSource and UITableViewDelegate protocols.

Select the table view, open the Connections Inspector, and connect the table view's dataSource and delegate outlets to the View Controller object. With the table view selected, open the Attributes Inspector and set the number of Prototype Cells to 1.

Before we continue, we need to create a UITableViewCell subclass for the prototype cell. Create a new Objective-C subclass, ToDoCell, and set its superclass to UITableViewCell. Create two outlets, nameLabel of type UILabel and doneButton of type UIButton.

Head back to the storyboard, select the prototype cell in the table view, and set the class to ToDoCell in the Identity Inspector. Add a UILabel and a UIButton object to the cell's content view and connect the outlets in the Connections Inspector. With the prototype cell selected, open the Attributes Inspector and set the identifier of the prototype cell to ToDoCell. This identifier will serve as the cell's reuse identifier. The prototype cell's layout should look something like the screenshot below.

Creating the ToDoCell Prototype Cell

Create a new ViewController subclass and name it AddToDoViewController. Open AddToDoViewController.swift, declare an outlet textField of type UITextField and conform the view controller to the UITextFieldDelegate protocol.

Before we add the view controller to the storyboard, add the following two actions to the view controller's implementation file.

Open the storyboard one more time and add a bar button item with an identifier of Add to the right of the navigation bar of the ViewController. Add a new view controller to the storyboard and set its class to AddToDoViewController in the Identity Inspector. With the view controller selected, choose Embed In > Navigation Controller from the Editor menu.

The new view controller should now have a navigation bar. Add two bar button items to the navigation bar, one on the left with an identity of Cancel and one on the right with an identity of Save. Connect the cancel(_:) action to the left bar button item and the save(_:) action to the right bar button item.

Add a UITextField object to the view controller's view and position it 20 points below the navigation bar. The text field should remain at 20 points below the navigation bar. Note that the layout constraint at the top references the top layout guide.

Adding Layout Constraints

Connect the text field with the corresponding outlet in the view controller and set the view controller as the text field's delegate. Finally, control drag from the bar button item of the ViewController to the navigation controller of which the AddToDoViewController is the root view controller. Set the segue type to Present Modally and set the segue's identifier to SegueAddToDoViewController in the Attributes Inspector. That was a lot to take in. The interesting part is yet to come though.

Step 2: Implementing the Table View

Before we can take our application for a spin, we need to implement the UITableViewDataSource protocol in the ViewController class. However, this is where the NSFetchedResultsController class comes into play. To make sure that everything is working return 0 from the tableView(_:numberOfRowsInSection:) method. This will result in an empty table view, but it will allow us to run the application without running into a crash.

To satisfy the compiler, we also need to implement tableView(_:cellForRowAtIndexPath:). At the top of AddToDoViewController.swift, add a constant for the cell reuse identifier.

Implementing tableView(_:cellForRowAtIndexPath:) is pretty simple since we're not doing anything special with the table view cell yet.

Step 3: Save and Cancel

Open the AddToDoViewController class and implement the cancel(_:) and save(_:) methods as shown below. We'll update their implementations later in this tutorial.

Build and run the application in the simulator to see if everything is wired up correctly. You should be able to tap the add button in the top right to bring up the AddToDoViewController and dismiss it by tapping either the cancel or the save button.

6. Adding the NSFetchedResultsController Class

The NSFetchedResultsController class is part of the Core Data framework and it's meant to manage the results of a fetch request. The class was designed to work seamlessly with UITableView and UICollectionView on iOS and NSTableView on OS X. However, it can be used for other purposes as well.

Step 1: Laying the Groundwork

Before we can start working with the NSFetchedResultsController class, however, the ViewController class needs access to an NSManagedObjectContext instance, the NSManagedObjectContext instance we created earlier in the application delegate. Start by declaring a property managedObjectContext of type NSManagedObjectContext! in the header file of the ViewController class. Note that we're also adding an import statement for the Core Data framework at the top.

Open Main.storyboard, select the storyboard's initial view controller, an UINavigationController instance, and set its Storyboard ID to StoryboardIDRootNavigationController in the Identity Inspector.

In the application delegate's application(_:didFinishLaunchingWithOptions:) method, we get a reference to the ViewController instance, the root view controller of the navigation controller, and set its managedObjectContext property. The updated application(_:didFinishLaunchingWithOptions:) method looks as follows:

To make sure that everything is working, add the following print statement to the viewDidLoad() method of the ViewController class.

Step 2: Initializing the NSFetchedResultsController Instance

Open the implementation file of the ViewController class and declare a lazy stored property of type NSFetchedResultsController. Name the property fetchedResultsController. An NSFetchedResultsController instance also has a delegate property that needs to conform to the NSFetchedResultsControllerDelegate protocol. Because the ViewController instance will serve as the delegate of the NSFetchedResultsController instance, we need to conform the ViewController class to the NSFetchedResultsControllerDelegate protocol as shown below.

It's time to initialize the NSFetchedResultsController instance. The heart of a fetched results controller is the NSFetchRequest object, because it determines which records the fetched results controller will manage. In the view controller's viewDidLoad() method, we initialize the fetch request by passing "Item" to the initWithEntityName(_:) method. This should be familiar by now and so is the next line in which we add sort descriptors to the fetch request to sort the results based on the value of the createdAt attribute of each record.

The initialization of the fetched results controller is pretty straightforward. The init(fetchRequest:managedObjectContext:sectionNameKeyPath:cacheName:) method takes four arguments:

  • the fetch request
  • the managed object context the fetched results controller will be monitoring
  • a section key path if you want the results to be split up into sections
  • a cache name if you want to enable caching

We pass nil for the last two parameters for now. The first argument is obvious, but why do we need to pass a NSManagedObjectContext object as well? Not only is the passed in managed object context used to execute the fetch request, it is also the managed object context that the fetched results controller will be monitoring for changes. This will become clearer in a few minutes when we start implementing the delegate methods of the NSFetchedResultsControllerDelegate protocol.

Finally, we need to tell the fetched results controller to execute the fetch request we passed it. We do this by invoking performFetch() in viewDidLoad(). Note that this is a throwing method, which means we need to wrap it in a do-catch statement. The performFetch() method is similar to the executeFetchRequest(_:) method of the NSManagedObjectContext class.

Step 3: Implementing the Delegate Protocol

With the fetched results controller set up and ready to use, we need to implement the NSFetchedResultsControllerDelegate protocol. As we saw earlier, the protocol defines five methods, three of which are of interest to us in this tutorial:

  • controllerWillChangeContent(controller: NSFetchedResultsController)
  • controllerDidChangeContent(controller: NSFetchedResultsController)
  • controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?)

The first two methods tell us when the data the fetched results controller is managing will and did change. This is important to batch update the user interface. For example, it is possible that multiple changes occur at the same time. Instead of updating the user interface for every change, we batch update the user interface once all changes have been made.

In our example, this boils down to the following implementations of controllerWillChangeContent(controller: NSFetchedResultsController) and controllerDidChangeContent(controller: NSFetchedResultsController).

The implementation of controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) is a bit trickier. This delegate method takes no less than five arguments:

  • the NSFetchedResultsController instance
  • the NSManagedObject instance that changed
  • the current index path of the record in the fetched results controller
  • the type of change, that is, insertupdate, or delete
  • the new index path of the record in the fetched results controller, after the change

Note that the index paths have nothing to do with our table view. An NSIndexPath is nothing more than an object that contains one or more indexes to represent a path in a hierarchical structure hence the class's name.

Internally the fetched results controller manages a hierarchical data structure and it notifies its delegate when that data structure changes. It's up to us to visualize those changes in, for example, a table view.

The implementation of controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) looks daunting, but let me walk you through it.

The change type is of type NSFetchedResultsChangeType. This enumeration has four member values:

  • Insert
  • Delete
  • Move
  • Update

The names are pretty self-explanatory. If the type is Insert, we tell the table view to insert a row at newIndexPath. Similarly, if the type is Delete, we remove the row at indexPath from the table view.

If a record is updated, we update the corresponding row in the table view by invoking configureCell(_:atIndexPath:), a helper method that accepts a ToDoCell object and an NSIndexPath object. We'll implement this method in a moment.

If the change type is equal to Move, we remove the row at indexPath and insert a row at newIndexPath to reflect the record's updated position in the fetched results controller's internal data structure.

Step 4: Implementing the UITableViewDataSource Protocol

That wasn't too difficult. Was it? Implementing the UITableViewDataSource protocol is much easier, but there are a few things you should be aware of. Let's start with numberOfSectionsInTableView(_:) and tableView(_:numberOfRowsInSection:.

Even though the table view in our sample application will only have one section, let's ask the fetched results controller for the number of sections. We do this by calling sections on it, which returns an array of objects that conform to the NSFetchedResultsSectionInfo protocol.

Objects conforming to the NSFetchedResultsSectionInfo protocol need to implement a few methods and properties, including numberOfObjects. This gives us what we need to implement the first two methods of the UITableViewDataSource protocol.

Next up are tableView(_:cellForRowAtIndexPath:) and configureCell(_:atIndexPath:). The implementation of tableView(_:cellForRowAtIndexPath:) is short, because we move most of the cell's configuration to configureCell(_:atIndexPath:). We ask the table view for a reusable cell with reuse identifier ReuseIdentifierToDoCell and pass the cell and the index path to configureCell(_:atIndexPath:).

The magic happens in configureCell(_:atIndexPath:). We ask the fetched results controller for the item at indexPath. The fetched results controller returns an NSManagedObject instance to us. We update the nameLabel and the state of the doneButton by asking the record for its name and done attributes.

We'll revisit the UITableViewDataSource protocol later in this tutorial when we delete items from the list. We first need to populate the table view with some data.

7. Adding Records

Let's finish this tutorial by adding the ability to create to-do items. Open the AddToDoViewController class, add an import statement for the Core Data framework, and declare a property managedObjectContext of type NSManagedObjectContext!.

Head back to the ViewController class and implement the prepareForSegue(_:sender:) method. In this method, we set the managedObjectContext property of the AddToDoViewController instance. If you've worked with storyboards before, then the implementation of prepareForSegue(_:sender:) should be straightforward.

If the user enters text in the text field of the AddToDoViewController and taps the Save button, we create a new record, populate it with data, and save it. This logic goes into the save(_:) method we created earlier.

The save(_:) method looks pretty impressive, but there's nothing in there that we haven't covered yet. We create a new managed object, using an NSEntityDescription instance and an NSManagedObjectContext instance. We then populate the managed object with a name and date.

If saving the managed object context is successful, we dismiss the view controller, otherwise we show an alert by invoking showAlertWithTitle(_:message:cancelButtonTitle:), a helper method. If the user taps the save button without entering any text, we also show an alert. In showAlertWithTitle(_:message:cancelButtonTitle:), we create, configure, and present a UIAlertController.

Run the application and add a few items. I'm sure you agree that the NSFetchedResultsController class makes the process of adding items incredibly easy. It takes care of monitoring the managed object context for changes and we update the user interface, the table view of the ViewController class, based on what the NSFetchedResultsController instance tells us through the NSFetchedResultsControllerDelegate protocol.

Conclusion

In the next article, we'll finish the application by adding the ability to delete and update to-do items. It's important that you understand the concepts we discussed in this article. The way Core Data broadcasts the changes of a managed object context's state is essential so make sure you understand this before moving on.

2015-11-12T17:45:37.000Z2015-11-12T17:45:37.000ZBart Jacobs

Telerik Platform 2.0: Fast Forward Mobile Development

$
0
0

Telerik Platform is Telerik's answer to mobile, cross-platform application development. It's used by thousands of companies and developers to create robust, cross-platform solutions. Built on this success, Telerik is working hard on Telerik Platform 2.0, which will be released in December.

Telerik Platform 2.0 gives us a glimpse into the future of mobile, cross-platform application development. The company's goal with Telerik Platform 2.0 is creating a unified experience for mobile application development. A quick look at the product shows us that this is the most unified mobile development solution in the market, offering a far superior development experience compared to existing development tools.

Based on existing users of the product, developers are estimated to be 60% - 80% more productive developing high quality mobile applications with Telerik Platform 2.0 versus developing the applications using native languages.

There is a lot to look froward to and Telerik Platform 2.0 is a major milestone for the platform. On December 3, the company is hosting a free webinar to make you familiar with Telerik Platform 2.0. In this free webinar, Rob Lauer, Brandon Satrom, and Hristo Borisov will introduce you to Telerik Platform 2.0 and help you get up to speed in no time. Sign up for the webinar to learn more about Telerik Platform 2.0.

2015-11-12T18:15:00.000Z2015-11-12T18:15:00.000ZBart Jacobs

Telerik Platform 2.0: Fast Forward Mobile Development

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-25178

Telerik Platform is Telerik's answer to mobile, cross-platform application development. It's used by thousands of companies and developers to create robust, cross-platform solutions. Built on this success, Telerik is working hard on Telerik Platform 2.0, which will be released in December.

Telerik Platform 2.0 gives us a glimpse into the future of mobile, cross-platform application development. The company's goal with Telerik Platform 2.0 is creating a unified experience for mobile application development. A quick look at the product shows us that this is the most unified mobile development solution in the market, offering a far superior development experience compared to existing development tools.

Based on existing users of the product, developers are estimated to be 60% - 80% more productive developing high quality mobile applications with Telerik Platform 2.0 versus developing the applications using native languages.

There is a lot to look froward to and Telerik Platform 2.0 is a major milestone for the platform. On December 3, the company is hosting a free webinar to make you familiar with Telerik Platform 2.0. In this free webinar, Rob Lauer, Brandon Satrom, and Hristo Borisov will introduce you to Telerik Platform 2.0 and help you get up to speed in no time. Sign up for the webinar to learn more about Telerik Platform 2.0.

2015-11-12T18:15:00.000Z2015-11-12T18:15:00.000ZBart Jacobs

Core Data and Swift: More NSFetchedResultsController

$
0
0

In this tutorial, we continue our exploration of the NSFetchedResultsController class by adding the ability to update and delete to-do items. You'll notice that updating and deleting to-do items is surprisingly easy thanks to the groundwork we laid in the previous tutorial.

Prerequisites

What I cover in this series on Core Data is applicable to iOS 7+ and OS X 10.10+, but the focus will be on iOS. In this series, I will work with Xcode 7.1 and Swift 2.1. If you prefer Objective-C, then I recommend reading my earlier series on the Core Data framework.

1. Updating a Record's Name

Step 1: Create View Controller

Start by creating a new UIViewController subclass named UpdateToDoViewController. In UpdateToDoViewController.swift, declare an outlet, textField of type UITextField!, and two properties, managedObjectContext of type NSManagedObjectContext! and record of type NSManagedObject!. Add an import statement for the Core Data framework at the top.

Next, create two actions, cancel(_:) and save(_:). Their implementations can remain empty for the time being.

Step 2: Update Storyboard

Open the main storyboard, Main.storyboard, add a new view controller object, and set its class to UpdateToDoViewController in the Identity Inspector. Press Control and drag from the prototype cell in the ViewController instance to the UpdateToDoViewController instance. Select Selection Segue > Show from the menu that appears and, in the Attributes Inspector, set the segue's identifier to SegueUpdateToDoViewController.

Add a UITextField object to the view of the UpdateToDoViewController object and configure it just like we did with the text field of the AddToDoViewController class. Don't forget to connect the view controller's outlet with the text field.

As in the AddToDoViewController class, add two bar button items to the view controller's navigation bar, set their identities to Cancel and Save respectively, and connect each bar button item to the corresponding action in the Connections Inspector.

Updating the Storyboard

Step 3: Passing a Reference

We also need to make a few changes to the ViewController class. Let's start by updating prepareForSegue(_:sender:), we fetch the record that corresponds with the user's selection and pass it to the UpdateToDoViewController instance.

To finish, we implement the tableView(_:didSelectRowAtIndexPath:) method of the UITableViewDelegate protocol. In this method, we deselect the row the user tapped.

Step 4: Populating the Text Field

In the viewDidLoad() method of the UpdateToDoViewController class, populate the text field with the name of the record as shown below.

Step 5: Updating the Record

In the cancel(_:) action, we pop the update view controller from the navigation controller's navigation stack.

In the save(_:) action, we first check if the text field is empty and show an alert if it is. If the text field contains a valid value, we update the record's name attribute and pop the view controller from the navigation controller's navigation stack.

The implementation of showAlertWithTitle(_:message:cancelButtonTitle:) is identical to that of the AddToDoViewController class.

This is all it takes to update a record using Core Data. Run the application to verify that everything is working. The fetched results controller automatically detects the change and notifies its delegate, the ViewController instance. The ViewController object, on its turn, updates the table view to reflect the change. It's that easy.

2. Updating a Record's State

Step 1: Updating ToDoCell

When a user taps the button on the right of a ToDoCell, the item's state needs to change. To accomplish this, we first need to update the ToDoCell class. Open ToDoCell.swift and add a typealias for a handler named ToDoCellDidTapButtonHandler. Next, declare a property, didTapButtonHandler, of type ToDoCellDidTapButtonHandler?.

In the class's awakeFromNib() method, we invoke a helper method, setupView(), to setup the table view cell.

In setupView(), we configure the doneButton object by setting images for each state of the button and adding the table view cell as a target. When the user taps the button, the table view cell is sent a message of didTapButton(_:) in which we invoke the didTapButtonHandler closure. You'll see in a moment how convenient this pattern is. The images are included in the source files of this tutorial, which you can find on GitHub.

Step 2: Updating ViewController

Thanks to the NSFetchedResultsController class and the foundation we've laid, we only need to update the configureCell(_:atIndexPath:) method in the ViewController class.

Step 3: Saving Changes

You may be wondering why we aren't saving the managed object context. Won't we lose the changes we've made if we don't commit the changes to the persistent store? Yes and no.

It is true that we need to write the changes of the managed object context to the backing store at some point. If we don't, the user will lose some of its data. However, there's no need to save the changes of a managed object context every time we make a change.

A better approach is to save the managed object context the moment the application moves to the background. We can do this in the applicationDidEnterBackground(_:) method of the UIApplicationDelegate protocol. Open AppDelegate.swift and implement applicationDidEnterBackground(_:) as shown below.

However, this doesn't work if the application is force quit by the user. It's therefore a good idea to also save the managed object context when the application is terminated. The applicationWillTerminate(_:) method is another method of the UIApplicationDelegate protocol that notifies the application's delegate when the application is about to be terminated.

Note that we have duplicate code in applicationDidEnterBackground(_:) and applicationWillTerminate(_:). Let's be smart and create a helper method to save the managed object context and call this helper method in both delegate methods.

3. Deleting Records

You'll be surprised by how few lines it takes to delete records using the NSFetchedResultsController class. Start by implementing the tableView(_:canEditRowAtIndexPath:) method of the UITableViewDataSource protocol.

The second method of the UITableViewDataSource protocol that we need to implement is tableView(_:commitEditingStyle:forRowAtIndexPath:). In this method, we fetch the managed object the user has selected for deletion and pass it to the deleteObject(_:) method of the managed object context of the fetched results controller.

Because we've already implemented the NSFetchedResultsControllerDelegate protocol, the user interface is automatically updated, animations included.

Conclusion

I hope you agree that the NSFetchedResultsController class is a very convenient member of the Core Data framework. If you understand the basics of the Core Data framework, then it's not difficult to get up to speed with this class. I encourage you to further explore its API to find out what else it can do for you.

2015-11-13T17:45:09.000Z2015-11-13T17:45:09.000ZBart Jacobs

Core Data and Swift: More NSFetchedResultsController

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-25078

In this tutorial, we continue our exploration of the NSFetchedResultsController class by adding the ability to update and delete to-do items. You'll notice that updating and deleting to-do items is surprisingly easy thanks to the groundwork we laid in the previous tutorial.

Prerequisites

What I cover in this series on Core Data is applicable to iOS 7+ and OS X 10.10+, but the focus will be on iOS. In this series, I will work with Xcode 7.1 and Swift 2.1. If you prefer Objective-C, then I recommend reading my earlier series on the Core Data framework.

1. Updating a Record's Name

Step 1: Create View Controller

Start by creating a new UIViewController subclass named UpdateToDoViewController. In UpdateToDoViewController.swift, declare an outlet, textField of type UITextField!, and two properties, managedObjectContext of type NSManagedObjectContext! and record of type NSManagedObject!. Add an import statement for the Core Data framework at the top.

Next, create two actions, cancel(_:) and save(_:). Their implementations can remain empty for the time being.

Step 2: Update Storyboard

Open the main storyboard, Main.storyboard, add a new view controller object, and set its class to UpdateToDoViewController in the Identity Inspector. Press Control and drag from the prototype cell in the ViewController instance to the UpdateToDoViewController instance. Select Selection Segue > Show from the menu that appears and, in the Attributes Inspector, set the segue's identifier to SegueUpdateToDoViewController.

Add a UITextField object to the view of the UpdateToDoViewController object and configure it just like we did with the text field of the AddToDoViewController class. Don't forget to connect the view controller's outlet with the text field.

As in the AddToDoViewController class, add two bar button items to the view controller's navigation bar, set their identities to Cancel and Save respectively, and connect each bar button item to the corresponding action in the Connections Inspector.

Updating the Storyboard

Step 3: Passing a Reference

We also need to make a few changes to the ViewController class. Let's start by updating prepareForSegue(_:sender:), we fetch the record that corresponds with the user's selection and pass it to the UpdateToDoViewController instance.

To finish, we implement the tableView(_:didSelectRowAtIndexPath:) method of the UITableViewDelegate protocol. In this method, we deselect the row the user tapped.

Step 4: Populating the Text Field

In the viewDidLoad() method of the UpdateToDoViewController class, populate the text field with the name of the record as shown below.

Step 5: Updating the Record

In the cancel(_:) action, we pop the update view controller from the navigation controller's navigation stack.

In the save(_:) action, we first check if the text field is empty and show an alert if it is. If the text field contains a valid value, we update the record's name attribute and pop the view controller from the navigation controller's navigation stack.

The implementation of showAlertWithTitle(_:message:cancelButtonTitle:) is identical to that of the AddToDoViewController class.

This is all it takes to update a record using Core Data. Run the application to verify that everything is working. The fetched results controller automatically detects the change and notifies its delegate, the ViewController instance. The ViewController object, on its turn, updates the table view to reflect the change. It's that easy.

2. Updating a Record's State

Step 1: Updating ToDoCell

When a user taps the button on the right of a ToDoCell, the item's state needs to change. To accomplish this, we first need to update the ToDoCell class. Open ToDoCell.swift and add a typealias for a handler named ToDoCellDidTapButtonHandler. Next, declare a property, didTapButtonHandler, of type ToDoCellDidTapButtonHandler?.

In the class's awakeFromNib() method, we invoke a helper method, setupView(), to setup the table view cell.

In setupView(), we configure the doneButton object by setting images for each state of the button and adding the table view cell as a target. When the user taps the button, the table view cell is sent a message of didTapButton(_:) in which we invoke the didTapButtonHandler closure. You'll see in a moment how convenient this pattern is. The images are included in the source files of this tutorial, which you can find on GitHub.

Step 2: Updating ViewController

Thanks to the NSFetchedResultsController class and the foundation we've laid, we only need to update the configureCell(_:atIndexPath:) method in the ViewController class.

Step 3: Saving Changes

You may be wondering why we aren't saving the managed object context. Won't we lose the changes we've made if we don't commit the changes to the persistent store? Yes and no.

It is true that we need to write the changes of the managed object context to the backing store at some point. If we don't, the user will lose some of its data. However, there's no need to save the changes of a managed object context every time we make a change.

A better approach is to save the managed object context the moment the application moves to the background. We can do this in the applicationDidEnterBackground(_:) method of the UIApplicationDelegate protocol. Open AppDelegate.swift and implement applicationDidEnterBackground(_:) as shown below.

However, this doesn't work if the application is force quit by the user. It's therefore a good idea to also save the managed object context when the application is terminated. The applicationWillTerminate(_:) method is another method of the UIApplicationDelegate protocol that notifies the application's delegate when the application is about to be terminated.

Note that we have duplicate code in applicationDidEnterBackground(_:) and applicationWillTerminate(_:). Let's be smart and create a helper method to save the managed object context and call this helper method in both delegate methods.

3. Deleting Records

You'll be surprised by how few lines it takes to delete records using the NSFetchedResultsController class. Start by implementing the tableView(_:canEditRowAtIndexPath:) method of the UITableViewDataSource protocol.

The second method of the UITableViewDataSource protocol that we need to implement is tableView(_:commitEditingStyle:forRowAtIndexPath:). In this method, we fetch the managed object the user has selected for deletion and pass it to the deleteObject(_:) method of the managed object context of the fetched results controller.

Because we've already implemented the NSFetchedResultsControllerDelegate protocol, the user interface is automatically updated, animations included.

Conclusion

I hope you agree that the NSFetchedResultsController class is a very convenient member of the Core Data framework. If you understand the basics of the Core Data framework, then it's not difficult to get up to speed with this class. I encourage you to further explore its API to find out what else it can do for you.

2015-11-13T17:45:09.000Z2015-11-13T17:45:09.000ZBart Jacobs

Up and Running With Realm for Android

$
0
0

Introduction

If you have been keeping up with the latest trends in Android development, you’ve probably heard of Realm. Realm is a lightweight database that can replace both SQLite and ORM libraries in your Android projects.

Compared to SQLite, Realm is faster and has lots of modern features, such as JSON support, a fluent API, data change notifications, and encryption support, all of which make life easier for Android developers.

In this quick tip, you are going to learn the basics of Realm for Android. In this tutorial, I will be useing Realm v0.84.1.

1. Adding Realm to a Project

To use Realm in an Android project, you need to add it as a compile dependency in the app module’s build.gradle file.

2. Creating a Realm

A Realm is similar to a SQLite database. It has a file associated with it, which, once created, will persist on Android’s file system.

To create a new Realm, you can call the static Realm.getInstance method from inside any Activity.

Note that calling Realm.getInstance, without passing a RealmConfiguration to it, results in the creation of a Realm file called default.realm.

If you want to add another Realm to your app, you must use a RealmConfiguration.Builder object and give the Realm file a unique name.

3. Creating a RealmObject

Any JavaBean can be stored in a Realm once it extends the RealmObject class. If you are wondering what a JavaBean is, it is simply a Java class that is serializable, has a default constructor, and has getter/setter methods for its member variables. For example, instances of the following class can be easily stored in a Realm:

If you want to use a member variable of a RealmObject as a primary key, you can use the @PrimaryKey annotation. For example, here’s how you would add a primary key called code to the Country class:

4. Creating Transactions

While reading data from a Realm is very simple, as you will see in the next step, writing data to it is slightly more complex. Realm is ACID compliant and to ensure atomicity and consistency, Realm forces you to execute all write operations inside a transaction.

To start a new transaction, use the beginTransaction method. Similarly, to end the transaction, use the commitTransaction method.

Here’s how you would create and save an instance of the Country class:

You might have noticed that country1 was not created using the constructor of the Country class. For a Realm to manage an instance of a RealmObject, the instance must be created using the createObject method.

If you must use the constructor, don’t forget to use the copyToRealm method of the relevant Realm object before you commit the transaction. Here’s an example:

5. Writing Queries

Realm offers a very intuitive and fluent API for creating queries. To create a query, use the where method of the relevant Realm object and pass the class of the objects you are interested in. After creating the query, you can fetch all results using the findAll method, which returns a RealmResults object. In the following example, we fetch and print all objects of type Country:

Realm offers several aptly named methods, such as beginsWith, endsWith, lesserThan and greaterThan, you can use to filter the results. The following code shows you how you can use the greaterThan method to fetch only those Country objects whose population is greater than 100 million:

If you want the results of the query to be sorted, you can use the findAllSorted method. As its arguments, it takes a String specifying the name of the field to sort by and a boolean specifying the sort order.

Conclusion

In this quick tip, you learned how to use Realm in an Android project. You saw how easy it is to create a Realm database, store data in it, and query it. To learn more about Realm for Android, you can go through its Java documentation.

2015-11-16T15:45:22.000Z2015-11-16T15:45:22.000ZAshraff Hathibelagal

Up and Running With Realm for Android

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-25241

Introduction

If you have been keeping up with the latest trends in Android development, you’ve probably heard of Realm. Realm is a lightweight database that can replace both SQLite and ORM libraries in your Android projects.

Compared to SQLite, Realm is faster and has lots of modern features, such as JSON support, a fluent API, data change notifications, and encryption support, all of which make life easier for Android developers.

In this quick tip, you are going to learn the basics of Realm for Android. In this tutorial, I will be useing Realm v0.84.1.

1. Adding Realm to a Project

To use Realm in an Android project, you need to add it as a compile dependency in the app module’s build.gradle file.

2. Creating a Realm

A Realm is similar to a SQLite database. It has a file associated with it, which, once created, will persist on Android’s file system.

To create a new Realm, you can call the static Realm.getInstance method from inside any Activity.

Note that calling Realm.getInstance, without passing a RealmConfiguration to it, results in the creation of a Realm file called default.realm.

If you want to add another Realm to your app, you must use a RealmConfiguration.Builder object and give the Realm file a unique name.

3. Creating a RealmObject

Any JavaBean can be stored in a Realm once it extends the RealmObject class. If you are wondering what a JavaBean is, it is simply a Java class that is serializable, has a default constructor, and has getter/setter methods for its member variables. For example, instances of the following class can be easily stored in a Realm:

If you want to use a member variable of a RealmObject as a primary key, you can use the @PrimaryKey annotation. For example, here’s how you would add a primary key called code to the Country class:

4. Creating Transactions

While reading data from a Realm is very simple, as you will see in the next step, writing data to it is slightly more complex. Realm is ACID compliant and to ensure atomicity and consistency, Realm forces you to execute all write operations inside a transaction.

To start a new transaction, use the beginTransaction method. Similarly, to end the transaction, use the commitTransaction method.

Here’s how you would create and save an instance of the Country class:

You might have noticed that country1 was not created using the constructor of the Country class. For a Realm to manage an instance of a RealmObject, the instance must be created using the createObject method.

If you must use the constructor, don’t forget to use the copyToRealm method of the relevant Realm object before you commit the transaction. Here’s an example:

5. Writing Queries

Realm offers a very intuitive and fluent API for creating queries. To create a query, use the where method of the relevant Realm object and pass the class of the objects you are interested in. After creating the query, you can fetch all results using the findAll method, which returns a RealmResults object. In the following example, we fetch and print all objects of type Country:

Realm offers several aptly named methods, such as beginsWith, endsWith, lesserThan and greaterThan, you can use to filter the results. The following code shows you how you can use the greaterThan method to fetch only those Country objects whose population is greater than 100 million:

If you want the results of the query to be sorted, you can use the findAllSorted method. As its arguments, it takes a String specifying the name of the field to sort by and a boolean specifying the sort order.

Conclusion

In this quick tip, you learned how to use Realm in an Android project. You saw how easy it is to create a Realm database, store data in it, and query it. To learn more about Realm for Android, you can go through its Java documentation.

2015-11-16T15:45:22.000Z2015-11-16T15:45:22.000ZAshraff Hathibelagal

Core Data and Swift: Migrations

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-25084

In the previous articles of this series, we've encountered an annoying issue that we need to address. Whenever we modify the data model of a Core Data application, the persistent store becomes incompatible with the data model. The result is a crash on launch, rendering the application unusable, a serious problem if this happens to an application in the App Store.

Our application crashes because we invoke abort if adding the persistent store to the persistent store coordinator is unsuccessful. To be clear, the abort function causes the application to terminate immediately.

However, there is no need to terminate our application, let alone crash it. If Core Data tells us the data model and persistent store are incompatible, then it's up to us to resolve that.

In this article, we'll discuss two options to recover from such a situation, migrating the persistent store and creating a new persistent store that is compatible with the modified data model.

1. The Problem

Let me first clarify the problem that we're trying to solve. Download the sample project we created in the previous article and run it in the simulator. The application should run and work just fine.

Open Done.xcdatamodeld and add an attribute updatedAt of type Date to the Item entity. Run the application one more time and notice how the application crashes as soon as it's launched. Luckily, Core Data gives us a clue as to what went wrong. Take a look at the output in Xcode's console.

Near the end, Core Data tells us that the data model that was used to open the persistent store is incompatible with the data model that was used to create the persistent store. Wait. What?

When we launched the application for the first time, Core Data created a SQLite database based on the data model. However, because we changed the data model by adding an attribute to the Item entity, updatedAt, Core Data no longer understands how it should store Item records in the SQLite database. In other words, the modified data model is no longer compatible with the persistent store, the SQLite database, it created earlier.

2. The Solution

Fortunately for us, a few clever engineers at Apple have created a solution to safely modify a data model without running into compatibility issues. To solve the problem we're facing, we need to find a way to tell Core Data how one version of the data model relates to another version. That's correct, versioning the data model is part of the solution.

With that information, Core Data can understand how the persistent store needs to be updated to be compatible with the modified data model, that is, the new version of the data model. In other words, we need to hand Core Data the necessary information to migrate the persistent store from one version of the data model to another.

3. Migrations

There are two types of migrations, lightweight and heavy migrations. The words lightweight and heavy are pretty descriptive, but it's important that you understand how Core Data handles each type of migration.

Lightweight Migrations

Lightweight migrations require very little work from your part, the developer. I strongly recommend that you choose a lightweight migration over a heavy migration whenever you can. The cost of a lightweight migration is substantially lower than that of a heavy migration.

Of course, the flip side of lightweight migrations is that they are less powerful than heavy migrations. The changes you can make to a data model with lightweight migrations are limited. 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.

Lightweight migrations are ideal for expanding the data model, adding attributes and entities. If you plan to modify relationships or change attribute types, then you're in for a wild ride with heavy migrations.

Heavy Migrations

Heavy migrations are a bit trickier. Let me rephrase that. Heavy migrations are a pain in the neck and you should try to avoid them if possible. Heavy migrations are powerful, but that power comes at a cost. Heavy migrations require a lot of work and testing to make sure the migration completes successfully and, more importantly, without data loss.

We enter the world of heavy migrations if 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. Because heavy migrations are a complex topic, we won't cover it in this series.

4. Versioning

If you've worked with Ruby on Rails or any other framework that supports migrations, then Core Data migrations will make a lot of sense to you. The idea is simple but powerful. Core Data allows us to version the data model and this enables us to safely modify the data model. Core Data inspects the versioned data model to understand how the persistent store relates to the data model. By looking at the versioned data model, it also knows if the persistent store needs to be migrated before it can be used with the current version of the data model.

Versioning and migrations go hand in hand. If you wish to understand how migrations work, you'll first need to understand how to version the Core Data data model. Let's revisit the to-do application we created in the previous article. As we saw earlier, adding an attribute, updatedAt, to the Item entity results in the persistent store being incompatible with the modified data model. We now understand the cause of this.

Let's start with a clean slate by opening Done.xcdatamodeld and removing the updatedAt attribute from the Item entity. It's time to create a new version of the data model.

With the data model selected, choose Add Model Version... from the Editor menu. Xcode will ask you to name the new data model version and, more importantly, on which version the new version should be based. To ensure Core Data can migrate the persistent store for us, it's important that you choose the previous version of the data model. In this example, we have only one choice.

Adding a Model Version

The result of this action is that we can now see three data model files in the Project Navigator. There is one top level data model with a .xcdatamodeld extension and two children with a .xcdatamodel extension.

Data Model Versions

You can see the .xcdatamodeld file as a package for the versions of the data model, with each version represented by an .xcdatamodel file. You can verify this by right-clicking the .xcdatamodeld file and selecting Show in Finder. This will take you to the data model in the Xcode project. You should see the two versions of the data model, Done.xcdatamodel and Done 2.xcdatamodel.

Have you noticed in the Project Navigator that one of the versions has a green checkmark? This checkmark indicates what the current model version is, Done.xcdatamodel in this example. In other words, even though we've created a new version of the data model, it isn't put to use by our application yet. Before we change this, though, we need to tell Core Data what it should do with the versioned data model.

We need to tell Core Data how to migrate the persistent store for the data model. We do this when we add the persistent store to the persistent store coordinator in AppDelegate.swift. In the implementation of the persistentStoreCoordinator property, we create the persistent store coordinator and add a persistent store to it by invoking addPersistentStoreWithType(_:configuration:URL:options:). This should feel familiar by now.

The fourth parameter of this method is a dictionary of options, which is currently nil. This dictionary of options includes instructions for Core Data. It gives us the opportunity to tell the persistent store coordinator how it should migrate the persistent store that we want to add to it.

Take a look at the following code snippet in which we pass a dictionary of options with two key-value pairs.

The first key, NSMigratePersistentStoresAutomaticallyOption, tells Core Data that we'd like it to attempt to migrate the persistent store for us. The second key, NSInferMappingModelAutomaticallyOption, instructs Core Data to infer the mapping model for the migration. This is exactly what we want. It should work without issues as long as we're dealing with lightweight migrations.

With this change, we are ready to migrate the data model to the new version we created a few moments ago. Start by selecting the new version, Done 2.xcdatamodel, and add a new attribute updatedAt of type Date to the Item entity.

We also need to mark the new data model version as the version to use by Core Data. Select Done.xcdatamodeld in the Project Navigator and open the File Inspector on the right. In the section Model Version, set Current to Done 2.

Updating the Model Version

In the Project NavigatorDone 2.xcdatamodel should now have a green checkmark instead of Done.xcdatamodel.

Versioning the Data Model

With this change, you can safely build and run the application. If you've followed the above steps, Core Data should automatically migrate the persistent store for you by inferring the mapping model based on the versioned data model.

Note that there are a few caveats you should be aware of. If you run into a crash, then you've done something wrong. For example, if you've set the data model version to Done 2.xcdatamodel, run the application, and then make changes to Done 2.xcdatamodel, then you'll most likely run into a crash due to the persistent store being incompatible with the data model. Lightweight migrations are relatively powerful and they are easy to implement, but that doesn't mean you can modify the data model at any time.

The data layer of a software project requires care, attention, and preparation. Migrations are great, but they should be used sparingly. Crashes are no problem during development, but they are catastrophic in production. In the next section, we take a closer look at what this means and how to prevent crashes due to a problematic migration.

5. Avoiding Crashes

I have never come in a situation that warranted calling abort in production and it pains me when I browse a project in which Apple's default implementation for setting up the Core Data stack is used, in which abort is called when adding a persistent store is unsuccessful.

Avoiding abort is not that difficult, but it requires a few lines of code and informing the user about what went wrong in case something does go wrong. Developers are only human and we all make mistakes, but that doesn't mean you should throw in the towel and call abort.

Step 1: Getting Rid of abort

Start by opening AppDelegate.swift and remove the line in which we call abort. That's the first step to a happy user.

Step 2: Moving the Incompatible Store

If Core Data detects that the persistent store is incompatible with the data model, we first move the incompatible store to a safe location. We do this to make sure the user's data isn't lost. Even if the data model is incompatible with the persistent store, you may be able to recover data form it. Take a look at the updated implementation of the persistentStoreCoordinator property in AppDelegate.swift.

Note that I've changed the value of URLPersistentStore, the location of the persistent store. It points to a directory in the Documents directory in the application's sandbox. The implementation of applicationStoresDirectory(), a helper method, is straightforward as you can see below. It's certainly more verbose than in Objective-C. Also note that I force unwrap the result of path() of the URL constant, because we can safely assume that there's an application support directory in the application's sandbox, both on iOS and on OS X.

If the persistent store coordinator is unable to add the existing persistent store at URLPersistentStore, we move the persistent store to a separate directory. To do that, we make use of two more helper methods, applicationIncompatibleStoresDirectory() and nameForIncompatibleStore(). The implementation of applicationIncompatibleStoresDirectory() is similar to that of applicationStoresDirectory().

In nameForIncompatibleStore(), we generate a name for the incompatible store based on the current date and time to avoid naming collisions.

Step 3: Creating a New Persistent Store

It's time to create a new persistent store to finish the setup of the Core Data stack. The next few lines should look very familiar by now.

If Core Data is unable to create a new persistent store, then there are more serious problems that are not related to the data model being incompatible with the persistent store. If you do run into this issue, then double-check the value of URLPersistentStore.

Step 4: Notify the User

This step is probably the most important one in terms of creating a user friendly application. Losing the user's data is one thing, but pretending that nothing happened isn't nice. How would you feel if an airline lost your luggage, pretending as if nothing happened.

If Core Data was unable to migrate the persistent store using the data model, we remember this by setting a key-value pair in the application's user defaults database. We look for this key-value pair in the viewDidLoad() method of the ViewController class.

The implementation of showAlertWithTitle(_:message:cancelButtonTitle:) is similar to the one we've seen in the AddToDoViewController. Note that we remove the key-value pair when the user taps the button of the alert.

We show an alert to the user, but it's a good idea to take it a few steps further. For example, you could urge them to contact support and you can even implement a feature that lets them send you the corrupt store. The latter is very useful for debugging the issue.

Step 5: Testing

Persisting data is an important aspect of most applications. It's therefore important to properly test what we've implemented in this article. To test our recovery strategy, run the application in the simulator and double-check that the persistent store was successfully created in the Application Support directory, in the Stores subdirectory.

Add a new attribute to the Item entity in Done 2.xcdatamodel and run the application one more time. Because the existing persistent store is now incompatible with the data model, the incompatible persistent store is moved to the Incompatible subdirectory and a new persistent store is created. You should also see an alert, informing the user about the problem.

Informing The User

Conclusion

Migrations are an important topic if you plan to make extensive use of Core Data. Migrations let you safely modify your application's data model and, in the case of lightweight migrations, without much overhead.

In the next article, we focus on subclassing NSManagedObject. If a Core Data project has any kind of complexity, then subclassing NSManagedObject is the way to go.

2015-11-18T17:45:22.000Z2015-11-18T17:45:22.000ZBart Jacobs
Viewing all 1836 articles
Browse latest View live