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

Core Data and Swift: Subclassing NSManagedObject

$
0
0

1. Introduction

Earlier in this series, we created Done, a simple application to learn more about the NSFetchedResultsController class. In that project, we used key value coding (KVC) and key value observing (KVO) to create and update records. This works fine, but from the moment your project has any kind of complexity, you'll quickly run into issues. Not only is the KVC syntax verbose, valueForKey(_:) and setValue(_:forKey:), it may also introduce errors that are the result of typos. The following code snippet illustrates this problem well.

Each statement in the above code snippet returns a different result. In fact, every statement will result in an exception apart from the third statement, which uses the correct key as specified in the data model.

The above problem is easily solved by using string constants, but that's not the point I'm trying to make. Key value coding is great, but it is verbose and difficult to read if you're used to Swift's dot syntax. To make working with NSManagedObject instances easier, it's better to create an NSManagedObject subclass for each entity of the data model and that's what you'll learn in this article.

2. Subclassing NSManagedObject

To save some time, we're going to revisit Done, the application we created earlier in this series. Download it from GitHub and open it in Xcode.

Creating an NSManagedObject subclass is very easy. While it's possible to manually create an NSManagedObject subclass for an entity, it's easier to let Xcode do the work for you.

Open the data model of the project, Done.xcdatamodeld, and select the Item entity. Select New > File... from Xcode's File menu, choose the NSManagedObject subclass template from the Core Data section, and click Next.

Creating a NSManagedObject Subclass

Check the checkbox of the correct data model, Done, from the list of data models and click Next.

Selecting the Data Model

In the next step, you are asked to select the entities for which you want to create an NSManagedObject subclass. Check the checkbox of the Item entity and click Next.

Selecting the Entities

Choose a location to store the class files of the NSManagedObject subclass and make sure that Use scalar properties for primitive data types is checked. When working with Objective-C, this option is an important consideration. But for Swift, it's best to check it as it makes your code more readable and less complex. Don't forget to set Language to Swift and click Create to create the NSManagedObject subclass for the Item entity.

Configuring The NSManagedObject Subclass

3. NSManagedObject Anatomy

Navigate to the files Xcode created for you and take a look at their contents. Xcode should have create two files for you:

  • Item.swift
  • Item+CoreDataProperties.swift

If you're using an earlier version of Xcode, then Xcode may have created only one file. I recommend using Xcode 7—preferably Xcode 7.1 or higher—to follow along. The contents of Item.swift should be pretty easy to understand.

As you can see, Xcode has created a class for us, Item, that inherits from NSManagedObject. The comment Xcode has added to the class implementation is important. If you wish to add functionality to the class, you should add it here. Let's now take a look at the contents of Item+CoreDataProperties.swift.

There are a number of important details and a few new concepts. The first thing to notice is that this file defines an extension on the Item class. The extension declares three properties that correspond to the attributes of the Item entity, which we defined in the data model. The @NSManaged attribute is similar to the @dynamic attribute in Objective-C. The @NSManaged attribute tells the compiler that the storage and implementation of these properties will be provided at runtime. While this may sound great, Apple's documentation clearly states that @NSManaged should only be used in the context of Core Data.

If this sounds a bit confusing, then remember that @NSManaged is required for Core Data to do its work and the @NSManaged attribute should only be used for NSManagedObject subclasses.

What happens if you modify an entity and generate the files for the entity's NSManagedObject subclass again? That's a good question and Xcode warns you about this scenario. At the top of Item+CoreDataProperties.swift, below the copyright statement, Xcode has added the a comment for clarification.

Whenever you generate the files for an entity, Xcode will only replace the files of the extension. In other words, if you add an attribute to the Item entity and generate the files for the NSManagedObject subclass, Xcode replaces Item+CoreDataProperties.swift, leaving Item.swift untouched. That's why Xcode tells you to add functionality in Item.swift. This is very important to keep in mind.

The types of the properties may be a bit surprising. The name property is of type NSString?, because the attribute is marked as optional in the data model. The createdAt property is of type NSTimeInterval, because we checked the checkbox Use scalar properties for primitive data types. The same is true for the done property, which is of type Bool.

If we hadn't checked the checkbox, the createdAt property would be of type NSDate? and the done property would be of type NSNumber?. While it may be easier to use NSDate instances, it's certainly less practical to work with NSNumber objects if all you want is get and set boolean values.

4. Updating the Project

With the Item class ready to use, it's time to update the project by replacing any occurrences of valueForKey(_:) and setValue(_:forKey:).

ViewController

Open the implementation file of the ViewController class, navigate to the configureCell(_:atIndexPath:), and update the implementation as shown below.

We've made four changes. We first changed the type of the record variable to Item. The objectAtIndexPath(_:) method of the NSFetchedResultsController class returns an AnyObject instance. However, because we know the fetched results controller returns an Item instance we force downcast the result using the as! operator.

We also substitute the valueForKey(_:) calls. Instead, we use the properties of the record object, name and done. Thanks to Swift's dot syntax, the result is very legible.

To update the record, we no longer call setValue(_:forKey:). Instead, we use the dot syntax to set the record's done property. I'm sure you agree that this is much more elegant than using straight key value coding. We also don't need optional binding for the done property since the done property is of type Bool.

Remember that KVC and KVO remain an integral part of Core Data. Core Data uses valueForKey(_:) and setValue(_:forKey:) under the hood to get the job done.

AddToDoViewController

We also need to make a few changes in the AddToDoViewController class. In the save(_:) method, we first need to update the initialization of the NSManagedObject instance. Instead of initializing an NSManagedObject instance, we create a Item instance.

To populate the record, we use the dot syntax instead of the setValue(_:forKey:) method as shown below.

UpdateToDoViewController

The last class we need to update is the UpdateToDoViewController class. Let's start by changing the type of the record property to Item!.

This change will result in a warning in the ViewController class. To see what's wrong, open ViewController.swift and navigate to the prepareForSegue(_:sender:) method.

We ask the fetched results controller for the record at the selected index path. The type of the record variable is NSManagedObject, but the UpdateToDoViewController class expects an Item instance. The solution is very simple as you can see below.

Head back to the UpdateToDoViewController class and update the viewDidLoad() method as shown below.

We also need to update the save(_:) method, in which we replace setValue(_:forKey:) with the dot syntax.

Build the project and run the application in the simulator to see if everything is still working as expected.

5. Relationships

The current data model doesn't contain any relationships, but let's add a few to see how an NSManagedObject subclass with relationships looks like. As we've seen in the previous article of this series, we first need to create a new version of the data model. Select the data model in the Project Navigator and choose Add Model Version... from the Editor menu. Set Version name to Done 2 and base the model on the current data model, Done. Click Finish to create the new data model version.

Open Done 2.xcdatamodel, create a new entity named User, and add an attribute name of type String. Add a relationship items and set the destination to Item. Leave the inverse relationship blank for now. With the items relationship selected, open the Data Model Inspector on the right and set the relationship type to To Many. A user can have more than one item associated with them.

Adding User Entity

Select the Item entity, create a relationship user, and set the destination to User. Set the inverse relationship to items. This will automatically set the inverse relationship of the items relationship of the User entity. Note that the user relationship is not optional.

Updating Item Entity

Before we create the NSManagedObject subclasses for both entities, we need to tell the data model which data model version it should use. Select Done.xcdatamodeld, open the File Inspector on the right, and set the current model version to Done 2. When you do this, double-check that you've selected Done.xcdatamodeld, not Done.xcdatamodel.

Select New > File... from the File menu and choose the NSManagedObject subclass template from the Core Data section. From the list of data models, select Done 2.

Selecting Data Model Version

Select both entities from the list of entities. Because we've modified the Item entity, we need to regenerate the extension for the corresponding NSManagedObject subclass.

Selecting Entities

Item

Let's first take a look at the changes of the newly generated Item class. As you can see below, the extension on the Item class (Item+CoreDataProperties.swift) contains one additional property, user of type User?.

This is what a To One relationship looks like in an NSManagedObject subclass. Xcode is smart enough to infer that the type of the user property is User?, the NSManagedObject subclass we created a moment ago. Even though the user relationship is marked as not optional in the data model, the type of the user property is User?. It's not clear whether this is intentional or a bug in Xcode.

The implementation of the Item class (Item.swift) hasn't been updated by Xcode. Remember that Xcode doesn't touch this file if it already exists.

User

With what we've learned so far, the User class is easy to understand. Take a look at the extension of the User class (User+CoreDataProperties.swift). The first thing you'll notice is that the type of the items property is NSSet?. This shouldn't be a surprise, because we already knew that Core Data uses sets, instances of the NSSet class, for storing the members of a To Many relationship. Because the relationship is marked as optional in the data model, the type is NSSet?.

That's how easy it is to work with relationships in NSManagedObject subclasses.

6. Migrations

If you build the project and run the application in the simulator, you'll notice that the application crashes. The output in Xcode's console tells us that the data model used to open the persistent store is not compatible with the one that was used to create it. The reason of this problem is explained in detail in the previous article of this series. If you want to learn more about migrations and how to safely modify the data model, then I suggest you read that article.

Conclusion

Subclassing NSManagedObject is very common when working with Core Data. Not only does it add type safety, it also makes working with relationships much easier.

In the next installment of this series, we take a closer look at Core Data and concurrency. Concurrency is a tricky concept in almost any programming language, but knowing which pitfalls to avoid, makes it much less scary.

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

Core Data and Swift: Subclassing NSManagedObject

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

1. Introduction

Earlier in this series, we created Done, a simple application to learn more about the NSFetchedResultsController class. In that project, we used key value coding (KVC) and key value observing (KVO) to create and update records. This works fine, but from the moment your project has any kind of complexity, you'll quickly run into issues. Not only is the KVC syntax verbose, valueForKey(_:) and setValue(_:forKey:), it may also introduce errors that are the result of typos. The following code snippet illustrates this problem well.

Each statement in the above code snippet returns a different result. In fact, every statement will result in an exception apart from the third statement, which uses the correct key as specified in the data model.

The above problem is easily solved by using string constants, but that's not the point I'm trying to make. Key value coding is great, but it is verbose and difficult to read if you're used to Swift's dot syntax. To make working with NSManagedObject instances easier, it's better to create an NSManagedObject subclass for each entity of the data model and that's what you'll learn in this article.

2. Subclassing NSManagedObject

To save some time, we're going to revisit Done, the application we created earlier in this series. Download it from GitHub and open it in Xcode.

Creating an NSManagedObject subclass is very easy. While it's possible to manually create an NSManagedObject subclass for an entity, it's easier to let Xcode do the work for you.

Open the data model of the project, Done.xcdatamodeld, and select the Item entity. Select New > File... from Xcode's File menu, choose the NSManagedObject subclass template from the Core Data section, and click Next.

Creating a NSManagedObject Subclass

Check the checkbox of the correct data model, Done, from the list of data models and click Next.

Selecting the Data Model

In the next step, you are asked to select the entities for which you want to create an NSManagedObject subclass. Check the checkbox of the Item entity and click Next.

Selecting the Entities

Choose a location to store the class files of the NSManagedObject subclass and make sure that Use scalar properties for primitive data types is checked. When working with Objective-C, this option is an important consideration. But for Swift, it's best to check it as it makes your code more readable and less complex. Don't forget to set Language to Swift and click Create to create the NSManagedObject subclass for the Item entity.

Configuring The NSManagedObject Subclass

3. NSManagedObject Anatomy

Navigate to the files Xcode created for you and take a look at their contents. Xcode should have create two files for you:

  • Item.swift
  • Item+CoreDataProperties.swift

If you're using an earlier version of Xcode, then Xcode may have created only one file. I recommend using Xcode 7—preferably Xcode 7.1 or higher—to follow along. The contents of Item.swift should be pretty easy to understand.

As you can see, Xcode has created a class for us, Item, that inherits from NSManagedObject. The comment Xcode has added to the class implementation is important. If you wish to add functionality to the class, you should add it here. Let's now take a look at the contents of Item+CoreDataProperties.swift.

There are a number of important details and a few new concepts. The first thing to notice is that this file defines an extension on the Item class. The extension declares three properties that correspond to the attributes of the Item entity, which we defined in the data model. The @NSManaged attribute is similar to the @dynamic attribute in Objective-C. The @NSManaged attribute tells the compiler that the storage and implementation of these properties will be provided at runtime. While this may sound great, Apple's documentation clearly states that @NSManaged should only be used in the context of Core Data.

If this sounds a bit confusing, then remember that @NSManaged is required for Core Data to do its work and the @NSManaged attribute should only be used for NSManagedObject subclasses.

What happens if you modify an entity and generate the files for the entity's NSManagedObject subclass again? That's a good question and Xcode warns you about this scenario. At the top of Item+CoreDataProperties.swift, below the copyright statement, Xcode has added the a comment for clarification.

Whenever you generate the files for an entity, Xcode will only replace the files of the extension. In other words, if you add an attribute to the Item entity and generate the files for the NSManagedObject subclass, Xcode replaces Item+CoreDataProperties.swift, leaving Item.swift untouched. That's why Xcode tells you to add functionality in Item.swift. This is very important to keep in mind.

The types of the properties may be a bit surprising. The name property is of type NSString?, because the attribute is marked as optional in the data model. The createdAt property is of type NSTimeInterval, because we checked the checkbox Use scalar properties for primitive data types. The same is true for the done property, which is of type Bool.

If we hadn't checked the checkbox, the createdAt property would be of type NSDate? and the done property would be of type NSNumber?. While it may be easier to use NSDate instances, it's certainly less practical to work with NSNumber objects if all you want is get and set boolean values.

4. Updating the Project

With the Item class ready to use, it's time to update the project by replacing any occurrences of valueForKey(_:) and setValue(_:forKey:).

ViewController

Open the implementation file of the ViewController class, navigate to the configureCell(_:atIndexPath:), and update the implementation as shown below.

We've made four changes. We first changed the type of the record variable to Item. The objectAtIndexPath(_:) method of the NSFetchedResultsController class returns an AnyObject instance. However, because we know the fetched results controller returns an Item instance we force downcast the result using the as! operator.

We also substitute the valueForKey(_:) calls. Instead, we use the properties of the record object, name and done. Thanks to Swift's dot syntax, the result is very legible.

To update the record, we no longer call setValue(_:forKey:). Instead, we use the dot syntax to set the record's done property. I'm sure you agree that this is much more elegant than using straight key value coding. We also don't need optional binding for the done property since the done property is of type Bool.

Remember that KVC and KVO remain an integral part of Core Data. Core Data uses valueForKey(_:) and setValue(_:forKey:) under the hood to get the job done.

AddToDoViewController

We also need to make a few changes in the AddToDoViewController class. In the save(_:) method, we first need to update the initialization of the NSManagedObject instance. Instead of initializing an NSManagedObject instance, we create a Item instance.

To populate the record, we use the dot syntax instead of the setValue(_:forKey:) method as shown below.

UpdateToDoViewController

The last class we need to update is the UpdateToDoViewController class. Let's start by changing the type of the record property to Item!.

This change will result in a warning in the ViewController class. To see what's wrong, open ViewController.swift and navigate to the prepareForSegue(_:sender:) method.

We ask the fetched results controller for the record at the selected index path. The type of the record variable is NSManagedObject, but the UpdateToDoViewController class expects an Item instance. The solution is very simple as you can see below.

Head back to the UpdateToDoViewController class and update the viewDidLoad() method as shown below.

We also need to update the save(_:) method, in which we replace setValue(_:forKey:) with the dot syntax.

Build the project and run the application in the simulator to see if everything is still working as expected.

5. Relationships

The current data model doesn't contain any relationships, but let's add a few to see how an NSManagedObject subclass with relationships looks like. As we've seen in the previous article of this series, we first need to create a new version of the data model. Select the data model in the Project Navigator and choose Add Model Version... from the Editor menu. Set Version name to Done 2 and base the model on the current data model, Done. Click Finish to create the new data model version.

Open Done 2.xcdatamodel, create a new entity named User, and add an attribute name of type String. Add a relationship items and set the destination to Item. Leave the inverse relationship blank for now. With the items relationship selected, open the Data Model Inspector on the right and set the relationship type to To Many. A user can have more than one item associated with them.

Adding User Entity

Select the Item entity, create a relationship user, and set the destination to User. Set the inverse relationship to items. This will automatically set the inverse relationship of the items relationship of the User entity. Note that the user relationship is not optional.

Updating Item Entity

Before we create the NSManagedObject subclasses for both entities, we need to tell the data model which data model version it should use. Select Done.xcdatamodeld, open the File Inspector on the right, and set the current model version to Done 2. When you do this, double-check that you've selected Done.xcdatamodeld, not Done.xcdatamodel.

Select New > File... from the File menu and choose the NSManagedObject subclass template from the Core Data section. From the list of data models, select Done 2.

Selecting Data Model Version

Select both entities from the list of entities. Because we've modified the Item entity, we need to regenerate the extension for the corresponding NSManagedObject subclass.

Selecting Entities

Item

Let's first take a look at the changes of the newly generated Item class. As you can see below, the extension on the Item class (Item+CoreDataProperties.swift) contains one additional property, user of type User?.

This is what a To One relationship looks like in an NSManagedObject subclass. Xcode is smart enough to infer that the type of the user property is User?, the NSManagedObject subclass we created a moment ago. Even though the user relationship is marked as not optional in the data model, the type of the user property is User?. It's not clear whether this is intentional or a bug in Xcode.

The implementation of the Item class (Item.swift) hasn't been updated by Xcode. Remember that Xcode doesn't touch this file if it already exists.

User

With what we've learned so far, the User class is easy to understand. Take a look at the extension of the User class (User+CoreDataProperties.swift). The first thing you'll notice is that the type of the items property is NSSet?. This shouldn't be a surprise, because we already knew that Core Data uses sets, instances of the NSSet class, for storing the members of a To Many relationship. Because the relationship is marked as optional in the data model, the type is NSSet?.

That's how easy it is to work with relationships in NSManagedObject subclasses.

6. Migrations

If you build the project and run the application in the simulator, you'll notice that the application crashes. The output in Xcode's console tells us that the data model used to open the persistent store is not compatible with the one that was used to create it. The reason of this problem is explained in detail in the previous article of this series. If you want to learn more about migrations and how to safely modify the data model, then I suggest you read that article.

Conclusion

Subclassing NSManagedObject is very common when working with Core Data. Not only does it add type safety, it also makes working with relationships much easier.

In the next installment of this series, we take a closer look at Core Data and concurrency. Concurrency is a tricky concept in almost any programming language, but knowing which pitfalls to avoid, makes it much less scary.

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

Core Data and Swift: Concurrency

$
0
0

If you're developing a small or simple application, then you probably don't see the benefit of running Core Data operations in the background. However, what would happen if you imported hundreds or thousands of records on the main thread during the first launch of your application? The consequences could be dramatic. For example, your application could be killed by Apple's watchdog for taking too long to launch.

In this article, we take a look at the dangers when using Core Data on multiple threads and we explore several solutions to tackle the problem.

1. Thread Safety

When working with Core Data, it's important to always remember that Core Data isn't thread safe. Core Data expects to be run on a single thread. This doesn't mean that every Core Data operation needs to be performed on the main thread, which is true for UIKit, but it does mean that you need to be mindful which operations are executed on which threads. It also means that you need to be careful how changes from one thread are propagated to other threads.

Working with Core Data on multiple threads is actually very simple from a theoretical point of view. NSManagedObjectNSManagedObjectContext, and NSPersistentStoreCoordinator aren't thread safe. Instances of these classes should only be accessed from the thread they were created on. As you can imagine, this becomes a bit more complex in practice.

NSManagedObject

We already know that NSManagedObject isn't thread safe, but how do you access a record from different threads? An NSManagedObject instance has an objectID property that returns an instance of the NSManagedObjectID class. The NSManagedObjectID class is thread safe and an instance of this class contains all the information a managed object context needs to fetch the corresponding managed object.

In the following code snippet, we ask a managed object context for the managed object that corresponds with objectID. The objectWithID(_:) and existingObjectWithID(_:) methods return a local version—local to the current thread—of the corresponding managed object.

The basic rule to remember is not to pass the NSManagedObject instance from one thread to another. Instead, pass the managed object's objectID and ask the thread's managed object context for a local version of the record.

NSManagedObjectContext

Because the NSManagedObjectContext class isn't thread safe, we could create a managed object context for every thread that interacts with Core Data. This strategy is often referred to as thread confinement.

A common approach is to store the managed object context in the thread's dictionary, a dictionary to store data that is specific to the thread. Take a look at the following example to see how this works in practice.

Not too long ago, Apple recommended this approach. Even though it works fine, there is another and better option that Apple recommends nowadays. We'll look at this option in a few moments.

NSPersistentStoreCoordinator

What about the persistent store coordinator? Do you need to create a separate persistent store coordinator for every thread. While this is possible and one of the strategies Apple used to recommend, this isn't necessary.

The NSPersistentStoreCoordinator class was designed to support multiple managed object contexts, even if those managed object contexts were created on different threads. Because the NSManagedObjectContext class locks the persistent store coordinator while accessing it, it is possible for multiple managed object contexts to use the same persistent store coordinator even if those managed object contexts live on different threads. This makes a multithreaded Core Data setup much more manageable and less complex.

2. Concurrency Strategies

So far, we've learned that you need multiple managed object contexts if you perform Core Data operations on multiple threads. The caveat, however, is that managed object contexts are unaware of each others existence. Changes made to a managed object in one managed object context are not automatically propagated to other managed object contexts. How do we solve this problem?

There are two popular strategies that Apple recommends, notifications and parent-child managed object contexts. Let's look at each strategy and investigate their pros and cons.

The scenario we'll take as an example is an NSOperation subclass that performs work in the background and accesses Core Data on the operation's background thread. This example will show you the differences and advantages of each strategy.

Strategy 1: Notifications

Earlier in this series, I introduced you to the NSFetchedResultsController class and you learned that a managed object context posts three types of notifications:

  • NSManagedObjectContextObjectsDidChangeNotification: This notification is posted when one of the managed objects of the managed object context has changed.
  • NSManagedObjectContextWillSaveNotification: This notification is posted before the managed object context performs a save operation.
  • NSManagedObjectContextDidSaveNotification: This notification is posted after the managed object context performs a save operation.

When a managed object context saves its changes to a persistent store, via the persistent store coordinator, other managed object contexts may want to know about those changes. This is very easy to do and it's even easier to include or merge the changes into another managed object context. Let's talk code.

We create a non-concurrent operation that does some work in the background and needs access to Core Data. This is what the implementation of the NSOperation subclass could look like.

There are a few important details that need to be clarified. We initialize the private managed object context and set its persistent store coordinator property using the mainManagedObjectContext object. This is perfectly fine, because we don't access the mainManagedObjectContext, we only ask it for its reference to the application's persistent store coordinator. We don't violate the thread confinement rule.

It is essential to initialize the private managed object context in the operation's main() method, because this method is executed on the background thread on which the operation runs. Can't we initialize the managed object context in the operation's init(managedObjectContext:) method? The answer is no. The operation's init(managedObjectContext:) method is run on the thread on which the Operation instance is initialized, which is most likely the main thread. This would defeat the purpose of a private managed object context.

In the operation's main() method, we add the Operation instance as an observer of any NSManagedObjectContextDidSaveNotification notifications posted by the private managed object context.

We then do the work the operation was created for and save the changes of the private managed object context, which will trigger a NSManagedObjectContextDidSaveNotification notification. Let's take a look at what happens in the managedObjectContextDidSave(_:) method.

As you can see, its implementation is short and simple. We call mergeChangesFromContextDidSaveNotification(_:) on the main managed object context, passing in the notification object. As I mentioned earlier, the notification contains the changes, inserts, updates, and deletes, of the managed object context that posted the notification.

It is key to call this method on the thread the main managed object context was created on, the main thread. That's why we dispatch this call to the queue of the main thread. To make this easier and more transparant, you can use performBlock(_:) or performBlockAndWait(_:) to ensure merging the changes takes place on the queue of the managed object context. We'll talk more about these methods later in this article.

Putting the Operation class to use is as simple as initializing an instance, passing a managed object context, and adding the operation to an operation queue.

Strategy 2: Parent/Child Managed Object Contexts

Since iOS 6, there's an even better, more elegant strategy. Let's revisit the Operation class and leverage parent/child managed object contexts. The concept behind parent/child managed object contexts is simple but powerful. Let me explain how it works.

A child managed object context is dependent on its parent managed object context for saving its changes to the corresponding persistent store. In fact, a child managed object context doesn't have access to a persistent store coordinator. Whenever a child managed object context is saved, the changes it contains are pushed to the parent managed object context. There's no need to use notifications to manually merge the changes into the main or parent managed object context.

Another benefit is performance. Because the child managed object context doesn't have access to the persistent store coordinator, the changes aren't pushed to the latter when the child managed object context is saved. Instead, the changes are pushed to the parent managed object context, making it dirty. The changes are not automatically propagated to the persistent store coordinator.

Using ParentChild Managed Object Contexts

Managed object contexts can be nested. A child managed object context can have a child managed object context of its own. The same rules apply. However, it's important to remember that the changes that are pushed up to the parent managed object context are not pushed down to any other child managed object contexts. If child A pushes its changes to its parent, then child B is unaware of these changes.

Creating a child managed object context is only slightly different from what we've seen so far. We initialize a child managed object context by invoking init(concurrencyType:). The concurrency type the initializer accepts defines the managed object context's threading model. Let's look at each concurrency type.

  • MainQueueConcurrencyType: The managed object context is only accessible from the main thread. An exception is thrown if you try to access it from any other thread.
  • PrivateQueueConcurrencyType: When creating a managed object context with a concurrency type of PrivateQueueConcurrencyType, the managed object context is associated with a private queue and it can only be accessed from that private queue.
  • ConfinementConcurrencyType: This is the concurrency type that corresponds with the thread confinement concept we explored earlier. If you create a managed object context using init(), the concurrency type of that managed object context is ConfinementConcurrencyTypeApple has deprecated this concurrency type as of iOS 9. This also means that init() is deprecated as of iOS 9.

There are two key methods that were added to the Core Data framework when Apple introduced parent/child managed object contexts, performBlock(_:) and performBlockAndWait(_:). Both methods will make your life much easier. When you call performBlock(_:) on a managed object context and pass in a block of code to execute, Core Data makes sure that the block is executed on the correct thread. In the case of the PrivateQueueConcurrencyType concurrency type, this means that the block is executed on the private queue of that managed object context.

The difference between performBlock(_:) and performBlockAndWait(_:) is simple. The performBlock(_:) method doesn't block the current thread. It accepts the block, schedules it for execution on the correct queue, and continues with the execution of the next statement.

The performBlockAndWait(_:) method, however, is blocking. The thread from which performBlockAndWait(_:) is called waits for the block that is passed to the method to finish before executing the next statement. The advantage is that nested calls to performBlockAndWait(_:) are executed in order.

To end this article, I'd like to refactor the Operation class to take advantage of parent/child managed object contexts. You'll quickly notice that it greatly simplifies the NSOperation subclass we created. The main() method changes quite a bit. Take a look at its updated implementation below.

That's it. The main managed object context is the parent of the private managed object context. Note that we don't set the persistentStoreCoordinator property of the private managed object context and we don't add the operation as an observer for NSManagedObjectContextDidSaveNotification notifications. When the private managed object context is saved, the changes are automatically pushed to its parent managed object context. Core Data ensures that this happens on the correct thread. It's up to the main managed object context, the parent managed object context, to push the changes to the persistent store coordinator.

Conclusion

Concurrency isn't easy to grasp or implement, but it's naive to think that you'll never come across a situation in which you need to perform Core Data operations on a background thread.

2015-11-20T17:45:03.000Z2015-11-20T17:45:03.000ZBart Jacobs

Core Data and Swift: Concurrency

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

If you're developing a small or simple application, then you probably don't see the benefit of running Core Data operations in the background. However, what would happen if you imported hundreds or thousands of records on the main thread during the first launch of your application? The consequences could be dramatic. For example, your application could be killed by Apple's watchdog for taking too long to launch.

In this article, we take a look at the dangers when using Core Data on multiple threads and we explore several solutions to tackle the problem.

1. Thread Safety

When working with Core Data, it's important to always remember that Core Data isn't thread safe. Core Data expects to be run on a single thread. This doesn't mean that every Core Data operation needs to be performed on the main thread, which is true for UIKit, but it does mean that you need to be mindful which operations are executed on which threads. It also means that you need to be careful how changes from one thread are propagated to other threads.

Working with Core Data on multiple threads is actually very simple from a theoretical point of view. NSManagedObjectNSManagedObjectContext, and NSPersistentStoreCoordinator aren't thread safe. Instances of these classes should only be accessed from the thread they were created on. As you can imagine, this becomes a bit more complex in practice.

NSManagedObject

We already know that NSManagedObject isn't thread safe, but how do you access a record from different threads? An NSManagedObject instance has an objectID property that returns an instance of the NSManagedObjectID class. The NSManagedObjectID class is thread safe and an instance of this class contains all the information a managed object context needs to fetch the corresponding managed object.

In the following code snippet, we ask a managed object context for the managed object that corresponds with objectID. The objectWithID(_:) and existingObjectWithID(_:) methods return a local version—local to the current thread—of the corresponding managed object.

The basic rule to remember is not to pass the NSManagedObject instance from one thread to another. Instead, pass the managed object's objectID and ask the thread's managed object context for a local version of the record.

NSManagedObjectContext

Because the NSManagedObjectContext class isn't thread safe, we could create a managed object context for every thread that interacts with Core Data. This strategy is often referred to as thread confinement.

A common approach is to store the managed object context in the thread's dictionary, a dictionary to store data that is specific to the thread. Take a look at the following example to see how this works in practice.

Not too long ago, Apple recommended this approach. Even though it works fine, there is another and better option that Apple recommends nowadays. We'll look at this option in a few moments.

NSPersistentStoreCoordinator

What about the persistent store coordinator? Do you need to create a separate persistent store coordinator for every thread. While this is possible and one of the strategies Apple used to recommend, this isn't necessary.

The NSPersistentStoreCoordinator class was designed to support multiple managed object contexts, even if those managed object contexts were created on different threads. Because the NSManagedObjectContext class locks the persistent store coordinator while accessing it, it is possible for multiple managed object contexts to use the same persistent store coordinator even if those managed object contexts live on different threads. This makes a multithreaded Core Data setup much more manageable and less complex.

2. Concurrency Strategies

So far, we've learned that you need multiple managed object contexts if you perform Core Data operations on multiple threads. The caveat, however, is that managed object contexts are unaware of each others existence. Changes made to a managed object in one managed object context are not automatically propagated to other managed object contexts. How do we solve this problem?

There are two popular strategies that Apple recommends, notifications and parent-child managed object contexts. Let's look at each strategy and investigate their pros and cons.

The scenario we'll take as an example is an NSOperation subclass that performs work in the background and accesses Core Data on the operation's background thread. This example will show you the differences and advantages of each strategy.

Strategy 1: Notifications

Earlier in this series, I introduced you to the NSFetchedResultsController class and you learned that a managed object context posts three types of notifications:

  • NSManagedObjectContextObjectsDidChangeNotification: This notification is posted when one of the managed objects of the managed object context has changed.
  • NSManagedObjectContextWillSaveNotification: This notification is posted before the managed object context performs a save operation.
  • NSManagedObjectContextDidSaveNotification: This notification is posted after the managed object context performs a save operation.

When a managed object context saves its changes to a persistent store, via the persistent store coordinator, other managed object contexts may want to know about those changes. This is very easy to do and it's even easier to include or merge the changes into another managed object context. Let's talk code.

We create a non-concurrent operation that does some work in the background and needs access to Core Data. This is what the implementation of the NSOperation subclass could look like.

There are a few important details that need to be clarified. We initialize the private managed object context and set its persistent store coordinator property using the mainManagedObjectContext object. This is perfectly fine, because we don't access the mainManagedObjectContext, we only ask it for its reference to the application's persistent store coordinator. We don't violate the thread confinement rule.

It is essential to initialize the private managed object context in the operation's main() method, because this method is executed on the background thread on which the operation runs. Can't we initialize the managed object context in the operation's init(managedObjectContext:) method? The answer is no. The operation's init(managedObjectContext:) method is run on the thread on which the Operation instance is initialized, which is most likely the main thread. This would defeat the purpose of a private managed object context.

In the operation's main() method, we add the Operation instance as an observer of any NSManagedObjectContextDidSaveNotification notifications posted by the private managed object context.

We then do the work the operation was created for and save the changes of the private managed object context, which will trigger a NSManagedObjectContextDidSaveNotification notification. Let's take a look at what happens in the managedObjectContextDidSave(_:) method.

As you can see, its implementation is short and simple. We call mergeChangesFromContextDidSaveNotification(_:) on the main managed object context, passing in the notification object. As I mentioned earlier, the notification contains the changes, inserts, updates, and deletes, of the managed object context that posted the notification.

It is key to call this method on the thread the main managed object context was created on, the main thread. That's why we dispatch this call to the queue of the main thread. To make this easier and more transparant, you can use performBlock(_:) or performBlockAndWait(_:) to ensure merging the changes takes place on the queue of the managed object context. We'll talk more about these methods later in this article.

Putting the Operation class to use is as simple as initializing an instance, passing a managed object context, and adding the operation to an operation queue.

Strategy 2: Parent/Child Managed Object Contexts

Since iOS 6, there's an even better, more elegant strategy. Let's revisit the Operation class and leverage parent/child managed object contexts. The concept behind parent/child managed object contexts is simple but powerful. Let me explain how it works.

A child managed object context is dependent on its parent managed object context for saving its changes to the corresponding persistent store. In fact, a child managed object context doesn't have access to a persistent store coordinator. Whenever a child managed object context is saved, the changes it contains are pushed to the parent managed object context. There's no need to use notifications to manually merge the changes into the main or parent managed object context.

Another benefit is performance. Because the child managed object context doesn't have access to the persistent store coordinator, the changes aren't pushed to the latter when the child managed object context is saved. Instead, the changes are pushed to the parent managed object context, making it dirty. The changes are not automatically propagated to the persistent store coordinator.

Using ParentChild Managed Object Contexts

Managed object contexts can be nested. A child managed object context can have a child managed object context of its own. The same rules apply. However, it's important to remember that the changes that are pushed up to the parent managed object context are not pushed down to any other child managed object contexts. If child A pushes its changes to its parent, then child B is unaware of these changes.

Creating a child managed object context is only slightly different from what we've seen so far. We initialize a child managed object context by invoking init(concurrencyType:). The concurrency type the initializer accepts defines the managed object context's threading model. Let's look at each concurrency type.

  • MainQueueConcurrencyType: The managed object context is only accessible from the main thread. An exception is thrown if you try to access it from any other thread.
  • PrivateQueueConcurrencyType: When creating a managed object context with a concurrency type of PrivateQueueConcurrencyType, the managed object context is associated with a private queue and it can only be accessed from that private queue.
  • ConfinementConcurrencyType: This is the concurrency type that corresponds with the thread confinement concept we explored earlier. If you create a managed object context using init(), the concurrency type of that managed object context is ConfinementConcurrencyTypeApple has deprecated this concurrency type as of iOS 9. This also means that init() is deprecated as of iOS 9.

There are two key methods that were added to the Core Data framework when Apple introduced parent/child managed object contexts, performBlock(_:) and performBlockAndWait(_:). Both methods will make your life much easier. When you call performBlock(_:) on a managed object context and pass in a block of code to execute, Core Data makes sure that the block is executed on the correct thread. In the case of the PrivateQueueConcurrencyType concurrency type, this means that the block is executed on the private queue of that managed object context.

The difference between performBlock(_:) and performBlockAndWait(_:) is simple. The performBlock(_:) method doesn't block the current thread. It accepts the block, schedules it for execution on the correct queue, and continues with the execution of the next statement.

The performBlockAndWait(_:) method, however, is blocking. The thread from which performBlockAndWait(_:) is called waits for the block that is passed to the method to finish before executing the next statement. The advantage is that nested calls to performBlockAndWait(_:) are executed in order.

To end this article, I'd like to refactor the Operation class to take advantage of parent/child managed object contexts. You'll quickly notice that it greatly simplifies the NSOperation subclass we created. The main() method changes quite a bit. Take a look at its updated implementation below.

That's it. The main managed object context is the parent of the private managed object context. Note that we don't set the persistentStoreCoordinator property of the private managed object context and we don't add the operation as an observer for NSManagedObjectContextDidSaveNotification notifications. When the private managed object context is saved, the changes are automatically pushed to its parent managed object context. Core Data ensures that this happens on the correct thread. It's up to the main managed object context, the parent managed object context, to push the changes to the persistent store coordinator.

Conclusion

Concurrency isn't easy to grasp or implement, but it's naive to think that you'll never come across a situation in which you need to perform Core Data operations on a background thread.

2015-11-20T17:45:03.000Z2015-11-20T17:45:03.000ZBart Jacobs

An Introduction to Face Detection on Android

$
0
0

Introduced with the Vision libraries in Play Services 8.1, Face Detection makes it easy for you as a developer to analyze a video or image to locate human faces. Once you have a list of faces detected on an image, you can gather information about each face, such as orientation, likelihood of smiling, whether someone has their eyes open or closed, and specific landmarks on their face.

This information can be useful for multiple applications, such as a camera app that automatically takes a picture when everyone in the frame is smiling with their eyes open, or for augmenting images with silly effects, such as unicorn horns. It is important to note that Face Detection is not facial recognition. While information can be gathered about a face, that information is not used by the Vision library to determine if two faces come from the same person.

This tutorial will use a still image to run the Face Detection API and gather information about the people in the photo, while also illustrating that information with overlaid graphics. All code for this tutorial can be found on GitHub.

Example of a silly effect adding a unicorn horn to a face

1. Project Setup

To add the Vision library to your project, you need to import Play Services 8.1 or greater into your project. This tutorial imports only the Play Services Vision library. Open your project's build.gradle file and add the following compile line to the dependencies node.

Once you have included Play Services into your project, you can close your project's build.gradle file and open AndroidManifest.xml. You need to add a meta-data item defining the face dependency under the application node of your manifest. This lets the Vision library know that you plan to detect faces within your application.

Once you're finished setting up AndroidManifest.xml, you can go ahead and close it. Next, you need to create a new class named FaceOverlayView.java. This class extends View and contains the logic for detecting faces in the project, displaying the bitmap that was analyzed and drawing on top of the image in order to illustrate points.

For now, start by adding the member variables at the top of the class and defining the constructors. The Bitmap object will be used to store the bitmap that will be analyzed and the SparseArray of Face objects will store each face found in the bitmap.

Next, add a new method inside of FaceOverlayView called setBitmap(Bitmap bitmap). For now this will simply save the bitmap passed to it, however later you will use this method for analyzing the image.

Next, you need a bitmap. I have included one in the sample project on GitHub, but you can use any image that you would like in order to play with Face Detection and see what works and what doesn't. When you have selected an image, place it into the res/raw directory. This tutorial will assume that the image is called face.jpg.

After you have placed your image into the res/raw directory, open res/layout/activity_main.xml. This layout contains a reference to FaceOverlayView so that it is displayed in MainActivity.

With the layout defined, open MainActivity and set up the FaceOverlayView from onCreate(). You do this by getting a reference to the view, reading the face.jpg image file from the raw directory as an input stream, and converting that into a bitmap. Once you have the bitmap, you can call setBitmap on the FaceOverlayView to pass the image to your custom view.

2. Detecting Faces

Now that your project is set up, it's time to start detecting faces. In setBitmap( Bitmap bitmap ) you need to create a FaceDetector. This can be done using a FaceDetector.Builder, allowing you to define multiple parameters that affect how fast faces will be detected and what other data the FaceDetector will generate.

The settings that you pick depend on what you're attempting to do in your application. If you enable searching for landmarks, then faces will be detected more slowly. As with most things in programming, everything has its trade-offs. To learn more about the options available for FaceDetector.Builder, you can find the official documentation on Android's developer website.

You also need to have a check to see if the FaceDetector is operational. When a user uses face detection for the first time on their device, Play Services needs to go out and get a set of small native libraries to process your application's request. While this will almost always be done before your app has finished launching, it is important to handle the contingency that this has failed.

If the FaceDetector is operational, then you can convert your bitmap into a Frame object and pass it to the detector to gather data about faces in the image. When you are done, you will need to release the detector to prevent a memory leak. When you are finished detecting faces, call invalidate() to trigger redrawing the view.

Now that you have detected the faces in your image, it's time to use them. For this example, you will simply draw a green box around each face. Since invalidate() was called after the faces were detected, you can add all of the necessary logic into onDraw(Canvas canvas). This method ensures that the bitmap and faces are set, then draw the bitmap onto the canvas, and then draw a box around each face.

Since different devices have different display sizes, you will also keep track of the bitmap's scaled size so that the entire image is always visible on the device and all overlays are drawn appropriately.

The drawBitmap(Canvas canvas) method draws your bitmap onto the canvas and sizes it appropriately while also returning a multiplier for scaling your other dimensions correctly.

The drawFaceBox(Canvas canvas, double scale) method gets a little more interesting. Each face that was detected and saved has a position value above and to the left of each face. This method will take that position and draw a green rectangle from it to encompass each face based on its width and height.

You need to define your Paint object and then loop through each Face in your SparseArray to find its position, width, and height, and draw the rectangle on the canvas using that information.

At this point, you should be able to run your application and see your image with rectangles around each face that has been detected. It is important to note that the Face Detection API is still fairly new at the time of this writing and it may not detect every face. You can play with some of the settings in the FaceDetector.Builder object in order to hopefully gather more data, though it's not guaranteed.

Faces detected and bound by a drawn rectangle

3. Understanding Landmarks

Landmarks are points of interest on a face. The Face Detection API does not use landmarks for detecting a face, but rather detects a face in its entirety before looking for landmarks. That is why discovering landmarks is an optional setting that can be enabled through the FaceDetector.Builder.

You can use these landmarks as an additional source of information, such as where the subject's eyes are, so that you can react appropriately within your app. There are twelve landmarks that are possible to find:

  • left and right eye
  • left and right ear
  • left and right ear tip
  • base of the nose
  • left and right cheek
  • left and right corner of the mouth
  • base of the mouth

The landmarks that are available depend on the angle of the face detected. For example, someone facing off to the side will only have one eye visible, which means that the other eye will not be detectable. The following table outlines which landmarks should be detectable based on the Euler Y angle (direction left or right) of the face.

Euler YVisible Landmarks
< -36°left eye, left mouth, left ear, nose base, left cheek
-36° to -12°    left mouth, nose base, bottom mouth, right eye, left eye, left cheek, left ear tip
-12° to 12°right eye, left eye, nose base, left cheek, right cheek, left mouth, right mouth, bottom mouth
12° to 36°right mouth, nose base, bottom mouth, left eye, right eye, right cheek, right ear tip
> 36°right eye, right mouth, right ear, nose base, right cheek

Landmarks are also incredibly easy to use in your application as you've already included them during face detection. You simply need to call getLandmarks() on a Face object to get a List of Landmark objects that you can work with.

In this tutorial, you will paint a small circle on each detected landmark by calling a new method, drawFaceLandmarks(Canvas canvas, double scale), from onDraw(canvas canvas) instead of drawFaceBox(Canvas canvas, double scale). This method takes the position of each landmark, adjusts it for the scale of the bitmap, and then displays the landmark indicator circle.

After calling this method, you should see small green circles covering the detected faces as shown in the example below.

Circles placed over detected facial landmarks

4. Additional Face Data

While the position of a face and its landmarks are useful, you can also find out more information about each face detected in your app through some built-in methods from the Face object. The getIsSmilingProbability()getIsLeftEyeOpenProbability() and getIsRightEyeOpenProbability() methods attempt to determine if eyes are open or if the person detected is smiling by returning a float ranging from 0.0 to 1.0. The closer to 1.0, the more likely that person is smiling or has their left or right eye open.

You can also find the angle of the face on the Y and Z axes of an image by checking its Euler values. The Z Euler value will always be reported, however, you must use accurate mode when detecting faces in order to receive the X value. You can see an example of how to get these values in the following code snippet.

Conclusion

In this tutorial, you have learned about one of the main components of the Play Services Vision library, Face Detection. You now know how to detect faces in a still image, how to gather information, and find important landmarks for each face.

Using what you have learned, you should be able to add some great features to your own apps for augmenting still images, tracking faces in a video feed, or anything else you can imagine.

2015-11-23T16:55:52.000Z2015-11-23T16:55:52.000ZPaul Trebilcox-Ruiz

An Introduction to Face Detection on Android

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

Introduced with the Vision libraries in Play Services 8.1, Face Detection makes it easy for you as a developer to analyze a video or image to locate human faces. Once you have a list of faces detected on an image, you can gather information about each face, such as orientation, likelihood of smiling, whether someone has their eyes open or closed, and specific landmarks on their face.

This information can be useful for multiple applications, such as a camera app that automatically takes a picture when everyone in the frame is smiling with their eyes open, or for augmenting images with silly effects, such as unicorn horns. It is important to note that Face Detection is not facial recognition. While information can be gathered about a face, that information is not used by the Vision library to determine if two faces come from the same person.

This tutorial will use a still image to run the Face Detection API and gather information about the people in the photo, while also illustrating that information with overlaid graphics. All code for this tutorial can be found on GitHub.

Example of a silly effect adding a unicorn horn to a face

1. Project Setup

To add the Vision library to your project, you need to import Play Services 8.1 or greater into your project. This tutorial imports only the Play Services Vision library. Open your project's build.gradle file and add the following compile line to the dependencies node.

Once you have included Play Services into your project, you can close your project's build.gradle file and open AndroidManifest.xml. You need to add a meta-data item defining the face dependency under the application node of your manifest. This lets the Vision library know that you plan to detect faces within your application.

Once you're finished setting up AndroidManifest.xml, you can go ahead and close it. Next, you need to create a new class named FaceOverlayView.java. This class extends View and contains the logic for detecting faces in the project, displaying the bitmap that was analyzed and drawing on top of the image in order to illustrate points.

For now, start by adding the member variables at the top of the class and defining the constructors. The Bitmap object will be used to store the bitmap that will be analyzed and the SparseArray of Face objects will store each face found in the bitmap.

Next, add a new method inside of FaceOverlayView called setBitmap(Bitmap bitmap). For now this will simply save the bitmap passed to it, however later you will use this method for analyzing the image.

Next, you need a bitmap. I have included one in the sample project on GitHub, but you can use any image that you would like in order to play with Face Detection and see what works and what doesn't. When you have selected an image, place it into the res/raw directory. This tutorial will assume that the image is called face.jpg.

After you have placed your image into the res/raw directory, open res/layout/activity_main.xml. This layout contains a reference to FaceOverlayView so that it is displayed in MainActivity.

With the layout defined, open MainActivity and set up the FaceOverlayView from onCreate(). You do this by getting a reference to the view, reading the face.jpg image file from the raw directory as an input stream, and converting that into a bitmap. Once you have the bitmap, you can call setBitmap on the FaceOverlayView to pass the image to your custom view.

2. Detecting Faces

Now that your project is set up, it's time to start detecting faces. In setBitmap( Bitmap bitmap ) you need to create a FaceDetector. This can be done using a FaceDetector.Builder, allowing you to define multiple parameters that affect how fast faces will be detected and what other data the FaceDetector will generate.

The settings that you pick depend on what you're attempting to do in your application. If you enable searching for landmarks, then faces will be detected more slowly. As with most things in programming, everything has its trade-offs. To learn more about the options available for FaceDetector.Builder, you can find the official documentation on Android's developer website.

You also need to have a check to see if the FaceDetector is operational. When a user uses face detection for the first time on their device, Play Services needs to go out and get a set of small native libraries to process your application's request. While this will almost always be done before your app has finished launching, it is important to handle the contingency that this has failed.

If the FaceDetector is operational, then you can convert your bitmap into a Frame object and pass it to the detector to gather data about faces in the image. When you are done, you will need to release the detector to prevent a memory leak. When you are finished detecting faces, call invalidate() to trigger redrawing the view.

Now that you have detected the faces in your image, it's time to use them. For this example, you will simply draw a green box around each face. Since invalidate() was called after the faces were detected, you can add all of the necessary logic into onDraw(Canvas canvas). This method ensures that the bitmap and faces are set, then draw the bitmap onto the canvas, and then draw a box around each face.

Since different devices have different display sizes, you will also keep track of the bitmap's scaled size so that the entire image is always visible on the device and all overlays are drawn appropriately.

The drawBitmap(Canvas canvas) method draws your bitmap onto the canvas and sizes it appropriately while also returning a multiplier for scaling your other dimensions correctly.

The drawFaceBox(Canvas canvas, double scale) method gets a little more interesting. Each face that was detected and saved has a position value above and to the left of each face. This method will take that position and draw a green rectangle from it to encompass each face based on its width and height.

You need to define your Paint object and then loop through each Face in your SparseArray to find its position, width, and height, and draw the rectangle on the canvas using that information.

At this point, you should be able to run your application and see your image with rectangles around each face that has been detected. It is important to note that the Face Detection API is still fairly new at the time of this writing and it may not detect every face. You can play with some of the settings in the FaceDetector.Builder object in order to hopefully gather more data, though it's not guaranteed.

Faces detected and bound by a drawn rectangle

3. Understanding Landmarks

Landmarks are points of interest on a face. The Face Detection API does not use landmarks for detecting a face, but rather detects a face in its entirety before looking for landmarks. That is why discovering landmarks is an optional setting that can be enabled through the FaceDetector.Builder.

You can use these landmarks as an additional source of information, such as where the subject's eyes are, so that you can react appropriately within your app. There are twelve landmarks that are possible to find:

  • left and right eye
  • left and right ear
  • left and right ear tip
  • base of the nose
  • left and right cheek
  • left and right corner of the mouth
  • base of the mouth

The landmarks that are available depend on the angle of the face detected. For example, someone facing off to the side will only have one eye visible, which means that the other eye will not be detectable. The following table outlines which landmarks should be detectable based on the Euler Y angle (direction left or right) of the face.

Euler YVisible Landmarks
< -36°left eye, left mouth, left ear, nose base, left cheek
-36° to -12°    left mouth, nose base, bottom mouth, right eye, left eye, left cheek, left ear tip
-12° to 12°right eye, left eye, nose base, left cheek, right cheek, left mouth, right mouth, bottom mouth
12° to 36°right mouth, nose base, bottom mouth, left eye, right eye, right cheek, right ear tip
> 36°right eye, right mouth, right ear, nose base, right cheek

Landmarks are also incredibly easy to use in your application as you've already included them during face detection. You simply need to call getLandmarks() on a Face object to get a List of Landmark objects that you can work with.

In this tutorial, you will paint a small circle on each detected landmark by calling a new method, drawFaceLandmarks(Canvas canvas, double scale), from onDraw(canvas canvas) instead of drawFaceBox(Canvas canvas, double scale). This method takes the position of each landmark, adjusts it for the scale of the bitmap, and then displays the landmark indicator circle.

After calling this method, you should see small green circles covering the detected faces as shown in the example below.

Circles placed over detected facial landmarks

4. Additional Face Data

While the position of a face and its landmarks are useful, you can also find out more information about each face detected in your app through some built-in methods from the Face object. The getIsSmilingProbability()getIsLeftEyeOpenProbability() and getIsRightEyeOpenProbability() methods attempt to determine if eyes are open or if the person detected is smiling by returning a float ranging from 0.0 to 1.0. The closer to 1.0, the more likely that person is smiling or has their left or right eye open.

You can also find the angle of the face on the Y and Z axes of an image by checking its Euler values. The Z Euler value will always be reported, however, you must use accurate mode when detecting faces in order to receive the X value. You can see an example of how to get these values in the following code snippet.

Conclusion

In this tutorial, you have learned about one of the main components of the Play Services Vision library, Face Detection. You now know how to detect faces in a still image, how to gather information, and find important landmarks for each face.

Using what you have learned, you should be able to add some great features to your own apps for augmenting still images, tracking faces in a video feed, or anything else you can imagine.

2015-11-23T16:55:52.000Z2015-11-23T16:55:52.000ZPaul Trebilcox-Ruiz

Gradle in 60 Seconds

$
0
0

Gradle is the de facto build system for Android Studio. It takes your project's source code, resources, and other dependencies, and packages them up into an APK file. But there's much more that Gradle can do. In this video, I show you what Gradle is and what it can do for you.

A Bit More Detail

Learn more about Gradle on Envato Tuts+:

Other useful links:

60 seconds?!

This is part of a new series of quick video tutorials on Envato Tuts+. We’re aiming to introduce a range of subjects, all in 60 seconds–just enough to whet your appetite. Let us know in the comments what you thought of this video and what else you’d like to see explained in 60 seconds!

2015-11-24T17:45:09.000Z2015-11-24T17:45:09.000ZPaul Trebilcox-Ruiz

Gradle in 60 Seconds

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

Gradle is the de facto build system for Android Studio. It takes your project's source code, resources, and other dependencies, and packages them up into an APK file. But there's much more that Gradle can do. In this video, I show you what Gradle is and what it can do for you.

A Bit More Detail

Learn more about Gradle on Envato Tuts+:

Other useful links:

60 seconds?!

This is part of a new series of quick video tutorials on Envato Tuts+. We’re aiming to introduce a range of subjects, all in 60 seconds–just enough to whet your appetite. Let us know in the comments what you thought of this video and what else you’d like to see explained in 60 seconds!

2015-11-24T17:45:09.000Z2015-11-24T17:45:09.000ZPaul Trebilcox-Ruiz

Core Data and Swift: Batch Updates

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

Even though Core Data has been around for many years on OS X and iOS, a feature that was added only recently are batch updates. Developers have been asking for this feature for many years and Apple finally found a way to integrate it into Core Data. In this tutorial, I will show you how batch updates work and what they mean for the Core Data framework.

1. The Problem

Core Data is great at managing object graphs. Even complex object graphs with many entities and relationships aren't much of a problem for Core Data. However, Core Data does have a few weak spots, updating large numbers of records being one of them.

The problem is easy to understand. Whenever you update a record, Core Data loads the record into memory, updates the record, and saves the changes to the persistent store, a SQLite database for example.

If Core Data needs to update a large number of records, it needs to load every record into memory, update the record, and send the changes to the persistent store. If the number of records is too large, iOS will simply bail out due to a lack of resources. Even though a device running OS X may have the resources to execute the request, it will be slow and consume a lot of memory.

An alternative approach is to update the records in batches, but that too takes a lot of time and resources. On iOS 7, it's the only option iOS developers have. That's no longer the case since iOS 8 and OS X Yosemite.

2. The Solution

On iOS 8 and up and OS X Yosemite and up, it's possible to talk directly to the persistent store and tell it what you'd like to change. This generally involves updating an attribute. Apple calls this feature batch updates.

There are a number of pitfalls to watch out for though. Core Data does a lot of things for you and you may not even realize it until you use batch updates. Validation is a good example. Because Core Data performs batch updates directly on the persistent store, such as a SQLite database, Core Data isn't able to perform any validation on the data you write to the persistent store. This means that you are in charge of making sure you don't add invalid data to the persistent store.

When would you use batch updates? Apple recommends to only use this feature if the traditional approach is too resource or time intensive. If you need to mark hundreds or thousands of email messages as read, then batch updates is the best solution on iOS 8 and up and OS X Yosemite and up.

3. How Does It Work?

To illustrate how batch updates work, I suggest we revisit Done, a simple Core Data application that manages a to-do list. We'll add a button to the navigation bar that marks every item in the list as done.

Step 1: Projet Setup

Download or clone the project from GitHub and open it in Xcode 7. Run the application in the simulator and add a few to-do items.

Adding To-Do Items

Step 2: Create Bar Button Item

Open ViewController.swift and declare a property, checkAllButton, of type UIBarButtonItem at the top.

Initialize the bar button item in the viewDidLoad() method of the ViewController class and set it as the left bar button item of the navigation item.

Step 3: Implement checkAll(_:) Method

The checkAll(_:) method is fairly easy, but there are a few caveats to watch out for. Take a look at its implementation below.

Create Batch Request

We start by creating an NSEntityDescription instance for the Item entity and use it to initialize an NSBatchUpdateRequest object. The NSBatchUpdateRequest class is a subclass of NSPersistentStoreRequest.

We set the result type of the batch update request to .UpdatedObjectIDsResultType, a member value of the NSBatchUpdateRequestResultType enum. This means that the result of the batch update request will be an array containing the object IDs, instances of the NSManagedObjectID class, of the records that were changed by the batch update request.

We also populate the propertiesToUpdate property of the batch update request. For this example, we set propertiesToUpdate to a dictionary containing one key, "done", with value NSNumber(bool: true). This means that every Item record will be set to done, which is what we're after.

Execute Batch Update Request

Even though batch updates bypass the managed object context, executing a batch update request is done by calling executeRequest(_:) on an NSManagedObjectContext instance. This method accepts one argument, an instance of the NSPersistentStoreRequest class. Because executeRequest(_:) is a throwing method, we execute the method in a do-catch statement.

Updating the Managed Object Context

Even though we hand the batch update request to a managed object context, the managed object context is not aware of the changes as a result of executing the batch update request. As I mentioned earlier, it bypasses the managed object context. This gives batch updates their power and speed. To remedy this issue, we need to do two things:

  • turn the managed objects that were updated by the batch update into faults
  • tell the fetched results controller to perform a fetch to update the user interface

This is what we do in the next few lines of the checkAll(_:) method in the do clause of the do-catch statement. If the batch update request is successful, we extract the array of NSManagedObjectID instances from the NSBatchUpdateResult object.

We then iterate over the objectIDs array, ask the managed object context for the corresponding NSManagedObject instance, and turn it into a fault by invoking refreshObject(_:mergeChanges:), passing in the managed object as the first argument. To force the managed object into a fault, we pass false as the second argument.

Fetching Updated Records

The last step is to tell the fetched results controller to perform a fetch to update the user interface. If this is unsuccessful, we catch the error in the catch clause of the do-catch statement.

While this may seem cumbersome and fairly complex for an easy operation, keep in mind that we bypass the Core Data stack. In other words, we need to take care of some housekeeping that's usually done for us by Core Data.

Step 4: Build & Run

Build the project and run the application in the simulator or on a physical device. Click or tap the bar button item on the right to check every to-do item in the list.

Checking All To-Do Items

Conclusion

Batch updates are a great addition to the Core Data framework. Not only does it answer a need developers have had for many years, it isn't difficult to implement as long as you keep a few basic rules in mind. In the next tutorial, we'll take a closer look at batch deletes, another feature of the Core Data framework that was added only recently.

2015-11-25T17:45:19.000Z2015-11-25T17:45:19.000ZBart Jacobs

Core Data and Swift: Batch Deletes

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

Core Data is a framework I really enjoy working with. Even though Core Data isn't perfect, it's great to see that Apple continues to invest in the framework. This year, for example, Apple added the ability to batch delete records. In the previous article, we discussed batch updates. The idea underlying batch deletes is very similar as you'll learn in this tutorial.

1. The Problem

If a Core Data application needs to remove a large number of records, then it's faced with a problem. Even though there's no need to load a record into memory to delete it, that's simply how Core Data works. As we discussed in the previous article, this has a number of downsides. Before the introduction of batch updates, there was no proper solution for updating a large number of records. Before iOS 9 and OS X El Capitan, the same applied to batch deletes.

2. The Solution

While the NSBatchUpdateRequest class was introduced in iOS 8 and OS X Yosemite, the NSBatchDeleteRequest class was added only recently, alongside the release of iOS 9 and OS X El Capitan. Like its cousin, NSBatchUpdateRequest, a NSBatchDeleteRequest instance operates directly on one or more persistent stores.

Unfortunately, this means that batch deletes suffer from the same limitations batch updates do. Because a batch delete request directly affects a persistent store, the managed object context is ignorant of the consequences of a batch delete request. This also means that no validations are performed and no notifications are posted when the underlying data of a managed object changes as a result of a batch delete request. Despite these limitations, the delete rules for relationships are applied by Core Data.

3. How Does It Work?

In the previous tutorial, we added a feature to mark every to-do item as done. Let's revisit that application and add the ability to delete every to-do item that is marked as done.

Step 1: Project Setup

Download or clone the project from GitHub and open it in Xcode 7. Make sure the deployment target of the project is set to iOS 9 or higher to make sure the NSBatchDeleteRequest class is available.

Step 2: Create Bar Button Item

Open ViewController.swift and declare a property deleteAllButton of type UIBarButtonItem. You can delete the checkAllButton property since we won't be needing it in this tutorial.

Initialize the bar button item in the viewDidLoad() method of the ViewController class and set it as the left bar button item of the navigation item.

Step 3: Implement deleteAll(_:) Method

Using the NSBatchDeleteRequest class isn't difficult, but we need to take care of a few issues that are inherent to directly operating on a persistent store.

Create Fetch Request

An NSBatchDeleteRequest object is initialized with an NSFetchRequest object. It's this fetch request that determines which records will be deleted from the persistent store(s). In deleteAll(_:), we create a fetch request for the Item entity. We set fetch request's predicate property to make sure we only delete Item records that are marked as done.

Because the fetch request determines which records will be deleted, we have all the power of the NSFetchRequest class at our disposal, including setting a limit on the number of records, using sort descriptors, and specifying an offset for the fetch request.

Create Batch Request

As I mentioned earlier, the batch delete request is initialized with an NSFetchRequest instance. Because the NSBatchDeleteRequest class is an NSPersistentStoreRequest subclass, we can set the request's resultType property to specify what type of result we're interested in.

The resultType property of an NSBatchDeleteRequest instance is of type NSBatchDeleteRequestResultType.The NSBatchDeleteRequestResultType enum defines three member variables:

  • ResultTypeStatusOnly: This tells us whether the batch delete request was successful or unsuccessful.
  • ResultTypeObjectIDs: This gives us an array of the NSManagedObjectID instances  that correspond with the records that were deleted by the batch delete request.
  • ResultTypeCount: By setting the request's resultType property to ResultTypeCount, we are given the number of records that were affected (deleted) by the batch delete request.

Execute Batch Update Request

You may recall from the previous tutorial that executeRequest(_:) is a throwing method. This means that we need to wrap the method call in a do-catch statement. The executeRequest(_:) method returns a NSPersistentStoreResult object. Because we're dealing with a batch delete request, we cast the result to an NSBatchDeleteResult object. The result is printed to the console.

If you were to run the application, populate it with a few items, and tap the Delete All button, the user interface wouldn't be updated. I can assure you that the batch delete request did its work though. Remember that the managed object context is not notified in any way of the consequences of the batch delete request. Obviously, that's something we need to fix.

Updating the Managed Object Context

In the previous tutorial, we worked with the NSBatchUpdateRequest class. We updated the managed object context by refreshing the objects in the managed object context that were affected by the batch update request.

We can't use the same technique for the batch delete request, because some objects are no longer represented by a record in the persistent store. We need to take drastic measures as you can see below. We call reset() on the managed object context, which means that the managed object context starts with a clean slate.

This also means that the fetched results controller needs to perform a fetch to update the records it manages for us. To update the user interface, we invoke reloadData() on the table view.

4. Saving State Before Deleting

It's important to be careful whenever you directly interact with a persistent store(s). Earlier in this series, I wrote that it isn't necessary to save the changes of a managed object context whenever you add, update, or delete a record. That statement still holds true, but it also has consequences when working with NSPersistentStoreRequest subclasses.

Before we continue, I'd like to seed the persistent store with dummy data so we have something to work with. This makes it easier to visualize what I'm about to explain. Add the following helper method to ViewController.swift and invoke it in viewDidLoad().

In seedPersistentStore(), we create a few records and mark every third item as done. Note that we call save() on the managed object context at the end of this method to make sure the changes are pushed to the persistent store. In viewDidLoad(), we seed the persistent store.

Run the application and tap the Delete All button. The records that are marked as done should be deleted. What happens if you mark a few of the remaining items as done and tap the Delete All button again. Are these items also removed? Can you guess why that is?

The batch delete request directly interacts with the persistent store. When an item is marked as done, however, the change isn't immediately pushed to the persistent store. We don't call save() on the managed object context every time the user marks an items as done. We only do this when the application is pushed to the background and when it is terminated (see AppDelegate.swift).

The solution is simple. To fix the issue, we need to save the changes of the managed object context before executing the batch delete request. Add the following lines to the deleteAll(_:) method and run the application again to test the solution.

Conclusion

The NSPersistentStoreRequest subclasses are a very useful addition to the Core Data framework, but I hope it's clear that they should only be used when absolutely necessary. Apple only added the ability to directly operate on persistent stores to patch the weaknesses of the framework, but the advice is to use them sparingly.

2015-11-26T19:27:07.635Z2015-11-26T19:27:07.635ZBart Jacobs

Core Data and Swift: Asynchronous Fetching

$
0
0

In the previous installments, we discussed batch updates and batch deletes. In this tutorial, we'll take a closer look at how to implement asynchronous fetching and in what situations your application can benefit from this new API.

1. The Problem

Like batch updates, asynchronous fetching has been on the wish list of many developers for quite some time. Fetch requests can be complex, taking a non-trivial amount of time to complete. During that time the fetch request blocks the thread it's running on and, as a result, blocks access to the managed object context executing the fetch request. The problem is simple to understand, but what does Apple's solution look like.

2. The Solution

Apple's answer to this problem is asynchronous fetching. An asynchronous fetch request runs in the background. This means that it doesn't block other tasks while it's being executed, such as updating the user interface on the main thread.

Asynchronous fetching also sports two other convenient features, progress reporting and cancellation. An asynchronous fetch request can be cancelled at any time, for example, when the user decides the fetch request takes too long to complete. Progress reporting is a useful addition to show the user the current state of the fetch request.

Asynchronous fetching is a flexible API. Not only is it possible to cancel an asynchronous fetch request, it's also possible to make changes to the managed object context while the asynchronous fetch request is being executed. In other words, the user can continue to use your application while the application executes an asynchronous fetch request in the background.

3. How Does It Work?

Like batch updates, asynchronous fetch requests are handed to the managed object context as an NSPersistentStoreRequest object, an instance of the NSAsynchronousFetchRequest class to be precise.

An NSAsynchronousFetchRequest instance is initialized with an NSFetchRequest object and a completion block. The completion block is executed when the asynchronous fetch request has completed its fetch request.

Let's revisit the to-do application we created earlier in this series and replace the current implementation of the NSFetchedResultsController class with an asynchronous fetch request.

Step 1: Project Setup

Download or clone the project from GitHub and open it in Xcode 7. Before we can start working with the NSAsynchronousFetchRequest class, we need to make some changes. We won't be able to use the NSFetchedResultsController class for managing the table view's data since the NSFetchedResultsController class was designed to run on the main thread.

Step 2: Replacing the Fetched Results Controller

Start by updating the ViewController class as shown below. We remove the fetchedResultsController property and create a new property,items, of type [Item] for storing the to-do items. This also means that the ViewController class no longer needs to conform to the NSFetchedResultsControllerDelegate protocol.

Before we refactor the viewDidLoad() method, I first want to update the implementation of the UITableViewDataSource protocol. Take a look at the changes I've made.

We also need to change one line of code in the prepareForSegue(_:sender:) method as shown below.

Last but not least, delete the implementation of the NSFetchedResultsControllerDelegate protocol since we no longer need it.

Step 3: Creating the Asynchronous Fetch Request

As you can see below, we create the asynchronous fetch request in the view controller's viewDidLoad() method. Let's take a moment to see what's going on.

We start by creating and configuring an NSFetchRequest instance to initialize the asynchronous fetch request. It's this fetch request that the asynchronous fetch request will execute in the background.

To initialize an NSAsynchronousFetchRequest instance, we invoke init(request:completionBlock:), passing in fetchRequest and a completion block.

The completion block is invoked when the asynchronous fetch request has completed executing its fetch request. The completion block takes one argument of type NSAsynchronousFetchResult, which contains the result of the query as well as a reference to the original asynchronous fetch request.

In the completion block, we invoke processAsynchronousFetchResult(_:), passing in the NSAsynchronousFetchResult object. We'll take a look at this helper method in a few moments.

Executing the asynchronous fetch request is almost identical to how we execute an NSBatchUpdateRequest. We call executeRequest(_:) on the managed object context, passing in the asynchronous fetch request.

Even though the asynchronous fetch request is executed in the background, note that the executeRequest(_:) method returns immediately, handing us an NSAsynchronousFetchResult object. Once the asynchronous fetch request completes, that same NSAsynchronousFetchResult object is populated with the result of the fetch request.

Remember from the previous tutorial that executeRequest(_:) is a throwing method. We catch any errors in the catch clause of the do-catch statement and print them to the console for debugging.

Step 4: Processing the Asynchronous Fetch Result

The processAsynchronousFetchResult(_:) method is nothing more than a helper method in which we process the result of the asynchronous fetch request. We set the view controller's items property with the contents of the result's finalResult property and reload the table view.

Step 5: Build & Run

Build the project and run the application in the iOS Simulator. If your application crashes when it attempts to execute the asynchronous fetch request, then you may be using an API that is deprecated as of iOS 9 (and OS X El Capitan).

In Core Data and Swift: Concurrency, I explained the different concurrency types a managed object context can have. As of iOS 9 (and OS X El Capitan), the ConfinementConcurrencyType is deprecated. The same is true for the init() method of the NSManagedObjectContext class, because it creates an instance with a concurrency type of ConfinementConcurrencyType.

If your application crashes, you are most likely using a managed object context with a ConfinementConcurrencyType concurrency type, which doesn't support asynchronous fetching. Fortunately, the solution is simple. Create a managed object context using the designated initializer, init(concurrencyType:), passing in MainQueueConcurrencyType or PrivateQueueConcurrencyType as the concurrency type.

4. Showing Progress

The NSAsynchronousFetchRequest class adds support for monitoring the progress of the fetch request and it's even possible to cancel an asynchronous fetch request, for example, if the user decides that it's taking too long to complete.

The NSAsynchronousFetchRequest class leverages the NSProgress class for progress reporting as well as canceling an asynchronous fetch request. The NSProgress class, available since iOS 7 and OS X Mavericks, is a clever way to monitor the progress of a task without the need to tightly couple the task to the user interface.

The NSProgress class also support cancelation, which is how an asynchronous fetch request can be canceled. Let's find out what we need to do to implement progress reporting for the asynchronous fetch request.

Step 1: Adding SVProgressHUD

We'll show the user the progress of the asynchronous fetch request using Sam Vermette's SVProgressHUD library. The easiest way to accomplish this is through CocoaPods. This is what the project's Podfile looks like.

Run pod install form the command line and don't forget to open the workspace CocoaPods has created for you instead of the Xcode project.

Step 2: Setting Up NSProgress 

In this article, we won't explore the NSProgress class in much detail, but feel free to read more about it in Apple's documentation. We create an NSProgress instance in the view controller's viewDidLoad() method, before we execute the asynchronous fetch request.

You may be surprised that we set the total unit count to 1. The reason is simple. When Core Data executes the asynchronous fetch request, it doesn't know how many records it will find in the persistent store. This also means that we won't be able to show the relative progress to the user—a percentage. Instead, we will show the user the absolute progress—the number of records it has found.

You could remedy this issue by performing a fetch request to fetch the number of records before you execute the asynchronous fetch request. I prefer not to do this though, because this also means that fetching the records from the persistent store takes longer to complete because of the extra fetch request at the start.

Step 3: Adding an Observer

When we execute the asynchronous fetch request, we are immediately handed an NSAsynchronousFetchResult object. This object has a progress property, which is of type NSProgress. It's this progress property that we need to observe if we want to receive progress updates.

Note that we call resignCurrent on the progress object to balance the earlier becomeCurrentWithPendingUnitCount: call. Keep in mind that both of these methods need to be invoked on the same thread.

Step 4: Removing the Observer

In the completion block of the asynchronous fetch request, we remove the observer and dismiss the progress HUD.

Before we implement observeValueForKeyPath(_:ofObject:change:context:), we need to show the progress HUD before creating the asynchronous fetch request.

Step 5: Progress Reporting

All that's left for us to do, is implement the observeValueForKeyPath(_:ofObject:change:context:) method. We check if context is equal to ProgressContext, create a status object by extracting the number of completed records from the change dictionary, and update the progress HUD. Note that we update the user interface on the main thread.

5. Dummy Data

If we want to properly test our application, we need more data. While I don't recommend using the following approach in a production application, it's a quick and easy way to populate the database with data.

Open AppDelegate.swift and update the application(_:didFinishLaunchingWithOptions:) method as shown below. The populateDatabase() method is a simple helper method in which we add dummy data to the database.

The implementation is straightforward. Because we only want to insert dummy data once, we check the user defaults database for the key "didPopulateDatabase". If the key isn't set, we insert dummy data.

The number of records is important. If you plan to run the application on the iOS Simulator, then it's fine to insert 100,000 or 1,000,000 records. This won't work as good on a physical device and will take too long to complete.

In the for loop, we create a managed object and populate it with data. Note that we don't save the changes of the managed object context during each iteration of the for loop.

Finally, we update the user defaults database to make sure the database isn't populated the next time the application is launched.

Great. Run the application in the iOS Simulator to see the result. You'll notice that it takes a few moments for the asynchronous fetch request to start fetching records and update the progress HUD.

Showing The Progress of The Asynchronous Fetch Request

6. Breaking Changes

By replacing the fetched results controller class with an asynchronous fetch request, we have broken a few pieces of the application. For example, tapping the checkmark of a to-do item doesn't seem to work any longer. While the database is being updated, the user interface doesn't reflect the change. The solution is fairly easy to fix and I'll leave it up to you to implement a solution. You should now have enough knowledge to understand the problem and find a suitable solution.

Conclusion

I'm sure you agree that asynchronous fetching is surprisingly easy to use. The heavy lifting is done by Core Data, which means that there's no need to manually merge the results of the asynchronous fetch request with the managed object context. Your only job is to update the user interface when the asynchronous fetch request hands you the results.

2015-11-27T18:37:08.727Z2015-11-27T18:37:08.727ZBart Jacobs

Core Data and Swift: Asynchronous Fetching

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

In the previous installments, we discussed batch updates and batch deletes. In this tutorial, we'll take a closer look at how to implement asynchronous fetching and in what situations your application can benefit from this new API.

1. The Problem

Like batch updates, asynchronous fetching has been on the wish list of many developers for quite some time. Fetch requests can be complex, taking a non-trivial amount of time to complete. During that time the fetch request blocks the thread it's running on and, as a result, blocks access to the managed object context executing the fetch request. The problem is simple to understand, but what does Apple's solution look like.

2. The Solution

Apple's answer to this problem is asynchronous fetching. An asynchronous fetch request runs in the background. This means that it doesn't block other tasks while it's being executed, such as updating the user interface on the main thread.

Asynchronous fetching also sports two other convenient features, progress reporting and cancellation. An asynchronous fetch request can be cancelled at any time, for example, when the user decides the fetch request takes too long to complete. Progress reporting is a useful addition to show the user the current state of the fetch request.

Asynchronous fetching is a flexible API. Not only is it possible to cancel an asynchronous fetch request, it's also possible to make changes to the managed object context while the asynchronous fetch request is being executed. In other words, the user can continue to use your application while the application executes an asynchronous fetch request in the background.

3. How Does It Work?

Like batch updates, asynchronous fetch requests are handed to the managed object context as an NSPersistentStoreRequest object, an instance of the NSAsynchronousFetchRequest class to be precise.

An NSAsynchronousFetchRequest instance is initialized with an NSFetchRequest object and a completion block. The completion block is executed when the asynchronous fetch request has completed its fetch request.

Let's revisit the to-do application we created earlier in this series and replace the current implementation of the NSFetchedResultsController class with an asynchronous fetch request.

Step 1: Project Setup

Download or clone the project from GitHub and open it in Xcode 7. Before we can start working with the NSAsynchronousFetchRequest class, we need to make some changes. We won't be able to use the NSFetchedResultsController class for managing the table view's data since the NSFetchedResultsController class was designed to run on the main thread.

Step 2: Replacing the Fetched Results Controller

Start by updating the ViewController class as shown below. We remove the fetchedResultsController property and create a new property,items, of type [Item] for storing the to-do items. This also means that the ViewController class no longer needs to conform to the NSFetchedResultsControllerDelegate protocol.

Before we refactor the viewDidLoad() method, I first want to update the implementation of the UITableViewDataSource protocol. Take a look at the changes I've made.

We also need to change one line of code in the prepareForSegue(_:sender:) method as shown below.

Last but not least, delete the implementation of the NSFetchedResultsControllerDelegate protocol since we no longer need it.

Step 3: Creating the Asynchronous Fetch Request

As you can see below, we create the asynchronous fetch request in the view controller's viewDidLoad() method. Let's take a moment to see what's going on.

We start by creating and configuring an NSFetchRequest instance to initialize the asynchronous fetch request. It's this fetch request that the asynchronous fetch request will execute in the background.

To initialize an NSAsynchronousFetchRequest instance, we invoke init(request:completionBlock:), passing in fetchRequest and a completion block.

The completion block is invoked when the asynchronous fetch request has completed executing its fetch request. The completion block takes one argument of type NSAsynchronousFetchResult, which contains the result of the query as well as a reference to the original asynchronous fetch request.

In the completion block, we invoke processAsynchronousFetchResult(_:), passing in the NSAsynchronousFetchResult object. We'll take a look at this helper method in a few moments.

Executing the asynchronous fetch request is almost identical to how we execute an NSBatchUpdateRequest. We call executeRequest(_:) on the managed object context, passing in the asynchronous fetch request.

Even though the asynchronous fetch request is executed in the background, note that the executeRequest(_:) method returns immediately, handing us an NSAsynchronousFetchResult object. Once the asynchronous fetch request completes, that same NSAsynchronousFetchResult object is populated with the result of the fetch request.

Remember from the previous tutorial that executeRequest(_:) is a throwing method. We catch any errors in the catch clause of the do-catch statement and print them to the console for debugging.

Step 4: Processing the Asynchronous Fetch Result

The processAsynchronousFetchResult(_:) method is nothing more than a helper method in which we process the result of the asynchronous fetch request. We set the view controller's items property with the contents of the result's finalResult property and reload the table view.

Step 5: Build & Run

Build the project and run the application in the iOS Simulator. If your application crashes when it attempts to execute the asynchronous fetch request, then you may be using an API that is deprecated as of iOS 9 (and OS X El Capitan).

In Core Data and Swift: Concurrency, I explained the different concurrency types a managed object context can have. As of iOS 9 (and OS X El Capitan), the ConfinementConcurrencyType is deprecated. The same is true for the init() method of the NSManagedObjectContext class, because it creates an instance with a concurrency type of ConfinementConcurrencyType.

If your application crashes, you are most likely using a managed object context with a ConfinementConcurrencyType concurrency type, which doesn't support asynchronous fetching. Fortunately, the solution is simple. Create a managed object context using the designated initializer, init(concurrencyType:), passing in MainQueueConcurrencyType or PrivateQueueConcurrencyType as the concurrency type.

4. Showing Progress

The NSAsynchronousFetchRequest class adds support for monitoring the progress of the fetch request and it's even possible to cancel an asynchronous fetch request, for example, if the user decides that it's taking too long to complete.

The NSAsynchronousFetchRequest class leverages the NSProgress class for progress reporting as well as canceling an asynchronous fetch request. The NSProgress class, available since iOS 7 and OS X Mavericks, is a clever way to monitor the progress of a task without the need to tightly couple the task to the user interface.

The NSProgress class also support cancelation, which is how an asynchronous fetch request can be canceled. Let's find out what we need to do to implement progress reporting for the asynchronous fetch request.

Step 1: Adding SVProgressHUD

We'll show the user the progress of the asynchronous fetch request using Sam Vermette's SVProgressHUD library. The easiest way to accomplish this is through CocoaPods. This is what the project's Podfile looks like.

Run pod install form the command line and don't forget to open the workspace CocoaPods has created for you instead of the Xcode project.

Step 2: Setting Up NSProgress 

In this article, we won't explore the NSProgress class in much detail, but feel free to read more about it in Apple's documentation. We create an NSProgress instance in the view controller's viewDidLoad() method, before we execute the asynchronous fetch request.

You may be surprised that we set the total unit count to 1. The reason is simple. When Core Data executes the asynchronous fetch request, it doesn't know how many records it will find in the persistent store. This also means that we won't be able to show the relative progress to the user—a percentage. Instead, we will show the user the absolute progress—the number of records it has found.

You could remedy this issue by performing a fetch request to fetch the number of records before you execute the asynchronous fetch request. I prefer not to do this though, because this also means that fetching the records from the persistent store takes longer to complete because of the extra fetch request at the start.

Step 3: Adding an Observer

When we execute the asynchronous fetch request, we are immediately handed an NSAsynchronousFetchResult object. This object has a progress property, which is of type NSProgress. It's this progress property that we need to observe if we want to receive progress updates.

Note that we call resignCurrent on the progress object to balance the earlier becomeCurrentWithPendingUnitCount: call. Keep in mind that both of these methods need to be invoked on the same thread.

Step 4: Removing the Observer

In the completion block of the asynchronous fetch request, we remove the observer and dismiss the progress HUD.

Before we implement observeValueForKeyPath(_:ofObject:change:context:), we need to show the progress HUD before creating the asynchronous fetch request.

Step 5: Progress Reporting

All that's left for us to do, is implement the observeValueForKeyPath(_:ofObject:change:context:) method. We check if context is equal to ProgressContext, create a status object by extracting the number of completed records from the change dictionary, and update the progress HUD. Note that we update the user interface on the main thread.

5. Dummy Data

If we want to properly test our application, we need more data. While I don't recommend using the following approach in a production application, it's a quick and easy way to populate the database with data.

Open AppDelegate.swift and update the application(_:didFinishLaunchingWithOptions:) method as shown below. The populateDatabase() method is a simple helper method in which we add dummy data to the database.

The implementation is straightforward. Because we only want to insert dummy data once, we check the user defaults database for the key "didPopulateDatabase". If the key isn't set, we insert dummy data.

The number of records is important. If you plan to run the application on the iOS Simulator, then it's fine to insert 100,000 or 1,000,000 records. This won't work as good on a physical device and will take too long to complete.

In the for loop, we create a managed object and populate it with data. Note that we don't save the changes of the managed object context during each iteration of the for loop.

Finally, we update the user defaults database to make sure the database isn't populated the next time the application is launched.

Great. Run the application in the iOS Simulator to see the result. You'll notice that it takes a few moments for the asynchronous fetch request to start fetching records and update the progress HUD.

Showing The Progress of The Asynchronous Fetch Request

6. Breaking Changes

By replacing the fetched results controller class with an asynchronous fetch request, we have broken a few pieces of the application. For example, tapping the checkmark of a to-do item doesn't seem to work any longer. While the database is being updated, the user interface doesn't reflect the change. The solution is fairly easy to fix and I'll leave it up to you to implement a solution. You should now have enough knowledge to understand the problem and find a suitable solution.

Conclusion

I'm sure you agree that asynchronous fetching is surprisingly easy to use. The heavy lifting is done by Core Data, which means that there's no need to manually merge the results of the asynchronous fetch request with the managed object context. Your only job is to update the user interface when the asynchronous fetch request hands you the results.

2015-11-27T18:37:08.727Z2015-11-27T18:37:08.727ZBart Jacobs

How to Debug Your Android Wear Apps on a Hardware Device

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

The Android Wear API brings the Android platform to the newest generation of wearable devices and smartwatches. With Android Wear, you can create a user experience designed specifically for wearables.

But how do you debug your applications? While it is possible to debug most Wear features using the Android emulators, sometimes it is helpful to see the application on a real device. 

In this short video tutorial from my recent Android Wear course, I’ll show you how to debug your applications on a physical Wear device.

Watch the Tutorial

Watch the Full Course

In the full course, Develop Apps for Android Wear, I'll teach you about the various UI components specifically designed for Android Wear. You will also learn how to extend your application to use the new Wear notification types. 

I'll use practical examples to demonstrate how each of these new components can improve your wearable device applications, and I'll also show you how to create a basic digital watch face to help customize your users' experiences.

For more help with your Android development projects, check out the Android app templates on Envato Market.

2015-11-30T17:45:20.000Z2015-11-30T17:45:20.000ZPaul Trebilcox-Ruiz

Building a Shopping List Application With CloudKit: Adding Relationships

$
0
0

In the previous tutorial of this series, we added the ability to add, update, and remove shopping lists. A shopping list without any items in it isn't very useful, though. In this tutorial, we'll add the ability to add, update, and remove items from a shopping list. This means that we'll be working with references and the CKReference class.

We'll also take a closer look at the data model of the shopping list application. How easy is it to make changes to the data model and how does the application respond to changes we make in the CloudKit Dashboard?

Prerequisites

Remember that I will be using Xcode 7 and Swift 2. If you are using an older version of Xcode, then keep in mind that you are using a different version of the Swift programming language.

In this tutorial, we will continue where we left off in the second tutorial of this series. You can download or clone the project from GitHub.

1. Shopping List Details

Currently, the user can modify the name of a shopping list by tapping the detail disclosure indicator, but the user should also be able to see the contents of a shopping list by tapping one in the lists view controller. To make this work, we first need a new UIViewController subclass.

Step 1: Creating ListViewController

The ListViewController class will display the contents of a shopping list in a table view. The interface of the ListViewController class looks similar to that of the ListsViewController class. We import the CloudKit and SVProgressHUD frameworks and conform the class to the UITableViewDataSource and UITableViewDelegate protocols. Because we'll be using a table view, we declare a constant, ItemCell, that will serve as a cell reuse identifier.

We declare three outlets, messageLabel of type UILabel!tableView of type UITableView!, and activityIndicatorView of type UIActivityIndicatorView!. The list view controller keeps a reference to the shopping list it is displaying in the list property, which is of type CKRecord!. The items in the shopping list are stored in the items property, which is of type [CKRecord]. Finally, we use a helper variable, selection, to keep track of which item in the shopping list the user has selected. This will become clear later in this tutorial.

Step 2: Creating User Interface

Open Main.storyboard, add a view controller, and set its class to ListViewController in the Identity Inspector. Select the prototype cell of the lists view controller, press the control key, and drag from the prototype cell to the list view controller. Choose Show from the menu that pops up and set identifier to List in the Attributes Inspector.

Add a table view, a label, and an activity indicator view to the view controller's view. Don't forget to wire up the outlets of the view controller as well as those of the table view.

Select the table view and set Prototype Cells to 1 in the Attributes Inspector. Select the prototype cell, set Style to Right Detail, Identifier to ItemCell, and Accessory to Disclosure Indicator. This is what the view controller should look like when you're finished.

List View Controller

Step 3: Configuring View Controller

Before we revisit the CloudKit framework, we need to prepare the view controller for the data it's going to receive. Start by updating the implementation of viewDidLoad. We set the view controller's title to the name of the shopping list and invoke two helper methods, setupView and fetchItems.

The setupView method is identical to the one we implemented in the ListsViewController class.

While we're at it, let's also implement another familiar helper method, updateView. In updateView, we update the user interface of the view controller based on the items stored in the items property.

I'm going to leave fetchItems empty for now. We'll revisit this method once we're finished setting up the list view controller.

Step 4: Table View Data Source Methods

We're almost ready to take the application for another test run. Before we do, we need to implement the UITableViewDataSource protocol. If you've read the previous installments of this series, then the implementation will look familiar.

Step 5: Handling Selection

To tie everything together, we need to revisit the ListsViewController class. Start by implementing the tableView(_:didSelectRowAtIndexPath:) method of the UITableViewDelegate protocol.

We also need to update prepareForSegue(segue:sender:) to handle the segue we created a few moments ago. This means that we need to add a new case to the switch statement.

To satisfy the compiler, we also need to declare the SegueList constant at the top of ListsViewController.swift.

Build and run the application to see if everything is wired up correctly. Because we haven't implemented the fetchItems method yet, no items will be displayed. That's something we need to fix.

2. Fetching Items

Step 1: Create Record Type

Before we can fetch items from the CloudKit backend, we need to create a new record type in the CloudKit Dashboard. Navigate to the CloudKit Dashboard, create a new record type, and name it Items. Each item should have a name so create a new field, set field name to name and set field type to String.

Each item should also know to which shopping list it belongs. That means each item needs a reference to its shopping list. Create a new field, set field name to list and set field type to Reference. The Reference field type was designed for this exact purpose, managing relationships.

Item Record Type

Head back to Xcode, open ListsViewController.swift, and declare a new constant at the top for the Items record type.

Step 2: Fetching Items

Open ListViewController.swift and navigate to the fetchItems method. The implementation is similar to the fetchLists method of the ListsViewController class. There is an important difference, though.

The difference between fetchItems and fetchLists is the predicate we pass to the CKQuery initializer. We're not interested in every item in the user's private database. We're only interested in the items that are associated with a particular shopping list. This is reflected in the predicate of the CKQuery instance.

We create the predicate by passing in a CKReference instance, which we create by invoking init(recordID:action:). This method accepts two arguments, a CKRecordID instance that references the shopping list record and a CKReferenceAction instance that determines what happens when the shopping list is deleted.

Reference actions are very similar to delete rules in Core Data. If the referenced object, the shopping list in this example, is deleted, then the CloudKit framework inspects the reference action to determine what should happen to the records that hold a reference to the deleted record. The CKReferenceAction enum has two member values:

  • None: If the reference is deleted, nothing happens to the records referencing the deleted record.
  • DeleteSelf: If the reference is deleted, every record referencing the deleted record is also deleted.

Because no item should exist without a shopping list, we set the reference action to DeleteSelf.

The processResponseForQuery(records:error:) method contains nothing new. We process the response of the query and update the user interface accordingly.

Build and run the application. You won't see any items yet, but the user interface should update reflect that the shopping list is empty.

3. Adding Items

Step 1: Creating AddItemViewControler

It's time to implement the ability to add items to a shopping list. Start by creating a new UIViewController subclass, AddItemViewController. The interface of the view controller is similar to that of the AddListViewController class.

At the top, we import the CloudKit and SVProgressHUD frameworks. We declare the AddItemViewControllerDelegate protocol, which will serve the same purpose as the AddListViewControllerDelegate protocol. The protocol defines two methods, one for adding items and one for updating items.

We declare two outlets, a text field and a bar button item. We also declare a property for the delegate and a helper variable, newItem, that helps us determine whether we're creating a new item or updating an existing item. Finally, we declare a property list for referencing the shopping list to which the item will be added and a property item for the item we're creating or updating.

Before we create the user interface, let's implement two actions that we'll need in the storyboard, cancel(_:) and save(_:). We'll update the implementation of the save(_:) action later in this tutorial.

Step 2: Creating User Interface

Open Main.storyboard, add a bar button item to the navigation bar of the list view controller, and set System Item to Add in the Attributes Inspector. Drag a view controller from the Object Library and set its class to AddItemViewController. Create a segue from the bar button item we just created to the add item view controller. Choose Show from the menu that pops up and set the segue's identifier to ItemDetail.

Add two bar button items to the navigation bar of the add item view controller, a cancel button on the left and a save button on the right. Connect each bar button item to its corresponding action. Add a text field to the view controller's view and don't forget to connect the outlets of the view controller. This is what the add item view controller should look like when you're finished.

Add Item View Controller

Step 3: Configuring View Controller

The implementation of the add item view controller contains nothing that we haven't covered yet. There's one exception, though, which we'll discuss in a moment. Let's start by configuring the view controller in viewDidLoad.

We invoke setupView, a helper method, and update the value of newItem. If the item property is equal to nilnewItem is equal to true. This helps us determine whether we're creating or updating a shopping list item.

We also add the view controller as an observer for notifications of type UITextFieldTextDidChangeNotification. This means that the view controller is notified when the contents of the nameTextField changes.

In viewDidAppear(animated:), we show the keyboard by calling becomeFirstResponder on nameTextField.

The setupView method invokes two helper methods, updateNameTextField and updateSaveButton. The implementation of these helper methods is straightforward. In updateNameTextField, we populate the text field. In updateSaveButton, we enable or disable the save button based on the contents of the text field.

Before we take a look at the updated implementation of the save(_:) method, we need to implement the textFieldDidChange(_:) method. All we do is invoke updateSaveButton to enable or disable the save button.

Step 4: Saving Items

The save(_:) method is the most interesting method of the AddItemViewController class, because it shows us how to work with CloudKit references. Take a look at the implementation of the save(_:) method below.

Most of its implementation should look familiar since we covered saving records in the AddListViewController class. What interests us most is how the item keeps a reference to its shopping list. We first create a CKReference instance by invoking the designated initializer, init(recordID:action:). We covered the details of creating a CKReference instance a few minutes ago when we created the query for fetching shopping list items.

Telling the item about this reference is easy. We invoke setObjec(_:forKey:) on the item property, passing in the CKReference instance as the value and "list" as the key. The key corresponds with the field name we assigned in the CloudKit Dashboard. Saving the item to iCloud is identical to what we've covered before. That's how easy it is to work with CloudKit references.

The implementation of processResponse(record:error:) contains nothing new. We check to see if any errors popped up and, if no errors were thrown, we notify the delegate.

Step 5: Updating ListViewController

We still have some work to do in the ListViewController class. Start by conforming the ListViewController class to the AddItemViewControllerDelegate protocol. This is also a good moment to declare a constant for the segue with identifier ItemDetail.

Implementing the AddItemViewControllerDelegate protocol is trivial. In controller(_:didAddItem:), we add the new item to items, sort items, reload the table view, and invoke updateView.

The implementation of controller(_:didUpdateItem:) is even easier. We sort items and reload the table view.

In sortItems, we sort the array of CKRecord instances by name using the sortInPlace function, a method of the MutableCollectionType protocol.

There are two more features we need to implement, updating and deleting shopping list items.

Step 6: Deleting Items

To delete items, we need to implement tableView(_:commitEditingStyle:forRowAtIndexPath:) of the UITableViewDataSource protocol. We fetch the shopping list item that needs to be deleted and pass it to the deleteRecord(_:) method.

The implementation of deleteRecord(_:) doesn't contain anything new. We invoke deleteRecordWithID(_:completionHandler:) on the private database and process the response in the completion handler.

In processResponseForDeleteRequest(record:recordID:error:), we update the items property and the user interface. If something went wrong, we notify the user by showing an alert.

Step 7: Updating Items

The user can update an item by tapping the detail disclosure indicator. This means we need to implement the tableView(_:accessoryButtonTappedForRowWithIndexPath:) delegate method. In this method, we store the user's selection and manually perform the ListDetail segue. Note that nothing happens in the tableView(_:didSelectRowAtIndexPath:) method. All we do is deselect the row the user tapped.

In prepareForSegue(_:sender:), we fetch the shopping list item using the value of the selection property and configure the destination view controller, an instance of the AddItemViewController class.

That's all we need to do to delete and update shopping list items. In the next section, we explore how easy it is to update the data model in the CloudKit Dashboard.

4. Updating the Data Model

If you've ever worked with Core Data, then you know that updating the data model should be done with caution. You need to make sure you don't break anything or corrupt any of the application's persistent stores. CloudKit is a bit more flexible.

The Items record type currently has two fields, name and list. I want to show you what it involves to update the data model by adding a new field. Open the CloudKit Dashboard and add a new field to the Items record. Set field name to number and set field type to Int(64). Don't forget to save your changes.

Update Item Record Type

Let's now add the ability to modify an item's number. Open AddItemViewController.swift and declare two outlets, a label and a stepper.

We also need to add an action that is triggered when the stepper's value changes. In numberDidChange(_:), we update the contents of numberLabel.

Open Main.storyboard and add a label and a stepper to the add item view controller. Connect the outlets of the view controller to the corresponding user interface elements and connect the numberDidChange(_:) action to the stepper for the Value Changed event.

Update Add Item View Controller

The save(_:) action of the AddItemViewController class also changes slightly. Let's see what that looks like.

We only need to add two lines of code. A the top, we store the value of the stepper in a constant, number. When we configure item, we set number as the value for the "number" key and that's all there is to it.

We also need to implement a helper method to update the user interface of the add item view controller. The updateNumberStepper method checks if the record has a field named number and updates the stepper if it does.

We invoke updateNumberStepper in the setupView method of the AddItemViewController class.

To visualize the number of each item, we need to make one change to the ListViewController. In tableView(_:cellForRowAtIndexPath:), we set the contents of the cell's right label to the value of the item's number field.

That's all we need to do to implement the changes we made to the data model. There's no need to perform a migration or anything like that. CloudKit takes care of the nitty gritty details.

Conclusion

You should now have a proper foundation of the CloudKit framework. I hope you agree that Apple has done a great job with the framework and the CloudKit Dashboard. There's a lot that we haven't covered in this series, but this should give you enough to get started with CloudKit in your own projects.

If you have any questions or comments, feel free to leave them in the comments below or reach out to me on Twitter.

2015-11-30T18:45:02.000Z2015-11-30T18:45:02.000ZBart Jacobs

Building a Shopping List Application With CloudKit: Adding Relationships

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

In the previous tutorial of this series, we added the ability to add, update, and remove shopping lists. A shopping list without any items in it isn't very useful, though. In this tutorial, we'll add the ability to add, update, and remove items from a shopping list. This means that we'll be working with references and the CKReference class.

We'll also take a closer look at the data model of the shopping list application. How easy is it to make changes to the data model and how does the application respond to changes we make in the CloudKit Dashboard?

Prerequisites

Remember that I will be using Xcode 7 and Swift 2. If you are using an older version of Xcode, then keep in mind that you are using a different version of the Swift programming language.

In this tutorial, we will continue where we left off in the second tutorial of this series. You can download or clone the project from GitHub.

1. Shopping List Details

Currently, the user can modify the name of a shopping list by tapping the detail disclosure indicator, but the user should also be able to see the contents of a shopping list by tapping one in the lists view controller. To make this work, we first need a new UIViewController subclass.

Step 1: Creating ListViewController

The ListViewController class will display the contents of a shopping list in a table view. The interface of the ListViewController class looks similar to that of the ListsViewController class. We import the CloudKit and SVProgressHUD frameworks and conform the class to the UITableViewDataSource and UITableViewDelegate protocols. Because we'll be using a table view, we declare a constant, ItemCell, that will serve as a cell reuse identifier.

We declare three outlets, messageLabel of type UILabel!tableView of type UITableView!, and activityIndicatorView of type UIActivityIndicatorView!. The list view controller keeps a reference to the shopping list it is displaying in the list property, which is of type CKRecord!. The items in the shopping list are stored in the items property, which is of type [CKRecord]. Finally, we use a helper variable, selection, to keep track of which item in the shopping list the user has selected. This will become clear later in this tutorial.

Step 2: Creating User Interface

Open Main.storyboard, add a view controller, and set its class to ListViewController in the Identity Inspector. Select the prototype cell of the lists view controller, press the control key, and drag from the prototype cell to the list view controller. Choose Show from the menu that pops up and set identifier to List in the Attributes Inspector.

Add a table view, a label, and an activity indicator view to the view controller's view. Don't forget to wire up the outlets of the view controller as well as those of the table view.

Select the table view and set Prototype Cells to 1 in the Attributes Inspector. Select the prototype cell, set Style to Right Detail, Identifier to ItemCell, and Accessory to Disclosure Indicator. This is what the view controller should look like when you're finished.

List View Controller

Step 3: Configuring View Controller

Before we revisit the CloudKit framework, we need to prepare the view controller for the data it's going to receive. Start by updating the implementation of viewDidLoad. We set the view controller's title to the name of the shopping list and invoke two helper methods, setupView and fetchItems.

The setupView method is identical to the one we implemented in the ListsViewController class.

While we're at it, let's also implement another familiar helper method, updateView. In updateView, we update the user interface of the view controller based on the items stored in the items property.

I'm going to leave fetchItems empty for now. We'll revisit this method once we're finished setting up the list view controller.

Step 4: Table View Data Source Methods

We're almost ready to take the application for another test run. Before we do, we need to implement the UITableViewDataSource protocol. If you've read the previous installments of this series, then the implementation will look familiar.

Step 5: Handling Selection

To tie everything together, we need to revisit the ListsViewController class. Start by implementing the tableView(_:didSelectRowAtIndexPath:) method of the UITableViewDelegate protocol.

We also need to update prepareForSegue(segue:sender:) to handle the segue we created a few moments ago. This means that we need to add a new case to the switch statement.

To satisfy the compiler, we also need to declare the SegueList constant at the top of ListsViewController.swift.

Build and run the application to see if everything is wired up correctly. Because we haven't implemented the fetchItems method yet, no items will be displayed. That's something we need to fix.

2. Fetching Items

Step 1: Create Record Type

Before we can fetch items from the CloudKit backend, we need to create a new record type in the CloudKit Dashboard. Navigate to the CloudKit Dashboard, create a new record type, and name it Items. Each item should have a name so create a new field, set field name to name and set field type to String.

Each item should also know to which shopping list it belongs. That means each item needs a reference to its shopping list. Create a new field, set field name to list and set field type to Reference. The Reference field type was designed for this exact purpose, managing relationships.

Item Record Type

Head back to Xcode, open ListsViewController.swift, and declare a new constant at the top for the Items record type.

Step 2: Fetching Items

Open ListViewController.swift and navigate to the fetchItems method. The implementation is similar to the fetchLists method of the ListsViewController class. There is an important difference, though.

The difference between fetchItems and fetchLists is the predicate we pass to the CKQuery initializer. We're not interested in every item in the user's private database. We're only interested in the items that are associated with a particular shopping list. This is reflected in the predicate of the CKQuery instance.

We create the predicate by passing in a CKReference instance, which we create by invoking init(recordID:action:). This method accepts two arguments, a CKRecordID instance that references the shopping list record and a CKReferenceAction instance that determines what happens when the shopping list is deleted.

Reference actions are very similar to delete rules in Core Data. If the referenced object, the shopping list in this example, is deleted, then the CloudKit framework inspects the reference action to determine what should happen to the records that hold a reference to the deleted record. The CKReferenceAction enum has two member values:

  • None: If the reference is deleted, nothing happens to the records referencing the deleted record.
  • DeleteSelf: If the reference is deleted, every record referencing the deleted record is also deleted.

Because no item should exist without a shopping list, we set the reference action to DeleteSelf.

The processResponseForQuery(records:error:) method contains nothing new. We process the response of the query and update the user interface accordingly.

Build and run the application. You won't see any items yet, but the user interface should update reflect that the shopping list is empty.

3. Adding Items

Step 1: Creating AddItemViewControler

It's time to implement the ability to add items to a shopping list. Start by creating a new UIViewController subclass, AddItemViewController. The interface of the view controller is similar to that of the AddListViewController class.

At the top, we import the CloudKit and SVProgressHUD frameworks. We declare the AddItemViewControllerDelegate protocol, which will serve the same purpose as the AddListViewControllerDelegate protocol. The protocol defines two methods, one for adding items and one for updating items.

We declare two outlets, a text field and a bar button item. We also declare a property for the delegate and a helper variable, newItem, that helps us determine whether we're creating a new item or updating an existing item. Finally, we declare a property list for referencing the shopping list to which the item will be added and a property item for the item we're creating or updating.

Before we create the user interface, let's implement two actions that we'll need in the storyboard, cancel(_:) and save(_:). We'll update the implementation of the save(_:) action later in this tutorial.

Step 2: Creating User Interface

Open Main.storyboard, add a bar button item to the navigation bar of the list view controller, and set System Item to Add in the Attributes Inspector. Drag a view controller from the Object Library and set its class to AddItemViewController. Create a segue from the bar button item we just created to the add item view controller. Choose Show from the menu that pops up and set the segue's identifier to ItemDetail.

Add two bar button items to the navigation bar of the add item view controller, a cancel button on the left and a save button on the right. Connect each bar button item to its corresponding action. Add a text field to the view controller's view and don't forget to connect the outlets of the view controller. This is what the add item view controller should look like when you're finished.

Add Item View Controller

Step 3: Configuring View Controller

The implementation of the add item view controller contains nothing that we haven't covered yet. There's one exception, though, which we'll discuss in a moment. Let's start by configuring the view controller in viewDidLoad.

We invoke setupView, a helper method, and update the value of newItem. If the item property is equal to nilnewItem is equal to true. This helps us determine whether we're creating or updating a shopping list item.

We also add the view controller as an observer for notifications of type UITextFieldTextDidChangeNotification. This means that the view controller is notified when the contents of the nameTextField changes.

In viewDidAppear(animated:), we show the keyboard by calling becomeFirstResponder on nameTextField.

The setupView method invokes two helper methods, updateNameTextField and updateSaveButton. The implementation of these helper methods is straightforward. In updateNameTextField, we populate the text field. In updateSaveButton, we enable or disable the save button based on the contents of the text field.

Before we take a look at the updated implementation of the save(_:) method, we need to implement the textFieldDidChange(_:) method. All we do is invoke updateSaveButton to enable or disable the save button.

Step 4: Saving Items

The save(_:) method is the most interesting method of the AddItemViewController class, because it shows us how to work with CloudKit references. Take a look at the implementation of the save(_:) method below.

Most of its implementation should look familiar since we covered saving records in the AddListViewController class. What interests us most is how the item keeps a reference to its shopping list. We first create a CKReference instance by invoking the designated initializer, init(recordID:action:). We covered the details of creating a CKReference instance a few minutes ago when we created the query for fetching shopping list items.

Telling the item about this reference is easy. We invoke setObjec(_:forKey:) on the item property, passing in the CKReference instance as the value and "list" as the key. The key corresponds with the field name we assigned in the CloudKit Dashboard. Saving the item to iCloud is identical to what we've covered before. That's how easy it is to work with CloudKit references.

The implementation of processResponse(record:error:) contains nothing new. We check to see if any errors popped up and, if no errors were thrown, we notify the delegate.

Step 5: Updating ListViewController

We still have some work to do in the ListViewController class. Start by conforming the ListViewController class to the AddItemViewControllerDelegate protocol. This is also a good moment to declare a constant for the segue with identifier ItemDetail.

Implementing the AddItemViewControllerDelegate protocol is trivial. In controller(_:didAddItem:), we add the new item to items, sort items, reload the table view, and invoke updateView.

The implementation of controller(_:didUpdateItem:) is even easier. We sort items and reload the table view.

In sortItems, we sort the array of CKRecord instances by name using the sortInPlace function, a method of the MutableCollectionType protocol.

There are two more features we need to implement, updating and deleting shopping list items.

Step 6: Deleting Items

To delete items, we need to implement tableView(_:commitEditingStyle:forRowAtIndexPath:) of the UITableViewDataSource protocol. We fetch the shopping list item that needs to be deleted and pass it to the deleteRecord(_:) method.

The implementation of deleteRecord(_:) doesn't contain anything new. We invoke deleteRecordWithID(_:completionHandler:) on the private database and process the response in the completion handler.

In processResponseForDeleteRequest(record:recordID:error:), we update the items property and the user interface. If something went wrong, we notify the user by showing an alert.

Step 7: Updating Items

The user can update an item by tapping the detail disclosure indicator. This means we need to implement the tableView(_:accessoryButtonTappedForRowWithIndexPath:) delegate method. In this method, we store the user's selection and manually perform the ListDetail segue. Note that nothing happens in the tableView(_:didSelectRowAtIndexPath:) method. All we do is deselect the row the user tapped.

In prepareForSegue(_:sender:), we fetch the shopping list item using the value of the selection property and configure the destination view controller, an instance of the AddItemViewController class.

That's all we need to do to delete and update shopping list items. In the next section, we explore how easy it is to update the data model in the CloudKit Dashboard.

4. Updating the Data Model

If you've ever worked with Core Data, then you know that updating the data model should be done with caution. You need to make sure you don't break anything or corrupt any of the application's persistent stores. CloudKit is a bit more flexible.

The Items record type currently has two fields, name and list. I want to show you what it involves to update the data model by adding a new field. Open the CloudKit Dashboard and add a new field to the Items record. Set field name to number and set field type to Int(64). Don't forget to save your changes.

Update Item Record Type

Let's now add the ability to modify an item's number. Open AddItemViewController.swift and declare two outlets, a label and a stepper.

We also need to add an action that is triggered when the stepper's value changes. In numberDidChange(_:), we update the contents of numberLabel.

Open Main.storyboard and add a label and a stepper to the add item view controller. Connect the outlets of the view controller to the corresponding user interface elements and connect the numberDidChange(_:) action to the stepper for the Value Changed event.

Update Add Item View Controller

The save(_:) action of the AddItemViewController class also changes slightly. Let's see what that looks like.

We only need to add two lines of code. A the top, we store the value of the stepper in a constant, number. When we configure item, we set number as the value for the "number" key and that's all there is to it.

We also need to implement a helper method to update the user interface of the add item view controller. The updateNumberStepper method checks if the record has a field named number and updates the stepper if it does.

We invoke updateNumberStepper in the setupView method of the AddItemViewController class.

To visualize the number of each item, we need to make one change to the ListViewController. In tableView(_:cellForRowAtIndexPath:), we set the contents of the cell's right label to the value of the item's number field.

That's all we need to do to implement the changes we made to the data model. There's no need to perform a migration or anything like that. CloudKit takes care of the nitty gritty details.

Conclusion

You should now have a proper foundation of the CloudKit framework. I hope you agree that Apple has done a great job with the framework and the CloudKit Dashboard. There's a lot that we haven't covered in this series, but this should give you enough to get started with CloudKit in your own projects.

If you have any questions or comments, feel free to leave them in the comments below or reach out to me on Twitter.

2015-11-30T18:45:02.000Z2015-11-30T18:45:02.000ZBart Jacobs

7 Android Templates to Inspire Your Next Project

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

Project templates are a great way to learn from other people's work. This article lists a few popular Android templates available on Envato Market. If you are looking for inspiration or you're building an application and need help with a particular feature, then you may find your answer in some of these templates.

Restaurant Finder

This template bursts with features and it even includes a backend ready to be deployed to a server. The application enables users to search for nearby restaurants, read reviews, share on social media, and it also includes the ability to book a table via email or text message.

Restaurant Finder

Almost every modern, mobile application talks to a backend for one reason or another and this application is no different. The template includes a backend for storing restaurants and user profiles. It also includes an analytics dashboard that shows metrics about the restaurants and users of the application. If you need inspiration for a location based application, then this template is worth checking out.

Your Radio App

If you ever wanted to know how to stream audio in an Android application, then this template is worth checking out. The application is focused on streaming audio from online radio stations. The template includes a feature packed Android application as well as a backend for managing the radio stations users can listen to.

Your Radio App

The template is compatible with both Android Studio and Eclipse and it relies on Parse for push notifications. It also includes AdMob for ad management. The application supports a wide range of stream formats and has a beautiful, modern user interface. If you're not convinced yet, then download the application from Google Play to try it out.

Educational App for Preschoolers

Mobile phones and tablets are a big hit with children. Because these devices are so easy to use, children intuitively know what to do when they're given one. This template includes an application for the youngest, teaching them the alphabet and numbers through sounds and images.

Educational App for Preschoolers

The template includes a number of games you can choose and learn from. The template is compatible with Eclipse and easy to customize to fit your needs.

Maintenance Service App

More and more traditional businesses are going mobile and this template serves the services market. In addition to the mobile application, the template also includes a backend. The application itself is rich in features and includes user registration, the possibility to schedule a service, and even the ability for customers to leave a review.

Maintenance Service App

The user interface is clean and modern. The application is compatible with Android Marshmallow, but it also supports older versions of the Android operating system. If you'd like to see what the application looks like, then watch this video the author put on YouTube.

Taxi Booking App

I already mentioned that many traditional businesses are making the jump to mobile and this includes taxi companies. There's a reason why Uber and Lyft are so popular. This Android template is quite impressive. It contains a feature rich Android application as well as a powerful backend, a complete solution. The application includes an interactive map with vehicle information and tracking, voice recognition, and support for push notifications.

Taxi Booking App

The template offers a solution for both users and drivers. Users can order a ride with the mobile application and drivers receive a notification when someone requests a ride. Even if you don't plan to build a taxi booking application, there's a lot you can learn from browsing the ins and outs of this template.

Inventory Management App

Managing inventory used to be either time consuming, using pen and paper, or costly due to expensive hardware and infrastructure. This is no longer the case and this Android template shows what the possibilities are. Adding, updating, and viewing products is easy and straightforward, and the user is notified when inventory is running low.

Inventory Management App

The template is lightweight but surprisingly powerful. Products are stored locally in a SQLite database and there's support for exporting to a spreadsheet. You can download the application from the author's website, if you'd like to take it for a spin.

Pixel Art

Who doesn't love pixel art? I think every developer does. This application template is a simple drawing application that focuses on pixel art. The tools are simple, but I really like the results you can get with it.

Pixel Art

The author included a short video in which he creates Luigi, Mario's brother. If you want to learn more about drawing on Android, then this is a great template to start with.

More?

Envato Market contains dozens of mobile application templates to get you started with your next project. These templates are great to learn or to see how fellow developers have implemented a particular feature. They're also great if you're looking for that kick of inspiration. Check out the Android templates on Envato Market.

2015-12-01T14:45:35.000Z2015-12-01T14:45:35.000ZBart Jacobs

Understanding the iOS Ecosystem

$
0
0

Before you begin building iOS applications, it is crucial that you first understand the ecosystem. This article examines the fundamentals of Apple's operating systems, the various devices available, and Apple's App Store.

1. Why iOS?

Before the arrival of Android and Windows Phone, Apple was the dominant player in the mobile space, rivaled only by Nokia and BlackBerry. With the emergence of new mobile platforms, it has become more and more important to ask yourself which platform is best suited for you.

In spite of Apple's head start in 2007, Android has surpassed iOS in market share. What does that mean for iOS? Is it still a platform worth developing for? It sure is. There are many great reasons to get started with iOS development today.

  • Strong Financial Incentives: People spend more money on Apple's App Store than on any other mobile platform. Despite the fact that Android has become the dominant player in the mobile space, the iOS platform remains more lucrative for developers.
  • Walled Garden: Over the years Apple's App Store has received a lot of criticism from developers and customers, Apple's review process in particular. It is clear, however, that Apple's policy has led to an App Store in which the quality of its applications is higher than in any other mobile store. Customers also tend to feel much safer when purchasing applications from the App Store than they do on other—more open—platforms, such as Google Play.
  • Community and Support: The iOS developer community is a great community to be part of. There is an almost unlimited supply of articles, tutorials, and documentation to help you out when you find yourself stuck with a problem. Also, Apple's documentation of the iOS SDK is superb, not to mention the hundreds of WWDC (World Wide Developer Conference) videos available on Apple's developer website.

People often forget, or don't know, that Android and iOS are very different platforms. Even though both platforms were designed for the mobile space, the iOS ecosystem differs in many respects from the Android ecosystem.

From a development perspective, most people seem to find it easier to develop for iOS than for Android. Don't misunderstand me, I am not referring to the technology stack that each platform uses nor am I referring to the available tools for each platform. Two reasons are at the foundation of the chasm between iOS and Android, fragmentation and adoption rate.

Fragmentation

One of Android's core strengths is at the same time one of its principal weaknesses. As most of you know, the Android operating system is released as an open source project and can therefore be used and be modified by anyone. Numerous hardware manufacturers have seen the potential of Android, especially since it is backed by Google.

As a result, Android quickly gained in popularity. The problem is that each hardware manufacturer modifies Android to fit their needs and a wide variety of form factors have emerged since the introduction of Android.

Even though Android's market share may seem like a big pot of honey, it's a pain to create software that runs on each Android version currently available. Due to the thousands of different devices that run Android, testing software on hardware is no trivial task. As you can imagine, support and compatibility become a real challenge.

Adoption Rate

Traditionally, in many countries, the wireless market is under tight control by cellular carriers. From the very beginning, Apple knew it needed to be in control of its mobile devices to provide the best user experience possible. The result is that customers can upgrade their iOS devices to the latest version of iOS the same day it is released to the public. This is a major advantage of the iOS platform and the result is substantial. Less than a week after the release of iOS 9, over 50% of iOS devices had been upgraded to iOS 9.

Let's compare this with Android. In September 2015, only 20% of Android users had upgraded their devices to Lollipop (released in 2014) and less than 40% had upgraded to KitKat (released in October 2013).

The reason for bringing up these numbers is not to downplay the Android platform or any other mobile platform. What I want to emphasize is the impact the adoption rate has on the application ecosystem of these platforms.

The slower users adopt a new release of an operating system, the longer developers are forced to support older versions of the operating system. It also becomes less appealing to adopt new technologies, which can only be used on a fraction of Android devices.

2. Why Native?

If you are a frequent reader of Envato Tuts+, then you may have heard of cross-platform frameworks like Xamarin, React NativePhoneGap, Apache Cordova, and Titanium Mobile. You might be wondering why you should go through the trouble of learning Swift or Objective-C when you can create iOS applications using C# or JavaScript. Let me give you a brief rundown of your options if you decide to develop applications for iOS.

Web Applications

A web application is your first option and this was, in fact, the only option prior to the introduction of the native iOS SDK in 2008. The upside of web applications is that they don't have to deal with the App Store or Apple's review process. Why is that? A web application is a fancy name for a website that acts and behaves like an application. All you need is a browser, such as Mobile Safari or Google Chrome.

Web applications have clear advantages. They are cross-platform by default since the applications run in a browser. Another advantage is the learning curve to create web applications. If you are familiar with web development, then you'll be up and running in no time.

Of course, the downsides of web applications shouldn't be ignored either. A web application has limited access to the capabilities of the devices they run on. Mobile web applications are quite powerful thanks to HTML5 and JavaScript. However, there are distinct limitations in terms of what they can do. You won't be able to use the cool features of the iPad and iPhone. Also, web applications typically require a network connection to work, although there are exceptions to this rule.

Perhaps the biggest downside to building web applications is that, in general, they feel significantly slower than native applications. The responsiveness of web applications is improving every year, but the inherited delay added by the browser should not be overlooked or ignored. The experience is different. There's no doubt about that.

Mobile Cross-Platform Frameworks

The promise of a cross-platform framework is that developers can write an application that can be deployed to multiple mobile devices from a single code base. This is accomplished through a number of approaches.

Some frameworks, like PhoneGap and Apache Cordova, use the native SDK of the platform to create a web view in which the application is embedded. As with web applications, this imposes limitations in terms of functionality. The main advantage is that the application feels like a native application in terms of user experience and that it can be distributed through the platform's store.

Even though mobile development frameworks might seem like the holy grail for mobile development, there are a number of downsides that need to be considered. The most important downside is that your application depends on a third party framework. In other words, your project's code base depends on the company that provides the cross-platform solution. If that company goes out of business or is slow to implement changes made to the native SDK, you could be forced to start over from scratch. That's a risk that you need to consider.

iOS SDK

Choosing to develop with the native SDK is the best choice if you want to create applications that stand out and take advantage of the device's capabilities. Opting for a native application also means that you will work in a robust development environment and that you can rely on Apple's development tools, utilities, and support.

3. iOS Ecosystem

One of the most appealing aspects of the iOS ecosystem is its simplicity. The list of devices capable of running iOS is surprisingly short compared to Android or Windows Phone. This means that testing iOS applications is much less cumbersome compared to other platforms.

As I mentioned earlier, Android has surpassed iOS in terms of market share, but this is only part of the story. The iOS platform accounts for more than a third of web usage on mobile devices. What does this tell us about the mobile space? It tells us that iOS remains a dominant player in the mobile space, at least online, and this despite Android's much larger market share.

Devices

There are essentially two device families within the iOS ecosystem:

  • the iPad device family
  • the iPhone device family, which also includes the iPod Touch

For a complete overview, I recommend taking a look at this list. The primary differences within the iPhone device family are hardware capabilities and screen size. For iPhone and iPod Touch, there are four possible screen sizes:

  • 3.5"
  • 4.0"
  • 4.7"
  • 5.5"

For the iPad device family, there are three possible screen sizes:

  • 7.9"
  • 9.7"
  • 12.9"

The difference in screen size does impact development, but it doesn't add much overhead for most applications. I will talk more about this in the course of the series.

In 2012, Apple introduced the iPad Mini and in 2015 the iPad family was expanded with the iPad Pro. Even though the introductions of the iPad Mini and the iPad Pro caused a ripple in the technology industry, it has had little impact for iOS developers.

The screen of the iPad Mini, for example, is significantly smaller than that of the 9.7" iPad Air, but the resolution is identical to the resolution of the 9.7" iPad devices. Due to the iPad Mini's smaller screen, the average size of the touch targets is smaller and this might pose a problem for some applications.

iOS

Apple traditionally releases a new version of its mobile operating system every year. To date, Apple has released nine major versions of its mobile operating system with the most recent release being iOS 9.

Device support is an aspect of iOS that people often overlook. Take the iPhone 4S, for example. The iPhone 4S was released in 2011 and is still capable of running iOS 9. There is no mobile platform that comes even close to this in terms of device support.

App Store

One of the key reasons to develop for the iOS platform is the incredible success of the App Store. Selling software has never been easier thanks to Apple's App Store on iOS and OS X. With more than one million applications it is getting a bit crowded in the App Store for iOS, but keep in mind that the number of iOS devices also continues to grow exponentially.

The mobile space is in its infancy and there is still so much potential that is waiting to be uncovered. As with the web in the late nineties, the mobile space will continue to grow at a fast pace and the amount of money that can be made increases with every new smartphone, smartwatch, and tablet sold.

4. watchOS and tvOS

In 2015, Apple announced two new operating systems, watchOS for Apple Watch and tvOS for Apple TV. Apple has opened up both platforms for third party developers, bringing third party applications to your wrist and living room.

The tools for watchOS and tvOS development are identical to those for iOS development. This is yet another reason for choosing for the iOS ecosystem. Apple's operating systems, OS X, iOS, watchOS, and tvOS, are tightly integrated and the possibilities are virtually endless.

Conclusion

You now have a clear picture of the iOS ecosystem and I hope that I was able to convince you to get started with iOS development. In the next post, I will show you how to get started with the native SDK by setting up the development environment. You're going to be surprised by how easy this is.

If you have any questions or comments, you can leave them in the comments below or reach out to me on Twitter.

2015-12-01T17:45:12.000Z2015-12-01T17:45:12.000ZBart Jacobs

Understanding the iOS Ecosystem

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

Before you begin building iOS applications, it is crucial that you first understand the ecosystem. This article examines the fundamentals of Apple's operating systems, the various devices available, and Apple's App Store.

1. Why iOS?

Before the arrival of Android and Windows Phone, Apple was the dominant player in the mobile space, rivaled only by Nokia and BlackBerry. With the emergence of new mobile platforms, it has become more and more important to ask yourself which platform is best suited for you.

In spite of Apple's head start in 2007, Android has surpassed iOS in market share. What does that mean for iOS? Is it still a platform worth developing for? It sure is. There are many great reasons to get started with iOS development today.

  • Strong Financial Incentives: People spend more money on Apple's App Store than on any other mobile platform. Despite the fact that Android has become the dominant player in the mobile space, the iOS platform remains more lucrative for developers.
  • Walled Garden: Over the years Apple's App Store has received a lot of criticism from developers and customers, Apple's review process in particular. It is clear, however, that Apple's policy has led to an App Store in which the quality of its applications is higher than in any other mobile store. Customers also tend to feel much safer when purchasing applications from the App Store than they do on other—more open—platforms, such as Google Play.
  • Community and Support: The iOS developer community is a great community to be part of. There is an almost unlimited supply of articles, tutorials, and documentation to help you out when you find yourself stuck with a problem. Also, Apple's documentation of the iOS SDK is superb, not to mention the hundreds of WWDC (World Wide Developer Conference) videos available on Apple's developer website.

People often forget, or don't know, that Android and iOS are very different platforms. Even though both platforms were designed for the mobile space, the iOS ecosystem differs in many respects from the Android ecosystem.

From a development perspective, most people seem to find it easier to develop for iOS than for Android. Don't misunderstand me, I am not referring to the technology stack that each platform uses nor am I referring to the available tools for each platform. Two reasons are at the foundation of the chasm between iOS and Android, fragmentation and adoption rate.

Fragmentation

One of Android's core strengths is at the same time one of its principal weaknesses. As most of you know, the Android operating system is released as an open source project and can therefore be used and be modified by anyone. Numerous hardware manufacturers have seen the potential of Android, especially since it is backed by Google.

As a result, Android quickly gained in popularity. The problem is that each hardware manufacturer modifies Android to fit their needs and a wide variety of form factors have emerged since the introduction of Android.

Even though Android's market share may seem like a big pot of honey, it's a pain to create software that runs on each Android version currently available. Due to the thousands of different devices that run Android, testing software on hardware is no trivial task. As you can imagine, support and compatibility become a real challenge.

Adoption Rate

Traditionally, in many countries, the wireless market is under tight control by cellular carriers. From the very beginning, Apple knew it needed to be in control of its mobile devices to provide the best user experience possible. The result is that customers can upgrade their iOS devices to the latest version of iOS the same day it is released to the public. This is a major advantage of the iOS platform and the result is substantial. Less than a week after the release of iOS 9, over 50% of iOS devices had been upgraded to iOS 9.

Let's compare this with Android. In September 2015, only 20% of Android users had upgraded their devices to Lollipop (released in 2014) and less than 40% had upgraded to KitKat (released in October 2013).

The reason for bringing up these numbers is not to downplay the Android platform or any other mobile platform. What I want to emphasize is the impact the adoption rate has on the application ecosystem of these platforms.

The slower users adopt a new release of an operating system, the longer developers are forced to support older versions of the operating system. It also becomes less appealing to adopt new technologies, which can only be used on a fraction of Android devices.

2. Why Native?

If you are a frequent reader of Envato Tuts+, then you may have heard of cross-platform frameworks like Xamarin, React NativePhoneGap, Apache Cordova, and Titanium Mobile. You might be wondering why you should go through the trouble of learning Swift or Objective-C when you can create iOS applications using C# or JavaScript. Let me give you a brief rundown of your options if you decide to develop applications for iOS.

Web Applications

A web application is your first option and this was, in fact, the only option prior to the introduction of the native iOS SDK in 2008. The upside of web applications is that they don't have to deal with the App Store or Apple's review process. Why is that? A web application is a fancy name for a website that acts and behaves like an application. All you need is a browser, such as Mobile Safari or Google Chrome.

Web applications have clear advantages. They are cross-platform by default since the applications run in a browser. Another advantage is the learning curve to create web applications. If you are familiar with web development, then you'll be up and running in no time.

Of course, the downsides of web applications shouldn't be ignored either. A web application has limited access to the capabilities of the devices they run on. Mobile web applications are quite powerful thanks to HTML5 and JavaScript. However, there are distinct limitations in terms of what they can do. You won't be able to use the cool features of the iPad and iPhone. Also, web applications typically require a network connection to work, although there are exceptions to this rule.

Perhaps the biggest downside to building web applications is that, in general, they feel significantly slower than native applications. The responsiveness of web applications is improving every year, but the inherited delay added by the browser should not be overlooked or ignored. The experience is different. There's no doubt about that.

Mobile Cross-Platform Frameworks

The promise of a cross-platform framework is that developers can write an application that can be deployed to multiple mobile devices from a single code base. This is accomplished through a number of approaches.

Some frameworks, like PhoneGap and Apache Cordova, use the native SDK of the platform to create a web view in which the application is embedded. As with web applications, this imposes limitations in terms of functionality. The main advantage is that the application feels like a native application in terms of user experience and that it can be distributed through the platform's store.

Even though mobile development frameworks might seem like the holy grail for mobile development, there are a number of downsides that need to be considered. The most important downside is that your application depends on a third party framework. In other words, your project's code base depends on the company that provides the cross-platform solution. If that company goes out of business or is slow to implement changes made to the native SDK, you could be forced to start over from scratch. That's a risk that you need to consider.

iOS SDK

Choosing to develop with the native SDK is the best choice if you want to create applications that stand out and take advantage of the device's capabilities. Opting for a native application also means that you will work in a robust development environment and that you can rely on Apple's development tools, utilities, and support.

3. iOS Ecosystem

One of the most appealing aspects of the iOS ecosystem is its simplicity. The list of devices capable of running iOS is surprisingly short compared to Android or Windows Phone. This means that testing iOS applications is much less cumbersome compared to other platforms.

As I mentioned earlier, Android has surpassed iOS in terms of market share, but this is only part of the story. The iOS platform accounts for more than a third of web usage on mobile devices. What does this tell us about the mobile space? It tells us that iOS remains a dominant player in the mobile space, at least online, and this despite Android's much larger market share.

Devices

There are essentially two device families within the iOS ecosystem:

  • the iPad device family
  • the iPhone device family, which also includes the iPod Touch

For a complete overview, I recommend taking a look at this list. The primary differences within the iPhone device family are hardware capabilities and screen size. For iPhone and iPod Touch, there are four possible screen sizes:

  • 3.5"
  • 4.0"
  • 4.7"
  • 5.5"

For the iPad device family, there are three possible screen sizes:

  • 7.9"
  • 9.7"
  • 12.9"

The difference in screen size does impact development, but it doesn't add much overhead for most applications. I will talk more about this in the course of the series.

In 2012, Apple introduced the iPad Mini and in 2015 the iPad family was expanded with the iPad Pro. Even though the introductions of the iPad Mini and the iPad Pro caused a ripple in the technology industry, it has had little impact for iOS developers.

The screen of the iPad Mini, for example, is significantly smaller than that of the 9.7" iPad Air, but the resolution is identical to the resolution of the 9.7" iPad devices. Due to the iPad Mini's smaller screen, the average size of the touch targets is smaller and this might pose a problem for some applications.

iOS

Apple traditionally releases a new version of its mobile operating system every year. To date, Apple has released nine major versions of its mobile operating system with the most recent release being iOS 9.

Device support is an aspect of iOS that people often overlook. Take the iPhone 4S, for example. The iPhone 4S was released in 2011 and is still capable of running iOS 9. There is no mobile platform that comes even close to this in terms of device support.

App Store

One of the key reasons to develop for the iOS platform is the incredible success of the App Store. Selling software has never been easier thanks to Apple's App Store on iOS and OS X. With more than one million applications it is getting a bit crowded in the App Store for iOS, but keep in mind that the number of iOS devices also continues to grow exponentially.

The mobile space is in its infancy and there is still so much potential that is waiting to be uncovered. As with the web in the late nineties, the mobile space will continue to grow at a fast pace and the amount of money that can be made increases with every new smartphone, smartwatch, and tablet sold.

4. watchOS and tvOS

In 2015, Apple announced two new operating systems, watchOS for Apple Watch and tvOS for Apple TV. Apple has opened up both platforms for third party developers, bringing third party applications to your wrist and living room.

The tools for watchOS and tvOS development are identical to those for iOS development. This is yet another reason for choosing for the iOS ecosystem. Apple's operating systems, OS X, iOS, watchOS, and tvOS, are tightly integrated and the possibilities are virtually endless.

Conclusion

You now have a clear picture of the iOS ecosystem and I hope that I was able to convince you to get started with iOS development. In the next post, I will show you how to get started with the native SDK by setting up the development environment. You're going to be surprised by how easy this is.

If you have any questions or comments, you can leave them in the comments below or reach out to me on Twitter.

2015-12-01T17:45:12.000Z2015-12-01T17:45:12.000ZBart Jacobs

Setting Up the Development Environment

$
0
0

Before we can start creating iOS applications, we need to set up the development environment. In this tutorial, I show you how to register as an Apple developer and install the development tools you need to get started.

1. Requirements & Prerequisites

The primary focus of this tutorial is getting started with Xcode. Xcode is an outstanding Integrated Development Environment (IDE) developed by Apple. The vast majority of OS X, iOS, watchOS, and tvOS developers rely on Xcode for building applications.

Xcode is only compatible with Apple's OS X operating system and I am therefore assuming that you have a Mac capable of running Xcode. I will be using Xcode 7.1 throughout this series.

This particular version of Xcode requires OS X 10.10.5 or higher. Even though it is possible to create iOS applications with an older version of Xcode, I recommend that you also use Xcode 7.1 to make sure that you don't run into unexpected issues along the way.

2. Join the Apple Developer Program

Apple recently changed its Apple Developer Program. Members of the Apple Developer Program can now create and publish applications for OS X, iOS, watchOS, and tvOS. The Apple Developer Program is still paid, though.

If you're just testing the waters and don't want to enroll just yet, then you can still follow along as long as you have an Apple ID. As of 2015, it is possible to develop applications for Apple's platforms with nothing more than an Apple ID. As long as you're thirteen years or older, anyone can create an Apple ID and get started with Xcode.

If you plan to submit your applications to the App Store, then you're required to enroll for the paid Apple Developer Program. The paid Apple Developer Program has three enrollment types, individual, organization, and enterprise. Apple also has an iOS Developer University Program for educational institutions.

At the time of writing, the individual and organization enrollment types cost $99 per year. The enterprise program is more expensive at $299 per year. The enterprise program is aimed at companies and organizations that intend to deploy in-house applications, applications that are not distributed through Apple's App Store.

Step 1: Create an Apple ID

Before you can start developing iOS applications, you need an Apple ID. You also need one to enroll in the Apple Developer Program. Chances are that you already have an Apple ID. You can create one for free on Apple's website. It only takes a few minutes to create one.

Step 2: Enroll in Apple's Developer Program

You can complete this series without enrolling in the Apple Developer Program, but keep in mind that you won't be able to submit applications to the App Store. If you enroll in the Apple Developer Program, you can develop for OS X, iOS, watchOS, and tvOS. Visit Apple's developer website for more information about the Apple Developer Program.

If you decided to enroll in Apple's Developer Program, then head over to the Apple Developer Program website and click Enroll in the top right. Sign in with your Apple ID and follow the steps. The process can take a few days to complete since Apple manually approves each application. For more information, visit Apple's developer support center.

Enrolling in the Apple Developer Program

3. Install Xcode

The name Xcode can be somewhat confusing at first. The name is often used to refer to the entire toolset for OS X, iOS, watchOS, and tvOS development, and that toolset includes the Xcode IDE, the simulator for running applications, and the actual OS X, iOS, watchOS, and tvOS SDKs (Software Development Kit). However, it's important to understand that the Xcode application itself is just an IDE and when I use the name Xcode I'm typically referring to just that.

You can download Xcode in one of two ways, through Apple's developer website or through the App Store on OS X. The advantage of the App Store on OS X is that updating Xcode is easier and faster.

Download Xcode Through the App Store

The advantage of downloading Xcode through Apple's developer website is that you can download developer previews. If you like living on the edge, then you'll like working with the developer previews. Since you are new to iOS development, I suggest you download and install Xcode through the App Store so you can work with the most recent stable release.

Open the App Store, search for Xcode, and start the installation process. Xcode is several gigabytes in size so you may want to grab a cup of coffee or, even better, go for a walk.

4. Create Your First Application

You've barely touched your computer and we are already set up and ready to create iOS applications. If you're familiar with the process of setting up the Android SDK, then I'm sure you can appreciate this simplicity.

With Xcode installed, it is time to launch it for the first time. If all went well, you should see the Welcome to Xcode window, which contains a few useful links and helps you create a new application. To create your first iOS application, select Create a new Xcode project from the list of options.

Welcome to Xcode

What is an Xcode project? An Xcode project is a folder or package that contains all the necessary files and components to manage and build your application. You'll become more familiar with Xcode projects during this series.

Xcode makes it easy to create a new Xcode project by offering a handful of useful project templates. The Single View Application template is a good choice for your first application. Select it from the list of iOS > Application templates and click Next.

Choosing the Single View Application Template

The next window lets you configure your Xcode project. Fill in the fields as shown in the screenshot below and click Next. In an upcoming article in this series, I will explain each of the configuration options in more detail. The focus of this article is getting your first application up and running in the simulator.

Configuring the Project

In the final step, Xcode asks you to specify a location for storing your new Xcode project. It doesn't really matter where you save the project as long as you can find it later. You'll also notice that Xcode offers the option to create a local Git repository for your project. I highly recommend that you use source control for any type of development. Git is an excellent choice and it is the most popular SCM (Source Control Management) system in the OS X and iOS community.

Choosing a Location to Store the Xcode Project

It's important to get familiar with source control management if this is new to you. Source control is indispensable in software development for various reasons. To begin using Git, you can visit Git's website or read its Wikipedia entry. There's also an excellent book by Scott Chacon that discusses Git in more detail.

Envato Tuts+ has two excellent courses on Git. In the first course, Git Essentials, Andrew Burgess covers the basics of Git. In the second course, Introduction to Git and GitHub, Dan Wellman goes into detail about Git and GitHub.

In the rest of this series on iOS development, I won't bother you with source control. Even though source control is important, I don't want to overcomplicate this series by adding an extra layer of complexity.

5. Build & Run

You have successfully set up your first Xcode project. Believe it or not, running your application in the simulator is only one click away. There's a large play button on the far left of the Xcode toolbar.

Ready to Build Run

Before you run your application, make sure that the active scheme is set to iPhone 6 or one of the other iOS Simulators. We will cover schemes in more detail later on in the series. Take a look at the next screenshot to make sure you're on the same page.

Choosing the Scheme Simulator

Are you ready to build and run your very first iOS application? Click the play button in the top right to build your project and run your application in the simulator. Alternatively, you can press Command + R or select Run from Xcode's Product menu. If all went well, you should see the simulator running your application. Of course, your application doesn't do anything useful yet. We'll fix that later in this series.

6. Simulator

The simulator is a valuable tool in your arsenal. Building and running an iOS application in the simulator is faster than deploying an application to a physical device. There is one caveat, however. For various reasons, the simulator doesn't perfectly mimic an iOS device.

For example, the simulator doesn't have a camera or an accelerometer, its GPS capabilities are limited to a list of predefined locations and routes, and user interaction is limited to gestures that require one or two fingers. Also, keep in mind that the simulator draws power and resources from the machine it runs on. This means that the simulator isn't suitable for testing application performance.

The point is that you should always test an application on a physical device before submitting it to the App Store or distributing it to testers. Even if you only have one device to test with, it is critical to test your applications on a physical device instead of relying solely on the simulator.

In spite of its shortcomings, the simulator is a very capable tool. Select the simulator and take a look at its menu and the various options it provides. The simulator is perfectly suited for testing user interfaces on different form factors, mimicking simple gestures, simulating memory warnings, or taking screenshots for the App Store. You'll find it a very useful tool for iOS development.

7. Physical Devices

As of 2015, running an application on a physical device is possible for every Apple developer, even if you don't enroll in the paid Apple Developer Program. That said, running an application on a physical device involves a few extra steps. These steps include configuring your project and setting up the device you plan to test with. Because this is a fairly complex topic, especially if you are new to iOS development, I will thoroughly explain how to do this in a separate article in this series.

8. Third Party Development Tools

I would like to end this article by listing a handful of third party tools that make iOS development easier and more enjoyable. Note that these applications are by no means required for iOS development, but knowing that they exist may save you a lot of frustration in the future.

  • Dash: Dash is a superb documentation browser and code snippet manager that I use constantly during development. Dash is a great alternative for Xcode's built-in documentation browser. It supports dozens of languages and frameworks, which means that you can use it for almost any type of development.
  • Tower: Tower is one of the best OS X applications for working with Git. Git is a command line tool, but some people prefer to use a graphical user interface instead. If you are not a command line superhero, then you'll definitely appreciate what Tower has to offer. Another great alternative is SourceTree, developed by Atlassian.
  • TextExpander: TextExpander is a popular utility for managing text snippets linked to custom keyboard shortcuts. Many developers use it for development, but you can use it wherever you like. It also supports placeholders for even more customizability.
  • Fabric: Fabric, owned by Twitter, is a suite of tools for mobile development. It allows developers to distribute test builds, collect crash reports, and integrate analytics. There are a number of alternatives that you may want to look into, such as HockeyApp and Apple's own TestFlight platform.

Conclusion

I hope you agree that setting up the development environment for iOS development is easy. With Xcode installed, we can start exploring the iOS SDK. That will be the focus of the rest of this series.

If you have any questions or comments, you can leave them in the comments below or reach out to me on Twitter.

2015-12-02T17:45:41.000Z2015-12-02T17:45:41.000ZBart Jacobs

iOS From Scratch With Swift: Understanding the iOS Ecosystem

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

Before you begin building iOS applications, it is crucial that you first understand the ecosystem. This article examines the fundamentals of Apple's operating systems, the various devices available, and Apple's App Store.

1. Why iOS?

Before the arrival of Android and Windows Phone, Apple was the dominant player in the mobile space, rivaled only by Nokia and BlackBerry. With the emergence of new mobile platforms, it has become more and more important to ask yourself which platform is best suited for you.

In spite of Apple's head start in 2007, Android has surpassed iOS in market share. What does that mean for iOS? Is it still a platform worth developing for? It sure is. There are many great reasons to get started with iOS development today.

  • Strong Financial Incentives: People spend more money on Apple's App Store than on any other mobile platform. Despite the fact that Android has become the dominant player in the mobile space, the iOS platform remains more lucrative for developers.
  • Walled Garden: Over the years Apple's App Store has received a lot of criticism from developers and customers, Apple's review process in particular. It is clear, however, that Apple's policy has led to an App Store in which the quality of its applications is higher than in any other mobile store. Customers also tend to feel much safer when purchasing applications from the App Store than they do on other—more open—platforms, such as Google Play.
  • Community and Support: The iOS developer community is a great community to be part of. There is an almost unlimited supply of articles, tutorials, and documentation to help you out when you find yourself stuck with a problem. Also, Apple's documentation of the iOS SDK is superb, not to mention the hundreds of WWDC (World Wide Developer Conference) videos available on Apple's developer website.

People often forget, or don't know, that Android and iOS are very different platforms. Even though both platforms were designed for the mobile space, the iOS ecosystem differs in many respects from the Android ecosystem.

From a development perspective, most people seem to find it easier to develop for iOS than for Android. Don't misunderstand me, I am not referring to the technology stack that each platform uses nor am I referring to the available tools for each platform. Two reasons are at the foundation of the chasm between iOS and Android, fragmentation and adoption rate.

Fragmentation

One of Android's core strengths is at the same time one of its principal weaknesses. As most of you know, the Android operating system is released as an open source project and can therefore be used and be modified by anyone. Numerous hardware manufacturers have seen the potential of Android, especially since it is backed by Google.

As a result, Android quickly gained in popularity. The problem is that each hardware manufacturer modifies Android to fit their needs and a wide variety of form factors have emerged since the introduction of Android.

Even though Android's market share may seem like a big pot of honey, it's a pain to create software that runs on each Android version currently available. Due to the thousands of different devices that run Android, testing software on hardware is no trivial task. As you can imagine, support and compatibility become a real challenge.

Adoption Rate

Traditionally, in many countries, the wireless market is under tight control by cellular carriers. From the very beginning, Apple knew it needed to be in control of its mobile devices to provide the best user experience possible. The result is that customers can upgrade their iOS devices to the latest version of iOS the same day it is released to the public. This is a major advantage of the iOS platform and the result is substantial. Less than a week after the release of iOS 9, over 50% of iOS devices had been upgraded to iOS 9.

Let's compare this with Android. In September 2015, only 20% of Android users had upgraded their devices to Lollipop (released in 2014) and less than 40% had upgraded to KitKat (released in October 2013).

The reason for bringing up these numbers is not to downplay the Android platform or any other mobile platform. What I want to emphasize is the impact the adoption rate has on the application ecosystem of these platforms.

The slower users adopt a new release of an operating system, the longer developers are forced to support older versions of the operating system. It also becomes less appealing to adopt new technologies, which can only be used on a fraction of Android devices.

2. Why Native?

If you are a frequent reader of Envato Tuts+, then you may have heard of cross-platform frameworks like Xamarin, React NativePhoneGap, Apache Cordova, and Titanium Mobile. You might be wondering why you should go through the trouble of learning Swift or Objective-C when you can create iOS applications using C# or JavaScript. Let me give you a brief rundown of your options if you decide to develop applications for iOS.

Web Applications

A web application is your first option and this was, in fact, the only option prior to the introduction of the native iOS SDK in 2008. The upside of web applications is that they don't have to deal with the App Store or Apple's review process. Why is that? A web application is a fancy name for a website that acts and behaves like an application. All you need is a browser, such as Mobile Safari or Google Chrome.

Web applications have clear advantages. They are cross-platform by default since the applications run in a browser. Another advantage is the learning curve to create web applications. If you are familiar with web development, then you'll be up and running in no time.

Of course, the downsides of web applications shouldn't be ignored either. A web application has limited access to the capabilities of the devices they run on. Mobile web applications are quite powerful thanks to HTML5 and JavaScript. However, there are distinct limitations in terms of what they can do. You won't be able to use the cool features of the iPad and iPhone. Also, web applications typically require a network connection to work, although there are exceptions to this rule.

Perhaps the biggest downside to building web applications is that, in general, they feel significantly slower than native applications. The responsiveness of web applications is improving every year, but the inherited delay added by the browser should not be overlooked or ignored. The experience is different. There's no doubt about that.

Mobile Cross-Platform Frameworks

The promise of a cross-platform framework is that developers can write an application that can be deployed to multiple mobile devices from a single code base. This is accomplished through a number of approaches.

Some frameworks, like PhoneGap and Apache Cordova, use the native SDK of the platform to create a web view in which the application is embedded. As with web applications, this imposes limitations in terms of functionality. The main advantage is that the application feels like a native application in terms of user experience and that it can be distributed through the platform's store.

Even though mobile development frameworks might seem like the holy grail for mobile development, there are a number of downsides that need to be considered. The most important downside is that your application depends on a third party framework. In other words, your project's code base depends on the company that provides the cross-platform solution. If that company goes out of business or is slow to implement changes made to the native SDK, you could be forced to start over from scratch. That's a risk that you need to consider.

iOS SDK

Choosing to develop with the native SDK is the best choice if you want to create applications that stand out and take advantage of the device's capabilities. Opting for a native application also means that you will work in a robust development environment and that you can rely on Apple's development tools, utilities, and support.

3. iOS Ecosystem

One of the most appealing aspects of the iOS ecosystem is its simplicity. The list of devices capable of running iOS is surprisingly short compared to Android or Windows Phone. This means that testing iOS applications is much less cumbersome compared to other platforms.

As I mentioned earlier, Android has surpassed iOS in terms of market share, but this is only part of the story. The iOS platform accounts for more than a third of web usage on mobile devices. What does this tell us about the mobile space? It tells us that iOS remains a dominant player in the mobile space, at least online, and this despite Android's much larger market share.

Devices

There are essentially two device families within the iOS ecosystem:

  • the iPad device family
  • the iPhone device family, which also includes the iPod Touch

For a complete overview, I recommend taking a look at this list. The primary differences within the iPhone device family are hardware capabilities and screen size. For iPhone and iPod Touch, there are four possible screen sizes:

  • 3.5"
  • 4.0"
  • 4.7"
  • 5.5"

For the iPad device family, there are three possible screen sizes:

  • 7.9"
  • 9.7"
  • 12.9"

The difference in screen size does impact development, but it doesn't add much overhead for most applications. I will talk more about this in the course of the series.

In 2012, Apple introduced the iPad Mini and in 2015 the iPad family was expanded with the iPad Pro. Even though the introductions of the iPad Mini and the iPad Pro caused a ripple in the technology industry, it has had little impact for iOS developers.

The screen of the iPad Mini, for example, is significantly smaller than that of the 9.7" iPad Air, but the resolution is identical to the resolution of the 9.7" iPad devices. Due to the iPad Mini's smaller screen, the average size of the touch targets is smaller and this might pose a problem for some applications.

iOS

Apple traditionally releases a new version of its mobile operating system every year. To date, Apple has released nine major versions of its mobile operating system with the most recent release being iOS 9.

Device support is an aspect of iOS that people often overlook. Take the iPhone 4S, for example. The iPhone 4S was released in 2011 and is still capable of running iOS 9. There is no mobile platform that comes even close to this in terms of device support.

App Store

One of the key reasons to develop for the iOS platform is the incredible success of the App Store. Selling software has never been easier thanks to Apple's App Store on iOS and OS X. With more than one million applications it is getting a bit crowded in the App Store for iOS, but keep in mind that the number of iOS devices also continues to grow exponentially.

The mobile space is in its infancy and there is still so much potential that is waiting to be uncovered. As with the web in the late nineties, the mobile space will continue to grow at a fast pace and the amount of money that can be made increases with every new smartphone, smartwatch, and tablet sold.

4. watchOS and tvOS

In 2015, Apple announced two new operating systems, watchOS for Apple Watch and tvOS for Apple TV. Apple has opened up both platforms for third party developers, bringing third party applications to your wrist and living room.

The tools for watchOS and tvOS development are identical to those for iOS development. This is yet another reason for choosing for the iOS ecosystem. Apple's operating systems, OS X, iOS, watchOS, and tvOS, are tightly integrated and the possibilities are virtually endless.

Conclusion

You now have a clear picture of the iOS ecosystem and I hope that I was able to convince you to get started with iOS development. In the next post, I will show you how to get started with the native SDK by setting up the development environment. You're going to be surprised by how easy this is.

If you have any questions or comments, you can leave them in the comments below or reach out to me on Twitter.

2015-12-01T17:45:12.000Z2015-12-01T17:45:12.000ZBart Jacobs
Viewing all 1836 articles
Browse latest View live