O'Reilly logo

iOS 8 Swift Programming Cookbook by Vandad Nahavandipoor

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Chapter 1. The Basics

1.0. Introduction

In order to write apps for iOS, you need to know some of the basics of the Swift programming language that we will use throughout this book. Swift is Apple’s new programming language introduced in Xcode 6 and iOS 8 SDK. Objects and classes are fundamental in object-oriented programming (OOP) languages such as Swift, Objective-C, Java, C++, and many others.

All iOS applications essentially use the model-view-controller (MVC) architecture. Model, view, and controller are the three main components of an iOS application from an architectural perspective.

The model is the brain of the application. It does the calculations and creates a virtual world for itself that can live without the views and controllers. In other words, think of a model as a virtual copy of your application, without a face!

A view is the window through which your users interact with your application. It displays what’s inside the model most of the time, but in addition to that, it accepts users’ interactions. Any interaction between the user and your application is sent to a view, which then can be captured by a view controller and sent to the model.

The controller in iOS programming usually refers to the view controllers I just mentioned. Think of a view controller as a bridge between the model and your views. This controller interprets what is happening on one side and uses that information to alter the other side as needed. For instance, if the user changes a field in a view, the controller makes sure the model changes in response. And if the model gets new data, the controller tells the view to reflect it.

In this chapter, you will learn how to create the structure of an iOS application and how to use views and view controllers to create intuitive applications.

I also want to teach you a few basics of the Swift programming language—but before we begin, I want to make it absolutely obvious that the goal of this book is not to teach you how to program in Swift. Apple has already released a full book more than 500 pages long that teaches you how to use Swift. But in case you’re using this book in parallel with some other resource to learn Swift, I will go over a few basics.

Defining Constants and Variables in Swift

We define constants with the let keyword like so:

let integerValue = 10
let stringValue = "Swift"
let doubleValue = 10.0

The value that we assign to a constant (or later to a variable) defines its type. In the examples I gave, we did not have to define the data type of the constants at all because the Swift compiler can figure out the proper type from the values we assigned. However, if you want to define the data type manually, you can do so using the following syntax:

let integerFromDouble = 10.7 as Int
/* The value of this variable is 10 
because the compiler truncated the value to an integer*/

When a constant is defined and a value is assigned to it, it cannot be changed later. If you need to change a value, use a variable instead, with the var keyword:

var myString = "Swi"
myString += "ft"
/* myString is now "Swift" */

Variables can be mutable or immutable. An immutable variable cannot be changed or appended to. Mutable variables can be changed.

Creating and Using Arrays in Swift

The [DataType] syntax can create an array. This is an example of creating an immutable array:

let allStrings = ["Swift", "Objective-C"]

If you want to create a mutable array, initialize an empty mutable array and then append values to it like so. Use var so your allStrings array is a variable, not a constant:

var allStrings = [String]()
allStrings.append("Swift")
allStrings.append("Objective-C")
/* Our array is now ["Swift", "Objective-C" */

If you want to access values inside an array, use subscripting with the [] syntax:

var allStrings = [String]()
allStrings.append("Swift")
allStrings.append("Objective-C")

println(allStrings[0]) /* Prints out "Swift" */

allStrings.insert("C++", atIndex: 0)

println(allStrings[0]) /* Prints out "C++" */

Defining and Accessing Dictionaries in Swift

A dictionary is a hash table. Each entry in a dictionary specifies one object as a key and another object as its value. Dictionaries in Swift are dynamically typed, based on what we feed them, and are created with the [key: value] syntax, as shown here:

let allFullNames = [
  "Vandad"  : "Nahavandipoor",
  "Andy"    : "Oram",
  "Molly"   : "Lindstedt"
]

To access the value of a key, use subscripting like so:

println(allFullNames["Vandad"]) /* Prints out "Nahavandipoor" */

The dictionary that we created was immutable because of the let keyword. To create a mutable version of the same dictionary, use the var keyword like so:

var allFullNames = [
  "Vandad"  : "Nahavandipoor",
  "Andy"    : "Oram",
  "Molly"   : "Lindstedt"
]

allFullNames["Rachel"] = "Roumeliotis"

This dictionary is of type [String: String] because of the values that we provided to it. You can add any type of value or key to the dictionary to see how the data type changes:

let personInformation = [
  "numberOfChildren"  : 2,
  "age"               : 32,
  "name"              : "Random person",
  "job"               : "Something cool",
] as [String : AnyObject]

The AnyObject type, as its name implies, represents an instance of any class type. In this case, we are saying that the keys to our dictionary are strings but the values are a mix of various class types. Dictionaries and arrays in Swift can be freely bridged to their Cocoa Touch counterparts of NSDictionary and NSArray.

Grouping Functionality with Classes and Structures in Swift

Structures are value types. That means that when they are passed around from one function to another, for instance, a new instance of them is created and then passed to the function. Classes are reference types, so that they can be passed around without having to be copied.

Imagine having the following structure:

struct Person{
  var firstName, lastName: String

  mutating func setFirstNameTo(firstName: String){
    self.firstName = firstName
  }

}

This structure has a method that can cause the structure to mutate, so it is prefixed with the keyword mutating. Now we can create a function that can change the value of any Person instance to any given string:

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

  var window: UIWindow?

  func changeFirstNameOf(var person: Person, to: String){
    person.setFirstNameTo(to)
    /* person.firstName is VANDAD now and only in this function */
  }

  func application(application: UIApplication,
    didFinishLaunchingWithOptions 
    launchOptions: [NSObject : AnyObject]?) -> Bool {

      var vandad = Person(firstName: "Vandad", lastName: "Nahavandipoor")
      changeFirstNameOf(vandad, to: "VANDAD")
      /* vandad.firstName is still Vandad */

    return true
  }

}

Note that the value of the firstName property of the person instance is changed only in the context of the function, not outside it. That means when the instance of the Person structure was passed to the function to change the first name to a given string, the structure as a whole was copied into the stack and passed to the function. Therefore, even though we called the mutating function on it, the first name of the vandad variable did not change.

Now off to classes. Classes are reference types and when passed to functions, are passed just as references to a single copy held in memory. Have a look at the following example:

class Person{
  var (firstName, lastName) = ("", "")
  init (firstName: String, lastName: String){
    self.firstName = firstName
    self.lastName = lastName
  }
}

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

  var window: UIWindow?

  func changeFirstNameOf(person: Person, to: String){
    person.firstName = to
  }

  func application(application: UIApplication,
    didFinishLaunchingWithOptions 
    launchOptions: [NSObject : AnyObject]?) -> Bool {

      var vandad = Person(firstName: "Vandad", lastName: "Nahavandipoor")
      changeFirstNameOf(vandad, to: "VANDAD")
      /* vandad.firstName is now VANDAD */

      return true
  }

}

You can see that the first name of the vandad variable is indeed changed in its original context after it was passed to a function that changed the first name. Classes can also have inheritance, but structures cannot have inheritance.

Diving into Operators in Swift

There are many valid operators in Swift. Here are a few examples:

typealias byte = UInt8

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

  var window: UIWindow?

  func application(application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool {

      /* Bitwise OR operator */
      let byte3 = 0b01010101 | 0b10101010 /* = 0b11111111 */

      /* plus operator */
      let plus = 10 + 20 /* = 30 */

      /* minus operator */
      let minus = 20 - 10 /* = 10 */

      /* multiplication operator */
      let multiplied = 10 * 20 /* = 200 */

      /* division operator */
      let division = 10.0 / 3.0 /* = 3.33333333333333 */

      return true
  }

}

You can also override operators. As we saw before, we had a class called Person. The two-character == operator checks whether two things are equal in the sense of having the same value, whereas the three-character === operator checks for instance equality. That means the first operator checks whether the two instances are equal (in whatever way that makes sense in the context of your app). The === operator is very strict: it makes sure that the two things you pass are occupying the same position in memory.

Let’s explore the first type of equality. With our Person class, it makes sense to declare two instances of this class equal if they have the same first and last name. Therefore, using the operator overloader for the == operator, we can define this functionality:

func == (left: Person, right: Person) -> Bool{
  if left.firstName == right.firstName &&
    left.lastName == right.lastName{
      return true
  }
  return false
}

And now, if we define two people with the same first name and last name and check whether they are the same, even though the instances are different, they will come out the same:

let andy = Person(firstName: "Andy", lastName: "Oram")
let someoneElse = Person(firstName: "Andy", lastName: "Oram")

if andy == someoneElse{
  /* This will be printed */
  println("They are the same")
} else {
  /* We won't get here in this case */
  println("They are not the same")
}

The three-character === operator would say they’re different, because they are separate variables and you can change one without changing the other.

Now let’s say that we want to add a postfix ++ operator to our Person class. To create some numerical data it can operate on, we’ll add a age property of type Int to the class:

class Person{
  var age: Int
  var fullName: String
  init(fullName: String, age: Int){
    self.fullName = fullName
    self.age = age
  }
}

Our goal is to allow the programmer to perform the prefix and the postfix operators of ++ on our person instances just like we would perform the prefix and postfix operator of ++ on integer values in C:

postfix func ++ (inout person: Person) -> Person{
  let newPerson = Person(fullName: person.fullName, age: person.age)
  person.age++
  return newPerson
}

prefix func ++ (inout person: Person) -> Person{
  person.age++
  let newPerson = Person(fullName: person.fullName, age: person.age)
  return newPerson
}

And now we can use them like so:

var vandad = Person(fullName: "Vandad Nahavandipoor", age: 29)
var sameAgeVandad = vandad++
/*
  vandad.age = 30
  sameAgeVandad.age = 29
*/

let olderVandad = ++sameAgeVandad

/*
  vandad.age = 30
  sameAgeVandad.age = 30
  olderVandad.age = 30
*/

In the same way, you can define prefix and postfix operators for any class or structure you like. Just ensure that your operator overloaders are public functions and not defined inside any specific class or structure.

Declaring and Using Enumerations in Swift

Enumerations are very sophisticated in Swift indeed. They can be of any given type. For instance, they can be strings:

enum CarClassification: String{
  case Estate = "Estate"
  case Hatchback = "Hatchback"
  case Saloon = "Saloon"
}

struct Car{
  let classification: CarClassification
}

And then you can use them without having to point to the enumeration type. Just use the values:

let volvoV50 = Car(classification: .Estate)

You can then use the switch statement to find each case of an enumeration:

let volvoV50 = Car(classification: .Estate)

switch volvoV50.classification{
case .Estate:
  println("This is a good family car")
case .Hatchback:
  println("Nice car, but not big enough for a family")
default:
  println("I don't understand this classification")
}

You can also get the raw value of an enumeration item using the rawValue property:

let volvoV50 = Car(classification: .Estate)
println(volvoV50.classification.rawValue) /* Prints out "Estate" */

Alternatively, you can construct a value of type of a specific structure using the initializer:

if let classification = CarClassification(rawValue: "Estate"){
  let volvoV50 = Car(classification: classification)
}

You can use the where clause inside a switch statement to add logic to case statements. For instance, if we have our Car type defined like so:

enum CarClassification: String{
  case Estate = "Estate"
  case Hatchback = "Hatchback"
  case Saloon = "Saloon"
}

struct Car{
  let classification: CarClassification
  let year: Int
}

We can have a function that classifies our cars and, for each classification, decides how old the car should be and still be considered in good condition:

func classifyCar(car: Car){
  switch car.classification{
  case .Estate where car.year >= 2013:
    println("This is a good and usable estate car")
  case .Hatchback where car.year >= 2010:
    println("This is an okay hatchback car")
  default:
    println("Unhandled case")
  }
}

And we can use the function like so:

let oldEstate = Car(classification: .Estate, year: 1980)
let estate = Car(classification: .Estate, year: 2010)
let newEstate = Car(classification: .Estate, year: 2015)
let hatchback = Car(classification: .Hatchback, year: 2013)
let newSaloon = Car(classification: .Saloon, year: 2015)

classifyCar(oldEstate)  /* Will go to the default case */
classifyCar(estate)     /* Will go to the default case */
classifyCar(newEstate)  /* Will be picked up in the function */
classifyCar(hatchback)  /* Will be picked up in the function */
classifyCar(newSaloon)  /* Will go to the default case */

1.1. Adding Blur Effects to Your Views

Problem

You want to add blur effects to various UI components on your application.

Solution

Use the following two classes:

UIBlurEffect

This is a class that represents a blur effect. You can initialize an instance of this class with its designated constructor and pass a value of type UIBlurEffectStyle to it. This value will then decide what type of blur effect you want to create.

UIVisualEffectView

This is a simple UIView subclass that can accept and apply a visual effect of type UIVisualEffect. Because the UIBlurEffect class is a subclass of the UIVisualEffect, you can simply create a blur effect and pass it to your visual effect view. Once you have the visual effect view, you can add it to any other existing view that you have on or off screen.

Figure 1-1 shows Safari’s icon rendered with a visual effect view that includes a blur effect, blurring the center of that image.

Applying a blur effect on a view
Figure 1-1. Applying a blur effect on a view

Discussion

For the purpose of this discussion, I have already added an image view on my view controller. The image is Safari.app’s icon. I have explained the process of extracting this icon in Recipe 19.2, so if you are curious and don’t have any other icon to use on your view controller, you can have a look at the aforementioned section of the book to learn how to extract Safari’s icon (or any other app’s icon for that matter). My view controller looks like Figure 1-2 at the moment.

View controller with Safari’s icon on it
Figure 1-2. View controller with Safari’s icon on it

What I want to do now is add a blurred view on top of this image view. As we learned in the Solution section of this recipe, we are going to create our blur effect and then create a visual effect view on top of our current view, like so:

import UIKit

class ViewController: UIViewController {

  override func viewDidLoad() {
    super.viewDidLoad()

    let blurEffect = UIBlurEffect(style: .Light)
    let blurView = UIVisualEffectView(effect: blurEffect)
    blurView.frame.size = CGSize(width: 200, height: 200)
    blurView.center = view.center

    view.addSubview(blurView)

  }

}

The UIBlurEffect class can be initialized with any of the blur styles that are specified in the UIBlurEffectStyle enumeration like so:

enum UIBlurEffectStyle : Int {
    case ExtraLight
    case Light
    case Dark
}

In our example code, we used a light blur effect, but you can use any of the ones just listed. Once you have your blur effect, you can add it to the UIVisualEffectView class. This class itself can accept any visual effect of type UIVisualEffect. Another class of the aforementioned type is the UIVibrancyEffect. This class is very similar to the UIBlurEffect class, and in fact under the hood uses a blur effect as well. UIVibrancyEffect brings out the colors on the layers that are behind it. For instance, if you have a popup window that is about to appear on top of another view that contains many colorful photos on it, it is best to add a UIVibrancyEffect to a visual effect view and construct your popup using this visual effect view. That way, the colors underneath the popup (colors that come from the photos) will be more appealing to the user and the user will be able to get a better understanding of the content under your popup.

1.2. Presenting Temporary Information on the Screen with Popovers

Problem

You want to display a temporary view to the user on the screen and allow them to interact with it. When they are done, this view will need to get dismissed. On an iPad, you would like this information to take up only a bit of the screen real estate, not the whole.

Solution

Use a popup controller of type UIPopoverController and display it on your view controllers using the presentPopoverFromBarButtonItem:permittedArrowDirections:animated: method of the popup controller. A popup controller has to originate from a specific rectangular space on the screen. This is usually a button or a control on the screen where the user taps and expects to see the popover. This item could be of type UIBarButtonItem, in which case you can display the popover using its presentPopoverFromBarButtonItem:permittedArrowDirections:animated: method. Otherwise, you can display and originate a popover from any rectangular spot on the screen using the presentPopoverFromRect:permittedArrowDirections:animated: method.

Discussion

Popovers are used to display temporary information on the screen. They can be used both on regular and on compact size devices such as iPads and iPhones. In this recipe, we want to build an application with a main view controller embedded inside a navigation bar. On the navigation bar we show a plus (+) button which, upon pressing, will display a table view that is populated with 100 items. This table view will be embedded inside its own navigation bar with a Cancel button on it. When the user selects an item in the table view, the popover will be dismissed and the selected item will be passed to the root view controller for processing (see Figure 1-3).

Our popover is displayed on the iPad screen
Figure 1-3. Our popover is displayed on the iPad screen

The table view controller has its own class and works with a completion handler. When an item is selected, this controller takes the selected item and passes it to its completion handler. Therefore, processing is very decoupled and it is best to start our implementation of this controller first. Before we begin, we need to define a few handy extensions:

extension Array{
  subscript(path: NSIndexPath) -> T{
    return self[path.row]
  }
}

extension NSIndexPath{
  class func firstIndexPath() -> NSIndexPath{
    return NSIndexPath(forRow: 0, inSection: 0)
  }
}

The first extension retrieves an item from an array using an index path, which is really cool, and the other extension constructs an index path at the first row of the first section to relieve us from doing it manually every time. We will be using these quite soon, so don’t worry if you don’t fully understand their use yet.

Next we are going to define the most useful variables for our table view controller. The most useful one out of all these variables is the array of items that we are going to display to the user in the table view, so they can select one. This is an array of strings and we populate it lazily:

class PopoverTableViewController: UITableViewController {

  struct TableViewValues{
    static let identifier = "Cell"
  }

  /* This variable is defined as lazy so that its memory is allocated
  only when it is accessed for the first time. If we don't use this variable,
  no computation is done and no memory is allocated for this variable */
  lazy var items: [String] = {
    var returnValue = [String]()
    for counter in 1...100{
      returnValue.append("Item \(counter)")
    }
    return returnValue
  }()

  var cancelBarButtonItem: UIBarButtonItem!
  var selectionHandler: ((selectedItem: String) -> Void!)?

  <# rest of the code #>

}

When the table view is displayed to the user, we will also construct our bar button items and show them on the navigation bar without an animation:

required init(coder aDecoder: NSCoder) {
  super.init(coder: aDecoder)
}

override init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: NSBundle!) {
  super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
  tableView.registerClass(UITableViewCell.classForCoder(),
    forCellReuseIdentifier: TableViewValues.identifier)
}

override init(style: UITableViewStyle) {
  super.init(style: style)
}

override func viewDidLoad() {
  super.viewDidLoad()

  cancelBarButtonItem = UIBarButtonItem(title: "Cancel", style: .Plain,
    target: self, action: "performCancel")
  navigationItem.leftBarButtonItem = cancelBarButtonItem

}

When the Cancel button is pressed, we should simply dismiss our controller:

func performCancel(){
  dismissViewControllerAnimated(true, completion: nil)
}

And when an item is selected, we will pass the item to our selection handler, which is an optional closure:

override func tableView(tableView: UITableView,
  didSelectRowAtIndexPath indexPath: NSIndexPath) {
    let selectedItem = items[indexPath]
    selectionHandler?(selectedItem: selectedItem)
    dismissViewControllerAnimated(true, completion: nil)
}

This way the root view controller can become the selection handler and get notified whenever the user has selected an item. As soon as our table view appears on the screen, we will set the preferred size of the popover controller:

override func viewWillAppear(animated: Bool) {
  super.viewWillAppear(animated)
  preferredContentSize = CGSize(width: 300, height: 200)
}

Last but not least, we will display the items that we have prepared, inside the table view:

override func tableView(tableView: UITableView,
  numberOfRowsInSection section: Int) -> Int {
  return items.count
}

override func tableView(tableView: UITableView,
  cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

  let cell = tableView.dequeueReusableCellWithIdentifier(
    TableViewValues.identifier, forIndexPath: indexPath) as UITableViewCell

  cell.textLabel.text = items[indexPath]

  return cell

}

Now let’s go to our root view controller and construct an instance of our popover controller. We place it inside a navigation bar so that the popover controller has a place to put the bar button items:

import UIKit

class ViewController: UIViewController {

  var selectedItem: String?

  lazy var popoverContentController: UINavigationController = {
    let controller = PopoverTableViewController(style: .Plain)
    controller.selectionHandler = self.selectionHandler
    let navigationController = UINavigationController(
      rootViewController: controller)
    return navigationController
    }()

  lazy var popoverController: UIPopoverController = {
    return UIPopoverController(contentViewController:
      self.popoverContentController)
    }()

  <# rest of the code #>

}

As you saw, the selectionHandler closure of our root view controller has become the selection handler of the popover controller, so we can implement this closure like this:

func selectionHandler(selectedItem: String){
  self.selectedItem = selectedItem

  /* Do something with the selected item */

}

I’ve left the implementation quite open, as you may want to do something special with the value that the table view passed to you. For instance, you may want to display an alert view to the user using what you have learned in Recipe 1.6. The plus (+) button on the navigation bar of the root view controller is hooked to a method named displayPopover: that simply displays the popover:

@IBAction func displayPopover(sender: UIBarButtonItem){
  popoverController.presentPopoverFromBarButtonItem(sender,
    permittedArrowDirections: .Any,
    animated: true)
}

Please note the permittedArrowDirections parameter of the presentPopoverFromBarButtonItem:permittedArrowDirections:animated method of the popover controller. This parameter dictates the direction of the arrow that originates from the source of the popover. Have another look at Figure 1-3. Can you see the arrow that is originating from the plus (+) button? That is the source of the popover. In this case, the arrow is pointing upwards towards the button, but you can change this behavior by changing the value of the permittedArrowDirections parameter of the aforementioned method to any of the values inside the UIPopoverArrowDirection structure.

See Also

Recipe 1.6

1.3. Displaying Images with UIImageView

Problem

You would like to display images on your app’s UI.

Solution

Use the UIImageView class.

Discussion

The UIImageView is one of the least-complicated classes in the iOS SDK. As you know, an image view is responsible for displaying images. There are no tips or tricks involved. All you have to do is instantiate an object of type UIImageView and add it to your views. Now, I have a photo of Safari’s icon and I would like to display it in an image view. Let’s start with our view controller’s implementation file:

import UIKit

class ViewController: UIViewController {

  let image = UIImage(named: "Safari")
  var imageView: UIImageView

  required init(coder aDecoder: NSCoder){
    imageView = UIImageView(image: image)
    super.init(coder: aDecoder)
  }

}

Go ahead and add the image view to your view controller’s view:

override func viewDidLoad() {
  super.viewDidLoad()
  imageView.center = view.center
  view.addSubview(imageView)
}

Now if we run the app, we will see something similar to Figure 1-4.

An image view that is too big to fit on the screen
Figure 1-4. An image view that is too big to fit on the screen

I should mention that the Safari image that I’m loading into this image view is 512×512 pixels, and as you can see, it certainly doesn’t fit into the screen. So how do we solve this problem? First, we need to make sure that we are initializing our image view using the initWithFrame: method, instead of the initWithImage: method, as the latter will set the width and height of the image view to the exact width and height of the image. So let’s remedy that first:

import UIKit

class ViewController: UIViewController {

  let image = UIImage(named: "Safari")
  var imageView: UIImageView!

  override func viewDidLoad() {
    super.viewDidLoad()
    imageView = UIImageView(frame: view.bounds)
    imageView.image = image
    imageView.center = view.center
    view.addSubview(imageView)
  }

}

So how does the app look now? See Figure 1-5.

An image whose width is squished to fit the width of the screen
Figure 1-5. An image whose width is squished to fit the width of the screen

This isn’t really what we wanted to do, is it? Of course, we got the frame of the image view right, but the way the image is rendered in the image view isn’t quite right. So what can we do? We can rectify this by setting the contentMode property of the image view. This property is of type UIContentMode.

Here is an explanation of some of the most useful values in the UIViewContentMode enumeration:

UIViewContentModeScaleToFill

This will scale the image inside the image view to fill the entire boundaries of the image view.

UIViewContentModeScaleAspectFit

This will make sure the image inside the image view will have the right aspect ratio and fit inside the image view’s boundaries.

UIViewContentModeScaleAspectFill

This will make sure the image inside the image view will have the right aspect ratio and fill the entire boundaries of the image view. For this value to work properly, make sure that you have set the clipsToBounds property of the image view to true.

Note

The clipsToBounds property of UIView denotes whether the subviews of that view should be clipped if they go outside the boundaries of the view. You use this property if you want to be absolutely certain that the subviews of a specific view will not get rendered outside the boundaries of that view (or that they do get rendered outside the boundaries, depending on your requirements).

So to make sure the image fits into the image view’s boundaries and that the aspect ratio of the image is right, we need to use the UIViewContentModeScaleAspectFit content mode:

import UIKit

class ViewController: UIViewController {

  let image = UIImage(named: "Safari")
  var imageView: UIImageView!

  override func viewDidLoad() {
    super.viewDidLoad()
    imageView = UIImageView(frame: view.bounds)
    imageView.contentMode = .ScaleAspectFit
    imageView.image = image
    imageView.center = view.center
    view.addSubview(imageView)
  }

}

1.4. Displaying Static Text with UILabel

Problem

You want to display text to your users. You would also like to control the text’s font and color.

Note

Static text is text that is not directly changeable by the user at runtime.

Solution

Use the UILabel class.

Discussion

Labels are everywhere in iOS. You can see them in practically every application, except for games, where the content is usually rendered with OpenGL ES instead of the core drawing frameworks in iOS.

To create a label, instantiate an object of type UILabel. Setting or getting the text of a label can be done through its text property. So let’s first define a label in our view controller:

import UIKit

class ViewController: UIViewController {
  var label: UILabel!
}

Now in the viewDidLoad method, instantiate the label and tell the runtime where the label has to be positioned (through its frame property) on the view to which it will be added (in this case, our view controller’s view):

import UIKit

class ViewController: UIViewController {
  var label: UILabel!

  override func viewDidLoad() {
    super.viewDidLoad()

    label = UILabel(frame: CGRect(x: 20, y: 100, width: 100, height: 23))
    label.text = "iOS Programming Cookbook"
    label.font = UIFont.boldSystemFontOfSize(14)
    view.addSubview(label)

  }

}

Now let’s run our app and see what happens (see Figure 1-6).

A label that is too small in width to contain its contents
Figure 1-6. A label that is too small in width to contain its contents

You can see that the contents of the label are truncated, with a trailing ellipsis, because the width of the label isn’t long enough to contain the whole contents. One solution would be to make the width longer, but how about the height? What if we wanted the text to wrap to the next line? OK, go ahead and change the height from 23.0f to 50.0f:

label = UILabel(frame: CGRect(x: 20, y: 100, width: 100, height: 50))

If you run your app now, you will get exactly the same results that you got in Figure 1-6. You might ask, “I increased the height, so why didn’t the content wrap to the next line?” It turns out that the UILabel class has a property called numberOfLines that needs to be adjusted to the number of lines the label has to wrap the text to, in case it runs out of horizontal space. If you set this value to 3, it tells the label that you want the text to wrap to a maximum of three lines if it cannot fit the text into one line:

import UIKit

class ViewController: UIViewController {
  var label: UILabel!

  override func viewDidLoad() {
    super.viewDidLoad()

    label = UILabel(frame: CGRect(x: 20, y: 100, width: 100, height: 70))
    label.numberOfLines = 3
    label.lineBreakMode = .ByWordWrapping
    label.text = "iOS Programming Cookbook"
    label.font = UIFont.boldSystemFontOfSize(14)
    view.addSubview(label)

  }

}

If you run the app now, you will get the desired results (see Figure 1-7).

A label wrapping its contents to three lines
Figure 1-7. A label wrapping its contents to three lines

Note

In some situations, you might not know how many lines are required to display a certain text in a label. In those instances, you need to set the numberOfLines property of your label to 0.

If you want your label’s frame to stay static and you want the font inside your label to adjust itself to fit into the boundaries of the label, you need to set the adjustsFontSizeToFitWidth property of your label to true. For instance, if the height of our label was 23.0f, as we see in Figure 1-6, we could adjust the font of the label to fit into the boundaries. Here is how it works:

import UIKit

class ViewController: UIViewController {
  var label: UILabel!

  override func viewDidLoad() {
    super.viewDidLoad()

    label = UILabel(frame: CGRect(x: 20, y: 100, width: 100, height: 23))
    label.adjustsFontSizeToFitWidth = true
    label.text = "iOS Programming Cookbook"
    label.font = UIFont.boldSystemFontOfSize(14)
    view.addSubview(label)

  }

}

Rich text is a thing of legend! A lot of us programmers have had the requirement to display mixed-style strings in one line of text on our UI. For instance, in one line of text you might have to display straight and italic text together, where one word is italic and the rest of the words are regular text. Or you might have had to underline a word inside a sentence. For this, some of us had to use Web Views, but that is not the optimal solution because Web Views are quite slow in rendering their content, and that will definitely impact the performance of your app.

Before we begin, I want to clearly show you what I mean by attributed strings, using Figure 1-8. Then we will set out on the journey to write the program to achieve exactly this.

An attributed string is displayed on the screen inside a simple label
Figure 1-8. An attributed string is displayed on the screen inside a simple label

Note

Just to be explicit, this text is rendered inside a single instance of the UILabel class.

So what do we see in this example? I’ll list the pieces:

The text “iOS” with the following attributes:
  • Bold font with size of 60 points

  • Background color of black

  • Font color of red

The text “SDK” with the following attributes:
  • Bold font with size of 60 points

  • White text color

  • Light-gray shadow

  • Red background color

The best way to construct attributed strings is to use the initWithString: method of the mutable variant of the NSMutableAttributedString class and pass an instance of the NSString to this method. This will create our attributed string without any attributes. Then, to assign attributes to different parts of the string, we will use the setAttributes:range: method of the NSMutableAttributedString class. This method takes in two parameters:

setAttributes

A dictionary whose keys are character attributes and the value of each key depends on the key itself. Here are the most important keys that you can set in this dictionary:

NSFontAttributeName

The value of this key is an instance of UIFont and defines the font for the specific range of your string.

NSForegroundColorAttributeName

The value for this key is of type UIColor and defines the color for your text for the specific range of your string.

NSBackgroundColorAttributeName

The value of this key is of type UIColor and defines the background color on which the specific range of your string has to be drawn.

NSShadowAttributeName

The value of this key must be an instance of the NSShadow and defines the shadow that you want to use under the specific range of your string.

range

A value of type NSRange that defines the starting point and the length of characters to which you want to apply the attributes.

Note

To see all the different keys that you can pass to this method, simply browse the Apple documentation online for the NSMutableAttributedString class. I will not put the direct URL to this documentation here because Apple may change the URL at some point, but a simple search online will do the trick.

We’ll break our example down into two dictionaries of attributes. The dictionary of attributes for the word “iOS” can be constructed in this way in code:

let attributesForFirstWord = [
  NSFontAttributeName : UIFont.boldSystemFontOfSize(60),
  NSForegroundColorAttributeName : UIColor.redColor(),
  NSBackgroundColorAttributeName : UIColor.blackColor()
]

And the word “SDK” can be constructed using the following attributes:

let shadow = NSShadow()
shadow.shadowColor = UIColor.darkGrayColor()
shadow.shadowOffset = CGSize(width: 4, height: 4)

let attributesForSecondWord = [
  NSFontAttributeName : UIFont.boldSystemFontOfSize(60),
  NSForegroundColorAttributeName : UIColor.whiteColor(),
  NSBackgroundColorAttributeName : UIColor.redColor(),
  NSShadowAttributeName : shadow,
]

Putting it together, we get the following code that not only creates our label, but also sets its attributed text:

import UIKit

class ViewController: UIViewController {
  var label: UILabel!

  func attributedText() -> NSAttributedString{

    let string = "iOS SDK" as NSString

    let result = NSMutableAttributedString(string: string)

    let attributesForFirstWord = [
      NSFontAttributeName : UIFont.boldSystemFontOfSize(60),
      NSForegroundColorAttributeName : UIColor.redColor(),
      NSBackgroundColorAttributeName : UIColor.blackColor()
    ]

    let shadow = NSShadow()
    shadow.shadowColor = UIColor.darkGrayColor()
    shadow.shadowOffset = CGSize(width: 4, height: 4)

    let attributesForSecondWord = [
      NSFontAttributeName : UIFont.boldSystemFontOfSize(60),
      NSForegroundColorAttributeName : UIColor.whiteColor(),
      NSBackgroundColorAttributeName : UIColor.redColor(),
      NSShadowAttributeName : shadow,
    ]

    /* Find the string "iOS" in the whole string and set its attribute */
    result.setAttributes(attributesForFirstWord,
      range: string.rangeOfString("iOS"))


    /* Do the same thing for the string "SDK" */
    result.setAttributes(attributesForSecondWord,
      range: string.rangeOfString("SDK"))

    return NSAttributedString(attributedString: result)

  }

  override func viewDidLoad() {
    super.viewDidLoad()

    label = UILabel()
    label.backgroundColor = UIColor.clearColor()
    label.attributedText = attributedText()
    label.sizeToFit()
    label.center = CGPoint(x: view.center.x, y: 100)
    view.addSubview(label)

  }

}

1.5. Adding Buttons to the User Interface with UIButton

Problem

You want to display a button on your UI and handle the touch events for that button.

Solution

Use the UIButton class.

Discussion

Buttons allow users to initiate an action in your app. For instance, the iCloud Settings bundle in the Settings app presents a Sign Out button, as you can see in Figure 1-9. If you press this button, the iCloud app will take action. The action depends on the app. Not all apps act the same when a Sign Out button is pressed by the user. Buttons can have images in them as well as text, as we will soon see.

The Sign Out button is visible at the bottom of the page
Figure 1-9. The Sign Out button is visible at the bottom of the page

A button can assign actions to different triggers. For instance, a button can fire one action when the user puts her finger on the button and another action when she lifts her finger off the button. These become actions, and the objects implementing the actions become targets. Let’s go ahead and define a button in our view controller:

import UIKit

class ViewController: UIViewController {
  var button: UIButton!
}

Next, we move on to the implementation of the button (Figure 1-10):

import UIKit

class ViewController: UIViewController {
  var button: UIButton!

  func buttonIsPressed(sender: UIButton){
    println("Button is pressed.")
  }

  func buttonIsTapped(sender: UIButton){
    println("Button is tapped.")
  }

  override func viewDidLoad() {
    super.viewDidLoad()

    button = UIButton.buttonWithType(.System) as? UIButton

    button.frame = CGRect(x: 110, y: 70, width: 100, height: 44)

    button.setTitle("Press Me", forState: .Normal)
    button.setTitle("I'm Pressed", forState: .Highlighted)

    button.addTarget(self,
      action: "buttonIsPressed:",
      forControlEvents: .TouchDown)

    button.addTarget(self,
      action: "buttonIsTapped:",
      forControlEvents: .TouchUpInside)

    view.addSubview(button)

  }
}
A system button is shown here
Figure 1-10. A system button is shown here

In this example code, we are using the setTitle:forState: method of our button to set two different titles for the button. The title is the text that gets displayed on the button. A button can be in different states at different times—such as normal and highlighted (pressed down)—and can display a different title in each state. So in this case, when the user sees the button for the first time, he will read “Press Me.” After he presses the button, the title of the button will change to “I’m Pressed.”

We did a similar thing with the actions that the button fires. We used the addTarget:action:forControlEvents: method to specify two actions for our button:

  1. An action to be fired when the user presses the button down.

  2. Another action to be fired when the user has pressed the button and has lifted his finger off the button. This completes a touch-up-inside action.

The other thing that you need to know about UIButton is that it must always be assigned a type, which you do by initializing it with a call to the class method buttonWithType, as shown in the example code. As the parameter to this method, pass a value of type UIButtonType.

A button can also render an image. An image will replace the default look and feel of the button. When you have an image or a series of images that you want to assign to different states of a button, make sure your button is of type UIButtonTypeCustom. I have prepared two images here: one for the normal state of the button and the other for the highlighted (pressed) state. I will now create my custom button and assign the two images to it.

import UIKit

class ViewController: UIViewController {
  var button: UIButton!

  override func viewDidLoad() {
    super.viewDidLoad()

    let normalImage = UIImage(named: "NormalBlueButton")
    let highlightedImage = UIImage(named: "HighlightedBlueButton")

    button = UIButton.buttonWithType(.Custom) as? UIButton
    button.frame = CGRect(x: 110, y: 70, width: 100, height: 44)

    button.setTitle("Normal", forState: .Normal)
    button.setTitle("Pressed", forState: .Highlighted)

    button.setBackgroundImage(normalImage, forState: .Normal)
    button.setBackgroundImage(highlightedImage, forState: .Highlighted)

    view.addSubview(button)

  }
}

Figure 1-11 shows what the app looks like when we run it in iOS Simulator. We are using the setBackgroundImage:forState: method of the button to set a background image. With a background image, we can still use the setTitle:forState: methods to render text on top of the background image. If your images contain text and you don’t need the title for a button, you can instead use the setImage:forState: method or simply remove the titles from the button.

A button with a background image
Figure 1-11. A button with a background image

1.6. Displaying Alerts and Action Sheets

Problem

You want to display alert views and/or action sheets to the user.

Solution

Use the UIAlertController class to create alert views and action sheets. To get an understanding of what an alert view looks like, take a look at Figure 1-12.

Simple alert view
Figure 1-12. Simple alert view

You can also see an example of an action sheet in Figure 1-13. Both action sheets and alert views can easily be created using the UIAlertController class. This class provides you with an instance of UIViewController that you can present on your own view controllers using the presentViewController:animated:completion: method of UIViewController.

Simple action sheet
Figure 1-13. Simple action sheet

A few steps are involved in creating a simple alert view or action sheet:

  1. Create an instance of the UIAlertController class and specify whether you want an alert view or an action sheet.

  2. For every action that you want to add to your alert view or action sheet (actions are usually represented by a button), create an instance of the UIAlertAction class.

  3. Add your UIAlertAction actions to your alert controller using the addAction: method of your alert controller.

  4. Now that you are all set up, when you are ready to display your alert controller, do so using the presentViewController:animated:completion: method of your host view controller. The host view controller is the view controller that is a part of your application. Every instance of UIViewController inherits the aforementioned method, so you can use that method to display your alert controller. Bear in mind that as we mentioned before, an alert controller is an instance of UIViewController itself, so you can display it like you would a normal view controller.

Discussion

Let’s have a look at constructing a simple alert view using the alert controller that we talked about. The first thing that we have to do, obviously, is define the variable that will hold our alert controller.

import UIKit

class ViewController: UIViewController {

  var controller:UIAlertController?

}

Next we are going to start constructing a simple alert view controller using the alert view style:

controller = UIAlertController(title: "Title",
  message: "Message",
  preferredStyle: .Alert)

Now that the alert controller is created, we are going to create an action that will simply print out a text to the console when pressed.

let action = UIAlertAction(title: "Done",
  style: UIAlertActionStyle.Default,
  handler: {(paramAction:UIAlertAction!) in
  println("The Done button was tapped")
  })

The only thing that is left now in order to construct the alert controller is to add the action that we created to the alert controller like so:

controller!.addAction(action)

When our view appears on the screen, we will attempt to present the alert controller, that holds an alert view, to the user:

override func viewDidAppear(animated: Bool) {
  super.viewDidAppear(animated)
  self.presentViewController(controller!, animated: true, completion: nil)
}

So by now, the code for our view controller will look like this:

import UIKit

class ViewController: UIViewController {

  var controller:UIAlertController?

  override func viewDidLoad() {
    super.viewDidLoad()

    controller = UIAlertController(title: "Title",
      message: "Message",
      preferredStyle: .Alert)

    let action = UIAlertAction(title: "Done",
      style: UIAlertActionStyle.Default,
      handler: {(paramAction:UIAlertAction!) in
      println("The Done button was tapped")
      })

    controller!.addAction(action)

  }

  override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    self.presentViewController(controller!, animated: true, completion: nil)
  }

}

Let’s talk a bit about how we constructed our alert controller. The constructor for UIAlertController is alertControllerWithTitle:message:preferredStyle. The title is a simple string that will usually be displayed on top of the alert or the action view. The message is an optional message that you would like to display to the user. This message usually appears under the title. Last but not least is the style of the alert controller, which you can set to either an alert (.Alert) or an action sheet (.ActionSheet). This style must be of type UIAlertControllerStyle.

We have now seen how we can construct a simple alert view. There is one more thing that I would like to show you before we conclude speaking about alert views, and that is adding text fields to alert views. Sometimes you want to capture some text in your app from the user—for instance, their username or some sort of an ID—using a popup dialog. You can do this easily using the alert controller. All you have to do is use the addTextFieldWithConfigurationHandler: method of your alert controller to add a text field to your alert view. Figure 1-14 shows you an example of how an alert view looks with a text field configured in it.

Alert view with text field
Figure 1-14. Alert view with text field

This is how we added the text field to our alert controller:

controller!.addTextFieldWithConfigurationHandler(
  {(textField: UITextField!) in
    textField.placeholder = "XXXXXXXXXX"
  })

And then, in our action closure that we constructed before, we can access the text fields in our alert controller using its textFields property. This is an array of text fields, and we want the text field in the zeroeth place because we have only one. So the code for the action to our alert view becomes so:

let action = UIAlertAction(title: "Next",
  style: UIAlertActionStyle.Default,
  handler: {[weak self] (paramAction:UIAlertAction!) in
    
    if let textFields = self!.controller?.textFields{
      let theTextFields = textFields as [UITextField]
      let userName = theTextFields[0].text
      println("Your username is \(userName)")
    }
    
  })

Now let’s have a look at constructing action sheets. Action sheets are also very similar to alert views, but the way in which they appear on the screen is different and they cannot contain text fields in them. They also have a concept of a destructive button that is visually very distinct. A destructive button is a button that usually terminates the alert view or the action sheet by doing something that is irreversible. For instance, if a delete or remove button causes an irreversible action such as losing information previously entered by the user, the button is said to be destructive. Alert views also have destructive buttons, but the way a destructive button is presented in an alert view is not as prominent as in an action sheet.

Now we want to display an action sheet similar to that shown in Figure 1-15.

Action sheet with destructive button
Figure 1-15. Action sheet with destructive button

First we will start by creating our alert controller:

controller = UIAlertController(
  title: "Choose how you would like to share this photo",
  message: "You cannot bring back a deleted photo",
  preferredStyle: .ActionSheet)

And then we will create our actions:

let actionEmail = UIAlertAction(title: "Via email",
  style: UIAlertActionStyle.Default,
  handler: {(paramAction:UIAlertAction!) in
    /* Send the photo via email */
  })

let actionImessage = UIAlertAction(title: "Via iMessage",
  style: UIAlertActionStyle.Default,
  handler: {(paramAction:UIAlertAction!) in
    /* Send the photo via iMessage */
  })

let actionDelete = UIAlertAction(title: "Delete photo",
  style: UIAlertActionStyle.Destructive,
  handler: {(paramAction:UIAlertAction!) in
    /* Delete the photo here */
  })

Once the actions are created, we add them to our alert controller like so:

controller!.addAction(actionEmail)
controller!.addAction(actionImessage)
controller!.addAction(actionDelete)

Everything is now set up for us to show our alert controller to the user, which we do when our view controller is displayed on the screen:

override func viewDidAppear(animated: Bool) {
  super.viewDidAppear(animated)
  self.presentViewController(controller!, animated: true, completion: nil)
}

See Also

Recipe 1.5

1.7. Creating, Using, and Customizing Switches with UISwitch

Problem

You would like to give your users the ability to turn an option on or off.

Solution

Use the UISwitch class.

Discussion

The UISwitch class provides an On/Off control like the one shown in Figure 1-16 for Auto-Capitalization, Auto-Correction, and so on.

UISwitch in the Settings app
Figure 1-16. UISwitch in the Settings app

In order to create a switch, you can either use Interface Builder or simply create your instance in code. Let’s do it through code. Let’s create a property of type UISwitch:

import UIKit

class ViewController: UIViewController {

  var mainSwitch:UISwitch!

}

We can go ahead now and create our switch:

import UIKit

class ViewController: UIViewController {

  var mainSwitch:UISwitch!

  override func viewDidLoad() {
    super.viewDidLoad()

    mainSwitch = UISwitch(frame: CGRect(x: 100, y: 100, width: 0, height: 0))
    view.addSubview(mainSwitch)

  }

}

So we are allocating an object of type UISwitch and using the initWithFrame: constructor to initialize our switch. Note that the parameter that we have to pass to this method is of type CGRect. A CGRect denotes the boundaries of a rectangle using the (x,y) position of the top-left corner of the rectangle and its width and height. After we’ve created the switch, we simply add it to our view controller’s view.

Now let’s run our app on iOS Simulator. Figure 1-17 shows what happens.

A switch placed on a view
Figure 1-17. A switch placed on a view

As you can see, the switch’s default state is off. We can change this by changing the value of the on property of the switch. Alternatively, you can call the setOn: method on the switch, as shown here:

mainSwitch.setOn(true, animated: true)

You can prettify the user interaction by using the setOn:animated: method of the switch. The animated parameter accepts a Boolean value. If this Boolean value is set to true, the change in the switch’s state (from on to off or off to on) will be animated, just as if the user were interacting with it.

Obviously, you can read from the on property of the switch to find out whether the switch is on or off at the moment. Alternatively, you can use the isOn method of the switch, as shown here:

if mainSwitch.on{
  /* Switch is on */
} else {
  /* Switch is off */
}

If you want to get notified when the switch gets turned on or off, you will need to add your class as the target for the switch, using the addTarget:action:forControlEvents: method of UISwitch, as shown here:

mainSwitch.addTarget(self,
  action: "switchIsChanged:",
  forControlEvents: .ValueChanged)

Then implement the switchIsChanged: method. When the runtime calls this method for the UIControlEventValueChanged event of the switch, it will pass the switch as the parameter to this method so you can find out which switch fired this event:

func switchIsChanged(sender: UISwitch){
  println("Sender is = \(sender)")

  if sender.on{
    println("The switch is turned on")
  } else {
    println("The switch is turned off")
  }
}

There are two main ways of customizing a switch:

Tint Colors

Tint colors are colors that you can apply to a UI component such as a UISwitch. The tint color will be applied on top of the current color of the component. For instance, in a normal UISwitch, you will be able to see different colors. When you apply the tint color on top, the normal color of the control will be mixed with the tint color, giving a flavor of the tint color on the UI control.

Images

A switch has two images:

On Image

The image that represents the on state of the switch. The width of this image is 77 points, and its height is 22.

Off Image

The image that represents the switch in its off state. This image, like the on state of the switch, is 77 points in width and 22 points in height.

Let’s get started by learning how we can change the tint color of the switch UI component. This can be achieved by using three important properties of the UISwitch class. Each of these properties is of type UIColor.

tintColor

This is the tint color that will be applied to the off state of the switch. Unfortunately, Apple has not taken the time to name this property offTintColor instead of tintColor to make it more explicit.

thumbTintColor

This is the tint color that will be applied to the little knob on the switch.

onTintColor

This tint color will be applied to the switch in its on state.

Here is a simple code snippet that will change the on-mode tint color of the switch to red, the off-mode tint color to brown, and the knob’s tint color to green. It is not the best combination of colors but will demonstrate what this recipe is trying to explain:

override func viewDidLoad() {
  super.viewDidLoad()

  mainSwitch = UISwitch(frame: CGRect(x: 100, y: 100, width: 0, height: 0))

  /* Adjust the off-mode tint color */
  mainSwitch.tintColor = UIColor.redColor()
  /* Adjust the on-mode tint color */
  mainSwitch.onTintColor = UIColor.brownColor()
  /* Also change the knob's tint color */
  mainSwitch.thumbTintColor = UIColor.greenColor()

  view.addSubview(mainSwitch)

}

1.8. Picking Values with the UIPickerView

Problem

You want to allow the users of your app to select from a list of values.

Solution

Use the UIPickerView class.

Discussion

A picker view is a graphical element that allows you to display a series of values to your users and allow them to pick one. The Timer section of the Clock app on the iPhone is a great example of this (Figure 1-18).

A picker view on top of the screen
Figure 1-18. A picker view on top of the screen

As you can see, this specific picker view has two separate and independent visual elements. One is on the left, and one is on the right. The element on the left is displaying hours (such as 0, 1, 2 hours, etc.) and the one on the right is displaying minutes (such as 10, 11, 12 mins, etc.). These two items are called components. Each component has rows. Any item in any of the components is in fact represented by a row, as we will soon see. For instance, in the left component, “0 hours” is a row, “1” is a row, etc.

Let’s go ahead and create a picker view on our view controller’s view.

import UIKit

class ViewController: UIViewController {

  var picker: UIPickerView!

}

Now let’s create the picker view in the viewDidLoad method of our view controller:

import UIKit

class ViewController: UIViewController {

  var picker: UIPickerView!

  override func viewDidLoad() {
    super.viewDidLoad()

    picker = UIPickerView()
    picker.center = view.center
    view.addSubview(picker)
  }

}

It’s worth noting that in this example, we are centering our picker view at the center of our view. When you run this app on the simulator, you will see a blank screen because the picker is white and so is the view controller’s background.

The reason this picker view is showing up as a plain white color is that we have not yet populated it with any values. Let’s do that. We do that by specifying a data source for the picker view and then making sure that our view controller sticks to the protocol that the data source requires. The data source of an instance of UIPickerView must conform to the UIPickerViewDataSource protocol, so let’s go ahead and make our view controller conform to this protocol:

class ViewController: UIViewController, UIPickerViewDataSource

Good. Let’s now change our code to make sure we select the current view controller as the data source of the picker view:

override func viewDidLoad() {
  super.viewDidLoad()

  picker = UIPickerView()
  picker.dataSource = self
  picker.center = view.center
  view.addSubview(picker)
}

After this, if you try to compile your application, you will get errors from the compiler telling you that you have not yet implemented some of the methods that the UIPickerViewDataSource protocol wants you to implement. The way to fix this is to press Command+Shift+O, type UIPickerViewDataSource, and press the Enter key on your keyboard. That will send you to the place in your code where this protocol is defined. Let’s go and implement them in our view controller:

func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
  if pickerView == picker{
    return 1
  }
  return 0
}

func pickerView(pickerView: UIPickerView,
  numberOfRowsInComponent component: Int) -> Int {
  if pickerView == picker{
    return 10
  }
  return 0
}

So what is happening here? Let’s have a look at what each one of these data source methods expects:

numberOfComponentsInPickerView:

This method passes you a picker view object as its parameter and expects you to return an integer, telling the runtime how many components you want that picker view to render.

pickerView:numberOfRowsInComponent:

For each component that gets added to a picker view, you will need to tell the system how many rows you want to render in that component. This method passes you an instance of picker view, and you will need to return an integer indicating the number of rows to render for that component.

So in the previous code listing, we are asking the system to display 1 component with only 10 rows for a picker view that we have created before.

Compile and run your application now. Ewww, what is that? Yes, indeed, we can now see the picker view, but all the items are populated incorrectly and not with the values that we have in mind. Actually, that doesn’t have to worry you too much. The reason behind this is that the picker view knows the number of sections and items that we want to display but doesn’t precisely know the items we need to show. That is something that we need to do now, and we do that by providing a delegate to the picker view. The delegate of an instance of UIPickerView has to conform to the UIPickerViewDelegate protocol and must implement all the @required methods of that protocol.

There is only one method in the UIPickerViewDelegate we are interested in: the pickerView:titleForRow:forComponent: method. This method will pass you the index of the current section and the index of the current row in that section for a picker view, and it expects you to return an instance of NSString. This string will then get rendered for that specific row inside the component. In here, I would simply like to display the first row as Row 1, and then continue to Row 2, Row 3, etc., until the end. Remember, we also have to set the delegate property of our picker view:

picker!.delegate = self

And now we will handle the delegate method we just learned about:

func pickerView(pickerView: UIPickerView,
  titleForRow row: Int,
  forComponent component: Int) -> String!{
  return "\(row + 1)"
}

Now let’s run our app and see what happens (Figure 1-19).

A picker view with one section and a few rows
Figure 1-19. A picker view with one section and a few rows

Now imagine that you created this picker view in your final application. What is the use of a picker view if we cannot detect what the user has actually selected in each one of its components? Well, it’s good that Apple has already thought of that and given us the ability to ask the picker view what is selected. Call the selectedRowInComponent: method of a UIPickerView and pass the zero-based index of a component. The method will return an integer indicating the zero-based index of the row that is currently selected in that component.

If you need to modify the values in your picker view at runtime, you need to make sure that your picker view reloads its data from its data source and delegate. To do that, you can either force all the components to reload their data, using the reloadAllComponents method, or you can ask a specific component to reload its data, using the reloadComponent: method and passing the index of the component that has to be reloaded.

See Also

Recipe 1.7

1.9. Picking the Date and Time with UIDatePicker

Problem

You want to allow the users of your app to select a date and time using an intuitive and ready-made user interface.

Solution

Use the UIDatePicker class.

Discussion

UIDatePicker is very similar to the UIPickerView class. The date picker is in fact a prepopulated picker view. A good example of the date picker control is in the Calendar app on the iPhone.

Let’s get started by first declaring a property of type UIDatePicker. Then we’ll allocate and initialize this property and add it to the view of our view controller:

import UIKit

class ViewController: UIViewController {

  var datePicker: UIDatePicker!

  override func viewDidLoad() {
    super.viewDidLoad()

    datePicker = UIDatePicker()
    datePicker.center = view.center
    view.addSubview(datePicker)

  }

}

Now let’s run the app and see how it looks in Figure 1-20.

A simple date picker
Figure 1-20. A simple date picker

You can see that the date picker, by default, has picked today’s date. The first thing that we need to know about date pickers is that they can have different styles or modes. This mode can be changed through the datePickerMode property, which is of type UIDatePickerMode.

Depending on what you need, you can set the mode of your date picker to any of the values listed in the UIDatePickerMode enumeration. I’ll show some of these as we go along.

Now that you have successfully displayed a date picker on the screen, you can attempt to retrieve its currently selected date using its date property. Alternatively, you can call the date method on the date picker, like so:

let currentDate = datePicker.date
println(currentDate)

Just like the UISwitch class, a date picker sends action messages to its targets whenever the user has selected a different date. To respond to these messages, the receiver must add itself as the target of the date picker, using the addTarget:action:forControlEvents: method, like so:

import UIKit

class ViewController: UIViewController {

  var datePicker: UIDatePicker!

  func datePickerDateChanged(datePicker: UIDatePicker){
    println("Selected date = \(datePicker.date)")
  }

  override func viewDidLoad() {
    super.viewDidLoad()

    datePicker = UIDatePicker()
    datePicker.center = view.center
    view.addSubview(datePicker)

    datePicker.addTarget(self,
      action: "datePickerDateChanged:",
      forControlEvents: .ValueChanged)

  }

}

Now, every time the user changes the date, you will get a message from the date picker.

A date picker also lets you set the minimum and the maximum dates that it can display. For this, let’s first switch our date picker mode to UIDatePickerModeDate and then, using the maximumDate and the minimumDate properties, adjust this range:

import UIKit

class ViewController: UIViewController {

  var datePicker: UIDatePicker!

  override func viewDidLoad() {
    super.viewDidLoad()

    datePicker = UIDatePicker()
    datePicker.center = view.center
    view.addSubview(datePicker)

    let oneYearTime:NSTimeInterval = 365 * 24 * 60 * 60
    let todayDate = NSDate()

    let oneYearFromToday = todayDate.dateByAddingTimeInterval(oneYearTime)

    let twoYearsFromToday = todayDate.dateByAddingTimeInterval(2 * oneYearTime)

    datePicker.minimumDate = oneYearFromToday
    datePicker.maximumDate = twoYearsFromToday

  }

}

With these two properties, we can then limit the user’s selection on the date to a specific range. In this example code, we limited the user’s input of dates to the range of one year to two years from now.

If you want to use the date picker as a countdown timer, you must set your date picker mode to UIDatePickerModeCountDownTimer and use the countDownDuration property of the date picker to specify the default countdown duration. For instance, if you want to present a countdown picker to the user and set the default countdown duration to two minutes, write code like this:

import UIKit

class ViewController: UIViewController {

  var datePicker: UIDatePicker!

  override func viewDidLoad() {
    super.viewDidLoad()

    datePicker = UIDatePicker()
    datePicker.center = view.center
    datePicker.datePickerMode = .CountDownTimer
    let twoMinutes = (2 * 60) as NSTimeInterval
    datePicker.countDownDuration = twoMinutes
    view.addSubview(datePicker)

  }

}

The results are shown in Figure 1-21.

A two-minute countdown duration set on a date picker
Figure 1-21. A two-minute countdown duration set on a date picker

1.10. Implementing Range Pickers with UISlider

Problem

You want to allow your users to specify a value within a range, using an easy-to-use and intuitive UI.

Solution

Use the UISlider class.

Discussion

You’ve certainly seen sliders before. Figure 1-22 shows an example.

The volume slider
Figure 1-22. The volume slider

To create a slider, instantiate an object of type UISlider. Let’s dive right in and create a slider and place it on our view controller’s view. First, let’s go to the viewDidLoad method and create our slider component. In this code, we are going to give our slider a range between 0 and 100 and set its default position to be halfway between start and end.

Note

The range of a slider has nothing to do with its appearance. We use the range specifiers of a slider to tell the slider to calculate its value based on the relative position within the range. For instance, if the range of a slider is provided as 0 to 100, when the knob on the slider is on the leftmost part, the value property of the slider is 0, and if the knob is to the rightmost side of the slider, the value property is 100.

import UIKit

class ViewController: UIViewController {

  var slider: UISlider!

  override func viewDidLoad() {
    super.viewDidLoad()

    slider = UISlider(frame: CGRect(x: 0, y: 0, width: 200, height: 23))
    slider.center = view.center
    slider.minimumValue = 0
    slider.maximumValue = 100
    slider.value = slider.maximumValue / 2.0
    view.addSubview(slider)

  }

}

What do the results look like? You can now run the app on the simulator and you’ll get results like those shown in Figure 1-23.

A simple slider at the center of the screen
Figure 1-23. A simple slider at the center of the screen

We used a few properties of the slider to get the results we wanted. What were they?

minimumValue

Specifies the minimum value of the slider’s range.

maximumValue

Specifies the maximum value of the slider’s range.

value

The current value of the slider. This is a read/write property, meaning that you can both read from it and write to it. If you want the slider’s knob to be moved to this value in an animated mode, you can call the setValue:animated: method of the slider and pass true as the animated parameter.

The little knob on a slider is called the thumb. If you wish to receive an event whenever the slider’s thumb has moved, you must add your object as the target of the slider, using the slider’s addTarget:action:forControlEvents: method:

import UIKit

class ViewController: UIViewController {

  var slider: UISlider!

  func sliderValueChanged(slider: UISlider){
    println("Slider's new value is \(slider.value)")
  }

  override func viewDidLoad() {
    super.viewDidLoad()

    slider = UISlider(frame: CGRect(x: 0, y: 0, width: 200, height: 23))
    slider.center = view.center
    slider.minimumValue = 0
    slider.maximumValue = 100
    slider.value = slider.maximumValue / 2.0

    slider.addTarget(self,
      action: "sliderValueChanged:",
      forControlEvents: .ValueChanged)

    view.addSubview(slider)

  }

}

If you run the application on the simulator now, you will notice that the sliderValueChanged: target method gets called whenever and as soon as the slider’s thumb moves. This might be what you want, but in some cases, you might need to get notified only after the user has let go of the thumb on the slider and let it settle. If you want to wait to be notified, set the continuous property of the slider to false. This property, when set to true (its default value), will call the slider’s targets continuously while the thumb moves.

The iOS SDK also gives you the ability to modify how a slider looks. For instance, the thumb on the slider can have a different image. To change the image of the thumb, simply use the setThumbImage:forState: method and pass an image along with a second parameter that can take any of these values:

UIControlStateNormal

The normal state of the thumb, with no user finger on this component.

UIControlStateHighlighted

The image to display for the thumb while the user is moving her finger on this component.

I have prepared two images: one for the normal state of the thumb and the other one for the highlighted (touched) state of the thumb. Let’s go ahead and add them to the slider:

import UIKit

class ViewController: UIViewController {

  var slider: UISlider!

  override func viewDidLoad() {
    super.viewDidLoad()

    slider = UISlider(frame: CGRect(x: 0, y: 0, width: 200, height: 23))
    slider.center = view.center
    slider.minimumValue = 0
    slider.maximumValue = 100
    slider.value = slider!.maximumValue / 2.0

    slider.setThumbImage(UIImage(named: "ThumbNormal"), forState: .Normal)
    slider.setThumbImage(UIImage(named: "ThumbHighlighted"), forState: .Highlighted)

    view.addSubview(slider)

  }

}

And now let’s have a look and see how our normal thumb image looks in the simulator (Figure 1-24).

A slider with a custom thumb image
Figure 1-24. A slider with a custom thumb image

1.11. Grouping Compact Options with UISegmentedControl

Problem

You would like to present a few options to your users from which they can pick an option through a UI that is compact, simple, and easy to understand.

Solution

Use the UISegmentedControl class, an example of which is shown in Figure 1-25.

A segmented control displaying four options
Figure 1-25. A segmented control displaying four options

Discussion

A segmented control is a UI component that allows you to display, in a compact UI, a series of options for the user to choose from. To show a segmented control, create an instance of UISegmentedControl. First, we will create the segmented control in the viewDidLoad method of your view controller:

import UIKit

class ViewController: UIViewController {

  var segmentedControl:UISegmentedControl!

  override func viewDidLoad() {
    super.viewDidLoad()

    let segments = [
      "iPhone",
      "iPad",
      "iPod",
      "iMac"]

    segmentedControl = UISegmentedControl(items: segments)
    segmentedControl.center = view.center
    self.view.addSubview(segmentedControl)

  }

}

We are simply using an array of strings to provide the different options that our segmented control has to display. We initialize our segmented control using the initWithObjects: constructor and pass the array of strings and images to the segmented control. The results will look like what we saw in Figure 1-25.

Now the user can pick one of the options in the segmented control. Let’s say she picked iPad. The segmented control will then change its user interface to show the user the option she has selected, as depicted in Figure 1-26.

User has selected one of the items in a segmented control
Figure 1-26. User has selected one of the items in a segmented control

Now the question is, how do you recognize when the user selects a new option in a segmented control? The answer is simple. Just as with a UISwitch or a UISlider, use the addTarget:action:forControlEvents: method of the segmented control to add a target to it. Provide the value of UIControlEventValueChanged for the forControlEvents parameter, because that is the event that gets fired when the user selects a new option in a segmented control:

import UIKit

class ViewController: UIViewController {

  var segmentedControl:UISegmentedControl!

  func segmentedControlValueChanged(sender: UISegmentedControl){

    let selectedSegmentIndex = sender.selectedSegmentIndex

    let selectedSegmentText =
    sender.titleForSegmentAtIndex(selectedSegmentIndex)

    println("Segment \(selectedSegmentIndex) with text" +
      " of \(selectedSegmentText) is selected")
  }

  override func viewDidLoad() {
    super.viewDidLoad()

    let segments = [
      "iPhone",
      "iPad",
      "iPod",
      "iMac"]

    segmentedControl = UISegmentedControl(items: segments)
    segmentedControl.center = view.center

    segmentedControl.addTarget(self,
      action: "segmentedControlValueChanged:",
      forControlEvents: .ValueChanged)

    self.view.addSubview(segmentedControl)

  }

}

If the user starts from the left side and selects each of the options in Figure 1-25, all the way to the right side of the control, the following text will print out to the console:

Segment 0 with text of iPhone is selected
Segment 1 with text of iPad is selected
Segment 2 with text of iPod is selected
Segment 3 with text of iMac is selected

As you can see, we used the selectedSegmentIndex method of the segmented control to find the index of the currently selected item. If no item is selected, this method returns the value –1. We also used the titleForSegmentAtIndex: method. Simply pass the index of an option in the segmented control to this method, and the segmented control will return the text for that item. Simple, isn’t it?

As you might have noticed, when the user selects an option in a segmented control, that option will get selected and remain selected, as shown in Figure 1-26. If you want the user to be able to select an option but you want the button for that option to bounce back to its original shape after it has been selected (just like a normal button that bounces back up after it is tapped), you need to set the momentary property of the segmented control to true:

segmentedControl.momentary = true

One of the really neat features of segmented controls is that they can contain images instead of text. To do this, simply use the initWithObjects: constructor method of the UISegmentedControl class and pass the strings and images that will be used to initialize the segmented UI control:

import UIKit

class ViewController: UIViewController {

  var segmentedControl:UISegmentedControl!
  override func viewDidLoad() {
    super.viewDidLoad()

    let segments = NSArray(objects:
      "Red",
      UIImage(named: "blueDot")!,
      "Green",
      "Yellow")

    segmentedControl = UISegmentedControl(items: segments)
    segmentedControl.center = view.center
    self.view.addSubview(segmentedControl)

  }

}

Note

In this example, the blueDot file is simply a blue circle image with the dimensions of 32x32@2x and 16x16@1x.

1.12. Presenting Sharing Options with UIActivityViewController

Problem

You want to be able to allow your users to share content inside your apps with their friends via an interface similar to that shown in Figure 1-27 that provides different sharing options available in iOS, such as Facebook and Twitter.

The activity view controller
Figure 1-27. The activity view controller

Solution

Create an instance of the UIActivityViewController class and share your content through this class, as we will see in the Discussion section of this recipe.

Note

The instances of UIActivityViewController must be presented modally on the iPhone and inside a popover on an iPad. For more information about popovers, refer to Recipe 1.2.

Discussion

There are many sharing options inside iOS, all built into the core of the OS. For instance, Facebook and Twitter integration is an integral part of the core of iOS, and you can share pretty much any content from anywhere you want. Third-party apps like ours can also use all the sharing functionalities available in iOS without having to think about the low-level details of these services and how iOS provides these sharing options. The beauty of this whole thing is that you mention what you want to share, and iOS will pick the sharing options that are capable of handling those items. For instance, if you want to share images and text, iOS will display many more items to you than if you want to share an audio file.

Sharing data is very easy in iOS. All you have to do is instantiate the UIActivityViewController class using its initWithActivityItems:applicationActivities: constructor. Here are the parameters to this method:

initWithActivityItems

The array of items that you want to share. These can be instances of NSString, UIImage, or instances of any of your custom classes that conform to the UIActivityItemSource protocol. We will talk about this protocol later in detail.

applicationActivities

An array of instances of UIActivity that represent the activities that your own application supports. For instance, you can indicate here whether your application can handle its own sharing of images and strings. We will not go into detail about this parameter for now and will simply pass nil as its value, telling iOS that we want to stick to the system sharing options.

So let’s say that you have a text field where the user can enter text to be shared, and a Share button near it. When the user presses the Share button, you will simply pass the text of the text field to your instance of the UIActivityViewController class. We are writing this code for iPhone, so we will present our activity view controller as a modal view controller.

Because we are putting a text field on our view controller, we need to make sure that we are handling its delegate messages, especially the textFieldShouldReturn: method of the UITextFieldDelegate protocol. Therefore, we are going to elect our view controller as the delegate of the text field. Also, we are going to attach an action method to our Share button. When the button is tapped, we want to make sure there is something in the text field to share. If there isn’t, we will simply display an alert to the user telling him why we cannot share the content of the text field. If there is some text in the text field, we will pop up an instance of the UIActivityViewController class.

We start off with writing two methods for our view controller, each of which is able to create one of our UI components and place it on our view controller’s view. One will create the text field, and the other will create the button next to it:

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

  var textField:UITextField!
  var buttonShare:UIButton!

  func createTextField(){
    textField = UITextField(frame:
      CGRect(x: 20, y: 35, width: 280, height: 30))
    textField.borderStyle = .RoundedRect;
    textField.placeholder = "Enter text to share..."
    textField.delegate = self
    view.addSubview(textField)
  }

  func createButton(){
    buttonShare = UIButton.buttonWithType(.System) as? UIButton
    buttonShare.frame = CGRect(x: 20, y: 80, width: 280, height: 44)
    buttonShare.setTitle("Share", forState:.Normal)

    buttonShare.addTarget(self,
      action:"handleShare:",
      forControlEvents:.TouchUpInside)

    view.addSubview(buttonShare)
  }

}

When we are done with that, we just have to call these two methods in the viewDidLoad method of our view controller. This will allow the UI components to be placed on the view of our view controller:

override func viewDidLoad() {
  super.viewDidLoad()
  createTextField()
  createButton()
}

In the textFieldShouldReturn: method, all we do is dismiss the keyboard in order to resign the text field’s active state. This simply means that when a user has been editing the text field and then presses the Return or Enter key on the keyboard, the keyboard should be dismissed. Bear in mind that the createTextField method that we just coded has set our view controller as the delegate of the text field. So we have to implement the aforementioned method as follows:

func textFieldShouldReturn(textField: UITextField!) -> Bool{
  textField.resignFirstResponder()
  return true
}

Last but not least is the handler method of our button. As you saw, the createButton method creates the button for us and elects the handleShare: method to handle the touch down inside action of the button. So let’s code this method:

func handleShare(sender: UIButton){

  if (textField.text.isEmpty){
    let message = "Please enter a text and then press Share"

    let alertController = UIAlertController(title: nil,
      message: message,
      preferredStyle: .Alert)

    alertController.addAction(
      UIAlertAction(title: "OK", style: .Default, handler: nil))

    presentViewController(alertController, animated: true, completion: nil)

    return
  }

  /* it is VERY important to cast your strings to NSString
  otherwise the controller cannot display the appropriate sharing options */
  activityViewController = UIActivityViewController(
    activityItems: [textField.text as NSString],
    applicationActivities: nil)

  presentViewController(activityViewController,
    animated: true,
    completion: {
    })
}

Note

If you want to present sharing options for textual items, you need to ensure that your strings are typecast to strings of type NSString. Swift’s string of type String cannot be handled by an activity view controller.

Now if you run the app, enter some text in the text field, and then press the Share button, you will see something similar to Figure 1-28.

Sharing options displayed for the instance of string that we are trying to share
Figure 1-28. Sharing options displayed for the instance of string that we are trying to share

You can also have sharing options displayed as soon as your view controller is displayed on the screen. The viewDidAppear method of your view controller will be called when the view of your view controller is displayed on the screen and is guaranteed to be in the view hierarchy of your app, meaning that you can now display other views on top of your view controller’s view.

Warning

Do not attempt to present the activity view controller in the viewDidLoad method of your view controller. At that stage in the app, your view controller’s view is still not attached to the view hierarchy of the application, so attempting to present a view controller on the view will not work. Your view must be present in the hierarchy of the views for your modal views to work.

For this reason, you need to present the sharing view controller in the viewDidAppear method of your view controller.

See Also

Recipe 1.2

1.13. Presenting Custom Sharing Options with UIActivityViewController

Problem

You want your app to participate in the list of apps that can handle sharing in iOS and appear in the list of available activities displayed in the activity view controller (see Figure 1-27).

For example, you might need something like this if you have a text-editing app and you want a custom item that says “Archive” to appear in the activity view controller when the user presses the Share button. When the user presses the Archive button, the text inside your app’s editing area will get passed to your custom activity, and your activity can then archive that text on the iOS device.

Solution

Create a class of type UIActivity. In other words, subclass the aforementioned class and give a name (whatever you like) to your new class. Instances of the subclasses of this class can be passed to the initWithActivityItems:applicationActivities: constructor of the UIActivityViewController class, and if they implement all the required methods of the UIActivity class, iOS will display them in the activity view controller.

Discussion

The initWithActivityItems:applicationActivities: method’s first parameter accepts values of different types. These values can be strings, numbers, images, etc.—any object, really. When you present an activity controller with an array of arbitrary objects passed to the initWithActivityItems parameter, iOS will go through all the available system activities, like Facebook and Twitter, and ask the user to pick an activity that suits her needs best. After the user picks an activity, iOS will pass the type of the objects in your array to the registered system activity that the user picked. Those activities can then check the type of the objects you are trying to share and decide whether they can handle those objects or not. They communicate this to iOS through a specific method that they will implement in their classes.

So let’s say that we want to create an activity that can reverse any number of strings that are handed to it. Remember that when your app initializes the activity view controller through the initWithActivityItems:applicationActivities: method, it can pass an array of arbitrary objects to the first parameter of this method. So our activity is going to peek at all these objects in this arbitrary array, and if they are all strings, it is going to reverse them and then display all the reversed strings in the console.

  1. Subclass UIActivity as shown here:

import UIKit

class StringReverserActivity: UIActivity {

  /*
  This will aggregate all the activity items that are acceptable by us.
  We will be passed an array of various class types and we will go through
  them all and only select the string items and put them in this array.
  */
  var activityItems = [NSString]()

}
  1. Next, override the activityType method of your activity. The return value of this method is an object of type NSString that is a unique identifier of your activity. This value will not be displayed to the user and is just for iOS to keep track of your activity’s identifier. There are no specific values that you are asked to return from this method and no guidelines available from Apple, but we will follow the reverse-domain string format and use our app’s bundle identifier and append the name of our class to the end of it. So if our bundle identifier is equal to com.pixolity.ios.cookbook.myapp and our class name is StringReverserActivity, we will return com.pixolity.ios.cookbook.myapp.StringReverserActivity from this method, like so:

override func activityType() -> String {
  return NSBundle.mainBundle().bundleIdentifier! + ".StringReverserActivity"
}
  1. The next method to override is the activityTitle method, which should return a string to be displayed to the user in the activity view controller. Make sure this string is short enough to fit into the activity view controller:

override func activityTitle() -> String {
  return "Reverse String"
}
  1. The next method is activityImage, which has to return an instance of UIImage that gets displayed in the activity view controller. Make sure that you provide both Retina and non-Retina versions of the image for both iPad and iPhone/iPod. The iPad Retina image has to be 110×110 pixels and the iPhone Retina image has to be 86×86 pixels. Obviously, divide these dimensions by 2 to get the width and the height of the non-Retina images. iOS uses only the alpha channel in this image, so make sure your image’s background is transparent and that you illustrate your image with the color white or the color black. I have already created an image in my app’s image assets section, and I’ve named the image “Reverse,” as you can see in Figure 1-29. Here is our code, then:

override func activityImage() -> UIImage {
  return UIImage(named: "Reverse")!
}
Our asset category contains images for our custom activity
Figure 1-29. Our asset category contains images for our custom activity
  1. Implement the canPerformWithActivityItems: method of your activity. This method’s parameter is an array that will be set when an array of activity items is passed to the constructor of the activity view controller. Remember, these are objects of arbitrary type. The return value of your method will be a Boolean indicating whether you can perform your actions on any of the given items or not. For instance, our activity can reverse any number of strings that it is given. So if we find one string in the array, that is good enough for us because we know we will later be able to reverse that string. If we are given an array of 1,000 objects that contains only 2 strings, we will still accept it. But if we are given an array of 1,000 objects, none of which are of our acceptable type, we will reject this request by returning false from this method:

override func canPerformWithActivityItems(
  activityItems: [AnyObject]) -> Bool {

    for object:AnyObject in activityItems{
      if object is String{
        return true
      }
    }

    return false

}
  1. Now implement the prepareWithActivityItems: method of your activity, whose parameter is of type NSArray. This method gets called if you returned true from the canPerformWithActivityItems: method. You have to retain the given array for later use or you may choose to retain only the objects that you need in this array, such as the string objects. You may choose to retain only the objects you need in this array, such as the string objects.

override func prepareWithActivityItems(paramActivityItems: [AnyObject]) {

  for object:AnyObject in paramActivityItems{
    if object is String{
      activityItems.append(object as String)
    }
  }

}
  1. Last but not least, you need to implement the performActivity method of your activity, which gets called when iOS wants you to actually perform your actions on the list of previously-provided arbitrary objects. In this method, basically, you have to perform your work. In our activity, we are going to go through the array of string objects that we extracted from this arbitrary array, reverse all of them, and display them in the console. You can come up with a better way of displaying these items or doing something more useful with them perhaps. But for the purpose of this recipe, we are simply going to display them in the console.

func reverseOfString(string: NSString) -> NSString{

  var result = ""
  var characters = [Character]()

  for character in string as String{
    characters.append(character)
  }

  for character in characters.reverse(){
    result += "\(character)"
  }

  return result

}

override func performActivity() {

  var reversedStrings = ""

  for string in activityItems{
    reversedStrings += reverseOfString(string) + "\n"
  }

  /* Do whatever you need to do with all these
  reversed strings */
  println(reversedStrings)

}

We are done with the implementation of our activity class. Now let’s go to our view controller’s implementation file and display the activity view controller with our custom activity in the list:

import UIKit

class ViewController: UIViewController {

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

    let itemsToShare = [
      "Item 1" as NSString,
      "Item 2" as NSString,
      "Item 3" as NSString
    ]

    let activityController = UIActivityViewController(
      activityItems: itemsToShare,
      applicationActivities:[StringReverserActivity()])

    presentViewController(activityController, animated: true, completion: nil)

  }

}

When the app runs for the first time, you will see something similar to Figure 1-30 on the screen.

Our custom Reverse String activity is showing in the list of available activities
Figure 1-30. Our custom Reverse String activity is showing in the list of available activities

See Also

Recipe 1.12

1.14. Displaying an Image on a Navigation Bar

Problem

You want to display an image instead of text as the title of the current view controller on the navigation controller.

Solution

Use the titleView property of the view controller’s navigation item:

import UIKit

class ViewController: UIViewController {

  override func viewDidLoad() {
    super.viewDidLoad()

    /* Create an Image View to replace the Title View */
    let imageView = UIImageView(
      frame: CGRect(x: 0, y: 0, width: 100, height: 40))

    imageView.contentMode = .ScaleAspectFit

    let image = UIImage(named:"Logo")

    imageView.image = image

    /* Set the Title View */
    navigationItem.titleView = imageView

  }

}

Note

The preceding code must be executed in a view controller that is placed inside a navigation controller.

I have already loaded an image into my project’s assets group and named it “Logo.” When you run this app with the given code snippet, you’ll see something similar to that shown in Figure 1-31.

An image view in our navigation bar
Figure 1-31. An image view in our navigation bar

Discussion

The navigation item of every view controller can display two types of content in the title area of the view controller to which it is assigned:

  • Simple text

  • A view

If you want to use text, you can use the title property of the navigation item. However, if you want more control over the title or if you simply want to display an image or any other view on the navigation bar, you can use the titleView property of the navigation item of a view controller. You can assign any object that is a subclass of the UIView class. In our example, we created an image view and assigned an image to it. Then we displayed it as the title of the current view controller on the navigation controller.

The titleView property of the navigation bar is just a simple view, but Apple recommends that you limit the height of this view to no more than 128 points. So think about it in terms of the image. If you are loading an image that is 128 pixels in height, that will translate to 64 points on a Retina display, so in that case you are fine. But if you are loading an image that is 300 pixels in height, on a Retina display, that will translate to 150 points in height, so you’ll be well over the 128-point limit that Apple recommends for the title bar view height. To remedy this situation, you need to ensure that your title view is never taller than 128 points height-wise and set the view’s content mode to fill the view, instead of stretching the view to fit the content. This can be done by setting the contentMode property of your title bar view to UIViewContentModeScaleAspectFit.

1.15. Adding Buttons to Navigation Bars Using UIBarButtonItem

Problem

You want to add buttons to a navigation bar.

Solution

Use the UIBarButtonItem class.

Discussion

A navigation bar can contain different items. Buttons are often displayed on the left and the right sides. These buttons are of class UIBarButtonItem and can take many different shapes and forms. Let’s have a look at an example in Figure 1-32.

Different buttons displayed on a navigation bar
Figure 1-32. Different buttons displayed on a navigation bar

Navigation bars are of class UINavigationBar and can be created at any time and added to any view. Just look at all the different buttons with different shapes that have been added to the navigation bar in Figure 1-32. The ones on the top right have up and down arrows, and the one on the top left has an arrow pointing to the left. We will have a look at creating some of these buttons in this recipe.

In order to create a navigation button, we must do the following:

  1. Create an instance of UIBarButtonItem.

  2. Add that button to the navigation bar of a view controller using the view controller’s navigationItem property. The navigationItem property allows us to interact with the navigation bar. This property has two properties: rightBarButtonItem and leftBarButtonItem. Both of these properties are of type UIBarButtonItem.

Let’s have a look at an example where we add a button to the right side of our navigation bar. In this button, we will display the text “Add”:

import UIKit

class ViewController: UIViewController {

  func performAdd(sender: UIBarButtonItem){
    println("Add method got called")
  }

  override func viewDidLoad() {
    super.viewDidLoad()

    navigationItem.rightBarButtonItem = UIBarButtonItem(
      title: "Add",
      style: .Plain,
      target: self,
      action: "performAdd:")

  }

}

Now when we run our app we will see something similar to Figure 1-33.

A navigation button added to a navigation bar
Figure 1-33. A navigation button added to a navigation bar

That was easy. But if you are an iOS user, you have probably noticed that the system apps that come preconfigured on iOS have a different Add button. Figure 1-34 shows an example in the Alarm section of the Clock app on the iPhone (notice the + button on the top right of the navigation bar).

The proper way of creating an Add button
Figure 1-34. The proper way of creating an Add button

It turns out that the iOS SDK allows us to create system buttons on the navigation bar. We do that by using the initWithBarButtonSystemItem:target:action: constructor of the UIBarButtonItem class:

import UIKit

class ViewController: UIViewController {

  func performAdd(sender: UIBarButtonItem){
    println("Add method got called")
  }

  override func viewDidLoad() {
    super.viewDidLoad()

    navigationItem.rightBarButtonItem = UIBarButtonItem(
      barButtonSystemItem: .Add,
      target: self,
      action: "performAdd:")

  }

}

And the results are exactly what we were looking for (Figure 1-35).

A system Add button
Figure 1-35. A system Add button

The first parameter of the initWithBarButtonSystemItem:target:action: constructor method of the navigation button can have any of the values listed in the UIBarButtonSystemItem enumeration.

One of the really great constructors of the UIBarButtonItem class is the initWithCustomView: method. As its parameter, this method accepts any view. This means we can even add a UISwitch (see Recipe 1.7) as a button on the navigation bar. This won’t look very good, but let’s give it a try:

import UIKit

class ViewController: UIViewController {

  func switchIsChanged(sender: UISwitch){
    if sender.on{
      println("Switch is on")
    } else {
      println("Switch is off")
    }
  }

  override func viewDidLoad() {
    super.viewDidLoad()

    let simpleSwitch = UISwitch()
    simpleSwitch.on = true

    simpleSwitch.addTarget(self,
      action: "switchIsChanged:",
      forControlEvents: .ValueChanged)

    self.navigationItem.rightBarButtonItem =
      UIBarButtonItem(customView: simpleSwitch)

  }

}

And Figure 1-36 shows the results.

A switch added to a navigation bar
Figure 1-36. A switch added to a navigation bar

You can create pretty amazing navigation bar buttons. Just take a look at what Apple has done with the up and down arrows on the top-right corner of Figure 1-32. Let’s do the same thing, shall we? Well, it looks like the button actually contains a segmented control (see Recipe 1.11). So we should create a segmented control with two segments, add it to a navigation button, and finally place the navigation button on the navigation bar. Let’s get started:

import UIKit

class ViewController: UIViewController {

  let items = ["Up", "Down"]

  func segmentedControlTapped(sender: UISegmentedControl){

    if sender.selectedSegmentIndex < items.count{
      println(items[sender.selectedSegmentIndex])
    } else {
      println("Unknown button is pressed")
    }

  }

  override func viewDidLoad() {
    super.viewDidLoad()

    let segmentedControl = UISegmentedControl(items: items)
    segmentedControl.momentary = true

    segmentedControl.addTarget(self,
      action: "segmentedControlTapped:",
      forControlEvents: .ValueChanged)

    navigationItem.rightBarButtonItem =
      UIBarButtonItem(customView: segmentedControl)

  }

}

And Figure 1-37 shows what the output looks like.

A segmented control inside a navigation button
Figure 1-37. A segmented control inside a navigation button

The navigationItem of every view controller also has two very interesting methods:

setRightBarButtonItem:animated:

Sets the navigation bar’s right button.

setLeftBarButtonItem:animated:

Sets the navigation bar’s left button.

Both methods allow you to specify whether you want the placement to be animated. Pass the value of true to the animated parameter if you want the placement to be animated. Here is an example:

let rightBarButton =
UIBarButtonItem(customView:segmentedControl)

navigationItem.setRightBarButtonItem(rightBarButton, animated: true)

1.16. Accepting User Text Input with UITextField

Problem

You want to accept text input in your user interface.

Solution

Use the UITextField class.

Discussion

A text field is very much like a label in that it can display text, but a text field can also accept text entry at runtime.

Note

A text field allows only a single line of text to be input/displayed. As a result, the default height of a text field is system defined. In Interface Builder, this height cannot be modified, but if you are creating your text field in code, you can change the text field’s height. A change in height, though, will not change the number of lines you can render in a text field, which is always 1.

Let’s start to define our text field:

import UIKit

class ViewController: UIViewController {

  var textField: UITextField!

}

And then let’s create the text field:

import UIKit

class ViewController: UIViewController {

  var textField: UITextField!

  override func viewDidLoad() {
    super.viewDidLoad()

    textField = UITextField(frame: CGRect(x: 0, y: 0, width: 200, height: 31))

    textField.borderStyle = .RoundedRect

    textField.contentVerticalAlignment = .Center

    textField.textAlignment = .Center

    textField.text = "Sir Richard Branson"
    textField.center = view.center
    view.addSubview(textField)

  }

}

Before looking at the details of the code, let’s first have a look at the results (Figure 1-38).

A simple text field with center-aligned text
Figure 1-38. A simple text field with center-aligned text

In order to create this text field, we used various properties of UITextField.

borderStyle

This property is of type UITextBorderStyle and specifies how the text field should render its borders.

contentVerticalAlignment

This value is of type UIControlContentVerticalAlignment and tells the text field how the text should appear, vertically, in the boundaries of the control. If we didn’t center the text vertically, it would appear on the top-left corner of the text field by default.

textAlignment

This property is of type NSTextAlignment and specifies the horizontal alignment of the text in a text field. In this example, we centered the text horizontally.

text

This is a read/write property: you can both read from it and write to it. Reading from it will return the text field’s current text, and writing to it will set the text field’s text to the value that you specify.

A text field sends delegate messages to its delegate object. These messages get sent, for instance, when the user starts editing the text inside a text field, when the user enters any character into the text field (changing its contents in any way), and when the user finishes editing the field (by leaving the field). To get notified of these events, set the delegate property of the text field to your object. The delegate of a text field must conform to the UITextFieldDelegate protocol, so let’s first take care of this:

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

  <# the rest of your code goes here #>

}

Hold down the Command key on your computer and click the UITextFieldDelegate protocol in Xcode. You will see all the methods that this protocol gives you control over. Here are those methods with descriptions of when they get called:

textFieldShouldBeginEditing:

A method that returns a BOOL telling the text field (the parameter to this method) whether it should start getting edited by the user or not. Return false if you don’t want the user to edit your text field. This method gets fired as soon as the user taps on the text field with the goal of editing its content (assuming the text field allows editing).

textFieldDidBeginEditing:

Gets called when the text field starts to get edited by the user. This method gets called when the user has already tapped on the text field and the textFieldShouldBeginEditing: delegate method of the text field returned true, telling the text field it is OK for the user to edit the content of the text field.

textFieldShouldEndEditing:

Returns a BOOL telling the text field whether it should end its current editing session or not. This method gets called when the user is about to leave the text field or the first responder is switching to another data entry field. If you return false from this method, the user will not be able to switch to another text entry field, and the keyboard will stay on the screen.

textFieldDidEndEditing:

Gets called when the editing session of the text field ends. This happens when the user decides to edit some other data entry field or uses a button provided by the supplier of the app to dismiss the keyboard shown for the text field.

textField:shouldChangeCharactersInRange:replacementString:

Gets called whenever the text inside the text field is modified. The return value of this method is a Boolean. If you return true, you say that you allow the text to be changed. If you return false, the change in the text of the text field will not be confirmed and will not happen.

textFieldShouldClear:

Each text field has a clear button that is usually a circular X button. When the user presses this button, the contents of the text field will automatically get erased. We need to manually enable the clear button, though. If you have enabled the clear button and you return false to this method, that gives the user the impression that your app isn’t working, so make sure you know what you are doing. It is a very poor user experience if the user sees a clear button and presses it but doesn’t see the text in the text field get erased.

textFieldShouldReturn:

Gets called when the user has pressed the Return/Enter key on the keyboard, trying to dismiss the keyboard. You should assign the text field as the first responder in this method.

Let’s mix this recipe with Recipe 1.4 and create a dynamic text label under our text field. We’ll also display the total number of characters entered in our text field in the label.

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

  var textField: UITextField!
  var label: UILabel!

}

We skip implementing many of the UITextFieldDelegate methods, because we don’t need all of them in this example:

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

  var textField: UITextField!
  var label: UILabel!

  func calculateAndDisplayTextFieldLengthWithText(text: String){

    var characterOrCharacters = "Character"
    if countElements(text) != 1{
      characterOrCharacters += "s"
    }

    let stringLength = countElements(text)

    label.text = "\(stringLength) \(characterOrCharacters)"

  }


  func textField(paramTextField: UITextField,
    shouldChangeCharactersInRange range: NSRange,
    replacementString string: String) -> Bool{

      let text = paramTextField.text as NSString

      let wholeText =
      text.stringByReplacingCharactersInRange(
        range, withString: string)

      calculateAndDisplayTextFieldLengthWithText(wholeText)

      return true

  }

  func textFieldShouldReturn(paramTextField: UITextField) -> Bool{
    paramTextField.resignFirstResponder()
    return true
  }

  override func viewDidLoad() {
    super.viewDidLoad()

    textField = UITextField(frame:
      CGRect(x: 38, y: 30, width: 220, height: 31))

    textField.delegate = self
    textField.borderStyle = .RoundedRect
    textField.contentVerticalAlignment = .Center
    textField.textAlignment = .Center
    textField.text = "Sir Richard Branson"
    view.addSubview(textField)

    label = UILabel(frame: CGRect(x: 38, y: 61, width: 220, height: 31))
    view.addSubview(label)
    calculateAndDisplayTextFieldLengthWithText(textField.text)

  }

}

One important calculation we are doing takes place in the textField:shouldChangeCharactersInRange:replacementString: method. There, we declare and use a variable called wholeText. When this method gets called, the replacementString parameter specifies the string that the user has entered into the text field. You might be thinking that the user can enter only one character at a time, so why can’t this field be a char? But don’t forget that the user can paste a whole chunk of text into a text field, so this parameter needs to be a string. The shouldChangeCharactersInRange parameter specifies where, in terms of location inside the text field’s text, the user is entering the text. So using these two parameters, we will create a string that first reads the whole text inside the text field and then uses the given range to place the new text inside the old text. With this, we will come up with the text that will appear in the text field after the textField:shouldChangeCharactersInRange:replacementString: method returns true. Figure 1-39 shows how our app looks when it gets run on the simulator.

Responding to delegate messages of a text field
Figure 1-39. Responding to delegate messages of a text field

In addition to displaying text, a text field can also display a placeholder. A placeholder is the text displayed before the user has entered any text in the text field, while the text field’s text property is empty. This can be any string that you wish, and setting it will help give the user an indication as to what this text field is for. Many use this placeholder to tell the user what type of value she can enter in that text field. You can use the placeholder property of the text field to set or get the current placeholder. Here is an example:

import UIKit

class ViewController: UIViewController {

  var textField: UITextField

  override func viewDidLoad() {
    super.viewDidLoad()

    textField = UITextField(frame:
      CGRect(x: 38, y: 30, width: 220, height: 31))

    textField.borderStyle = .RoundedRect
    textField.contentVerticalAlignment = .Center
    textField.textAlignment = .Center
    textField.placeholder = "Enter your text here..."
    view.addSubview(textField)

  }

}

The results are shown in Figure 1-40.

A placeholder is shown when the user has not entered any text in a text field
Figure 1-40. A placeholder is shown when the user has not entered any text in a text field

Text fields have two really neat properties called leftView and rightView. These two properties are of type UIView and are read/write. They appear, as their names imply, on the left and the right side of a text field if you assign a view to them. One place you might use a left view, for instance, is if you are displaying a currency text field where you would like to display the currency of the user’s current country in the left view as a UILabel. Here is how we can accomplish that:

let currencyLabel = UILabel(frame: CGRectZero)
currencyLabel.text = NSNumberFormatter().currencySymbol
currencyLabel.font = theTextField.font
currencyLabel.textAlignment = .Right
currencyLabel.sizeToFit()
/* Give more width to the label so that it aligns properly on the
  text field's left view when the label's text itself is right aligned
*/
currencyLabel.frame.size.width += 10
theTextField.leftView = currencyLabel
theTextField.leftViewMode = .Always
view.addSubview(theTextField)

If we simply assign a view to the leftView or to the rightView properties of a text field, those views will not appear automatically by default. When they show up on the screen depends on the mode that governs their appearance, and you can control that mode using the leftViewMode and rightViewMode properties, respectively. These modes are of type UITextFieldViewMode.

So if, for instance, you set the left view mode to UITextFieldViewModeWhileEditing and assign a value to it, it will appear only while the user is editing the text field. Conversely, if you set this value to UITextFieldViewModeUnlessEditing, the left view will appear only while the user is not editing the text field. As soon as editing starts, the left view will disappear. Let’s have a look at our code now in the simulator (Figure 1-41).

A text field with a left view
Figure 1-41. A text field with a left view

See Also

Recipe 1.4

1.17. Displaying Long Lines of Text with UITextView

Problem

You want to display multiple lines of text in your UI inside one scrollable view.

Solution

Use the UITextView class.

Discussion

The UITextView class can display multiple lines of text and contain scrollable content, meaning that if the contents run off the boundaries of the text view, the text view’s internal components allow the user to scroll the text up and down to see different parts of the text. An example of a text view is shown in Figure 1-42.

A text view is displayed on the screen
Figure 1-42. A text view is displayed on the screen

Let’s create a text view and see how it works. We start off by declaring the text view in our view controller:

import UIKit

class ViewController: UIViewController {

  var textView: UITextView?

}

Now it’s time to create the text view itself. We will make the text view as big as the view controller’s view:

import UIKit

class ViewController: UIViewController {

  var textView: UITextView?

  override func viewDidLoad() {
    super.viewDidLoad()

    textView = UITextView(frame: view.bounds)
    if let theTextView = textView{
      theTextView.text = "Some text goes here..."

      theTextView.contentInset =
        UIEdgeInsets(top: 10, left: 0, bottom: 0, right: 0)

      theTextView.font = UIFont.systemFontOfSize(16)
      view.addSubview(theTextView)
    }

  }

}

Now let’s run the app and see how it looks (Figure 1-43).

A text view consuming the entire boundary of the screen
Figure 1-43. A text view consuming the entire boundary of the screen

If you tap on the text field, you will notice a keyboard pop up from the bottom of the screen, concealing almost half the entire area of the text view. That means if the user starts typing text and gets to the middle of the text view, the rest of the text that she types will not be visible to her.

To remedy this, we have to listen for certain notifications:

UIKeyboardWillShowNotification

Gets sent by the system whenever the keyboard is brought up on the screen for any component, be it a text field, a text view, etc.

UIKeyboardDidShowNotification

Gets sent by the system when the keyboard has already been displayed.

UIKeyboardWillHideNotification

Gets sent by the system when the keyboard is about to hide.

UIKeyboardDidHideNotification

Gets sent by the system when the keyboard is now fully hidden.

Note

The keyboard notifications contain a dictionary, accessible through the userInfo property, that specifies the boundaries of the keyboard on the screen. This property is of type NSDictionary. One of the keys in this dictionary is UIKeyboardFrameEndUserInfoKey, which contains an object of type NSValue that itself contains the rectangular boundaries of the keyboard when it is fully shown. This rectangular area is denoted with a CGRect.

So our strategy is to find out when the keyboard is getting displayed and then somehow resize our text view. For this, we will use the contentInset property of UITextView to specify the margins of contents in the text view from top, left, bottom, and right:

import UIKit

class ViewController: UIViewController {

  var textView: UITextView?

  let defaultContentInset =
  UIEdgeInsets(top: 10, left: 0, bottom: 0, right: 0)

  func handleKeyboardDidShow (notification: NSNotification){

    /* Get the frame of the keyboard */
    let keyboardRectAsObject =
    notification.userInfo![UIKeyboardFrameEndUserInfoKey] as NSValue

    /* Place it in a CGRect */
    var keyboardRect = CGRectZero

    keyboardRectAsObject.getValue(&keyboardRect)

    /* Give a bottom margin to our text view that makes it
    reach to the top of the keyboard */
    textView!.contentInset =
      UIEdgeInsets(top: defaultContentInset.top,
        left: 0, bottom: keyboardRect.height, right: 0)
  }

  func handleKeyboardWillHide(notification: NSNotification){
    textView!.contentInset = defaultContentInset
  }

  override func viewDidLoad() {
    super.viewDidLoad()

    textView = UITextView(frame: view.bounds)
    if let theTextView = textView{
      theTextView.text = "Some text goes here..."
      theTextView.font = UIFont.systemFontOfSize(16)
      theTextView.contentInset = defaultContentInset

      view.addSubview(theTextView)

      NSNotificationCenter.defaultCenter().addObserver(
        self,
        selector: "handleKeyboardDidShow:",
        name: UIKeyboardDidShowNotification,
        object: nil)


      NSNotificationCenter.defaultCenter().addObserver(
        self,
        selector: "handleKeyboardWillHide:",
        name: UIKeyboardWillHideNotification,
        object: nil)

    }

  }

  deinit{
    NSNotificationCenter.defaultCenter().removeObserver(self)
  }

}

In this code, we start looking for keyboard notifications in viewWillAppear: and we stop listening to keyboard notifications in viewWillDisappear:. Removing your view controller as the listener is important, because when your view controller is no longer displayed, you probably don’t want to receive keyboard notifications fired by any other view controller. There may be times when a view controller in the background needs to receive notifications, but these are rare, and you must normally make sure to stop listening for notifications in viewWillDisappear:. I’ve seen many programmers break their apps by not taking care of this simple logic.

Note

If you intend to change your UI structure when the keyboard gets displayed and when the keyboard is dismissed, the only method that you can rely on is to use the keyboard notifications. Delegate messages of UITextField get fired when the text field is getting edited, whether there is a soft keyboard on the screen or not. Remember, a user can have a Bluetooth keyboard connected to his iOS device and use it to edit the content of text fields and any other data entry in your apps. In the case of a Bluetooth keyboard, no soft keyboard will be displayed on the screen—and if you change your UI when your text fields start to get edited, you might unnecessarily change the UI while the Bluetooth keyboard user is editing text.

Now, if the user tries to enter some text into the text view, the keyboard will pop up, and we take the height of the keyboard and assign that value as the bottom margin of the contents inside the text view. This makes our text view’s contents smaller in size and allows the user to enter as much text as she wishes without the keyboard blocking her view.

1.18. Creating Scrollable Content with UIScrollView

Problem

You have content that needs to get displayed on the screen, but it requires more real estate than what the device’s screen allows for.

Solution

Use the UIScrollView class.

Discussion

Scroll views are one of the features that make iOS a really neat operating system. They are practically everywhere. You’ve been to the Clock or the Contacts apps, haven’t you? Have you seen how the content can be scrolled up and down? Well, that’s the magic of scroll views.

There really is one basic concept you need to learn about scroll views: the content size, which lets the scroll view conform to the size of what it’s displaying. The content size is a value of type CGSize that specifies the width and the height of the contents of a scroll view. A scroll view, as its name implies, is a subclass of UIView, so you can simply add your views to a scroll view using its addSubview: method. However, you need to make sure that the scroll view’s content size is set properly; otherwise, the contents inside the scroll view won’t scroll.

As an example, let’s find a big image and load it to an image view. I will add the same image that I used in Recipe 1.3: Safari’s icon. I will add it to an image view and place it in a scroll view. Then I will use the contentSize of the scroll view to make sure this content size is equal to the size of the image (width and height). First, let’s define our image view and the scroll view:

import UIKit

class ViewController: UIViewController {
  var imageView: UIImageView!
  var scrollView: UIScrollView!
  let image = UIImage(named: "Safari")
}

And let’s place the image view inside the scroll view:

import UIKit

class ViewController: UIViewController {
  var imageView: UIImageView!
  var scrollView: UIScrollView!
  let image = UIImage(named: "Safari")

  override func viewDidLoad() {
    super.viewDidLoad()

    imageView = UIImageView(image: image)
    scrollView = UIScrollView(frame: view.bounds)

    scrollView.addSubview(imageView)
    scrollView.contentSize = imageView.bounds.size
    view.addSubview(scrollView)
    
  }

}

If you now load up the app in iOS Simulator, you will see that you can scroll the image horizontally and vertically. The challenge here, of course, is to provide an image that is bigger than the screen’s boundaries. For example, if you provide an image that is 20×20 pixels, the scroll view won’t be of much use to you. In fact, it would be wrong to place such an image into a scroll view, as the scroll view would practically be useless in that scenario. There would be nothing to scroll because the image is smaller than the screen size.

One of the handy features of UIScrollView is support for delegation, so that it can report really important events to the app through a delegate. A delegate for a scroll view must conform to the UIScrollViewDelegate protocol. Here are some of the methods defined in this protocol:

scrollViewDidScroll:

Gets called whenever the contents of a scroll view get scrolled.

scrollViewWillBeginDecelerating:

Gets called when the user scrolls the contents of a scroll view and lifts his finger off the screen as the scroll view scrolls.

scrollViewDidEndDecelerating:

Gets called when the scroll view has finished scrolling its contents.

scrollViewDidEndDragging:willDecelerate:

Gets called when the user finishes dragging the contents of the scroll view. This method is very similar to the scrollViewDidEndDecelerating: method, but you need to bear in mind that the user can drag the contents of a scroll view without scrolling the contents. She can simply put her finger on the content, move her finger to any location on the screen, and lift her finger without giving the contents any momentum to move. This is dragging as opposed to scrolling. Scrolling is similar to dragging, but the user will give momentum to the contents’ movement by lifting her finger off the screen while the content is being dragged around, and not waiting for the content to stop before lifting her finger off the screen. Dragging is comparable to holding down the accelerator in a car or pedaling on a bicycle, whereas scrolling is comparable to coasting in a car or on a bicycle.

So let’s add some fun to our previous app. Now the goal is to set the alpha level of the image inside our image view to 0.50f (half transparent) when the user starts to scroll the scroll view and set this alpha back to 1.0f (opaque) when the user finishes scrolling. Let’s begin by conforming to the UIScrollViewDelegate protocol:

import UIKit

class ViewController: UIViewController, UIScrollViewDelegate {
  var imageView: UIImageView!
  var scrollView: UIScrollView!
  let image = UIImage(named: "Safari")
}

Then let’s implement this functionality:

func scrollViewDidScroll(scrollView: UIScrollView){
/* Gets called when user scrolls or drags */
  scrollView.alpha = 0.50
}

func scrollViewDidEndDecelerating(scrollView: UIScrollView){
/* Gets called only after scrolling */
  scrollView.alpha = 1
}

func scrollViewDidEndDragging(scrollView: UIScrollView!,
  willDecelerate decelerate: Bool){
    scrollView.alpha = 1
}

override func viewDidLoad() {
  super.viewDidLoad()

  imageView = UIImageView(image: image)
  scrollView = UIScrollView(frame: view.bounds)

  if let theScrollView = scrollView{
    theScrollView.addSubview(imageView!)
    theScrollView.contentSize = imageView!.bounds.size
    theScrollView.delegate = self
    view.addSubview(theScrollView)
  }

}

As you might have noticed, scroll views have indicators. An indicator is the little tracking line that appears on the sides of a scroll view when its contents are getting scrolled and moved.

Indicators simply show the user where the current view is in relation to the content (top, halfway down, etc.). You can control what the indicators look like by changing the value of the indicatorStyle property. For instance, here I have changed the indicator style of my scroll view to white:

theScrollView.indicatorStyle = .White

1.19. Loading Web Pages with WebKit

Problem

You want to display web pages to your user and be able to customize the user’s interaction and experience with the web pages.

Solution

Use a blend of the following classes and protocols to load web pages to your UI:

WKWebView

This is a web view that can load web contents. We will need to create an instance of NSURL to contain the URL that we want to load and then place that URL inside an instance of NSURLRequest that will encapsulate our request to the web view. Once the request is ready, we will ask the web view to load it.

WKPreferences

This class will encapsulate our preferences for rendering web views. For instance, you can specify in your preferences that you do not want JavaScript to be loaded as part of loading the web page. When you are done creating your preferences, you should place them inside a web view configuration object.

WKWebViewConfiguration

After the preferences are created, you must place them inside a configuration object and pass the configuration to the web view.

WKNavigationDelegate

Whatever instance is assigned to the navigationDelegate property of your web view must confirm to this protocol. Using this protocol, you can, for instance, detect when the user taps on a link in the web view and then either accept or reject that request. There are many other things that you can do with the navigation delegate, as we shall soon see.

Let’s start off by conforming to the WKNavigationDelegate protocol:

class ViewController: UIViewController, WKNavigationDelegate

Then we define our web view as a property of our controller:

var webView: WKWebView?

After that, we create our web view preferences, followed by the configuration objects, stating that we don’t want our web view to process any JavaScript:

/* Create our preferences on how the web page should be loaded */
let preferences = WKPreferences()
preferences.javaScriptEnabled = false

/* Create a configuration for our preferences */
let configuration = WKWebViewConfiguration()
configuration.preferences = preferences

The next step is to create and configure the web view and add it to our view hierarchy:

/* Now instantiate the web view */
webView = WKWebView(frame: view.bounds, configuration: configuration)

if let theWebView = webView{
  /* Load a web page into our web view */
  let url = NSURL(string: "http://www.apple.com")
  let urlRequest = NSURLRequest(URL: url!)
  theWebView.loadRequest(urlRequest)
  theWebView.navigationDelegate = self
  view.addSubview(theWebView)

}

Our web view, depending on what page it is loading and which device it is loading the page on, may take a while to process our request. This calls for displaying the default system activity indicator to the user while the web view is processing the page for her. For that, we will implement two of the most important methods that are defined in the WKNavigationDelegate protocol, like so:

/* Start the network activity indicator when the web view is loading */
func webView(webView: WKWebView!,
  didStartProvisionalNavigation navigation: WKNavigation!){
    UIApplication.sharedApplication().networkActivityIndicatorVisible
      = true
}

/* Stop the network activity indicator when the loading finishes */
func webView(webView: WKWebView!,
  didFinishNavigation navigation: WKNavigation!){
    UIApplication.sharedApplication().networkActivityIndicatorVisible
      = false
}

The webView:didStartProvisionalNavigation: method gets called on the navigation delegate of your web view whenever a navigation has been provisioned to happen, before the web view asks you whether it is OK to make that navigation. We will give the answer to that question later. But for now, we see that the web view lets us know that a navigation is about to happen. The webView:didFinishNavigation: method of the navigation delegate gets called on our view controller when the web view has finished doing whatever navigation was requested of it. Here, we will use the opportunity to hide the network activity indicator that was previously displayed to the user.

The next thing we have to look at is the webView:decidePolicyForNavigationAction:decisionHandler: method of our web view’s navigation delegate, which gets called whenever a navigation of any sort is about to happen in the web view. The navigationAction parameter will give you more information about what type of navigation is about to happen. If you inspect the navigationType property of the navigationAction parameter, you will be able to tell between the various types of navigations that can occur on a web view. One sort of navigation is when the user taps on a link—any link! The other is when the user submits a form for processing on a server or (for instance) when the user reloads a page.

We are now going to take advantage of the presence of this method on the navigation delegate of our web view and block the user from tapping on any link in the web page that we are displaying. Whenever she attempts to tap on a link, we will display an alert informing her that she is not allowed to tap on a link inside our application. This is for demonstration purposes, to give an example of how you can tap into the power of WebKit to control how your users interact with a web view. You may not necessarily be interested in blocking your user from tapping on various links on a web page.

/* Do not allow links to be tapped */
func webView(webView: WKWebView!,
  decidePolicyForNavigationAction navigationAction: WKNavigationAction!,
  decisionHandler: ((WKNavigationActionPolicy) -> Void)!){

    /* Do not allow links to be tapped */
    if navigationAction.navigationType == .LinkActivated{

      decisionHandler(.Cancel)

      let alertController = UIAlertController(
        title: "Action not allowed",
        message: "Tapping on links is not allowed. Sorry!",
        preferredStyle: .Alert)

      alertController.addAction(UIAlertAction(
        title: "OK", style: .Default, handler: nil))

      presentViewController(alertController,
        animated: true,
        completion: nil)

      return

    }

    decisionHandler(.Allow)

}

Discussion

One of the really powerful frameworks in the iOS SDK is the WebKit framework. Using this framework, you can tap into many preferences and settings that Apple has enabled us to take control of. For instance, you can detect when the user wants to go back to the previous page or go forward to the next page. After you detect the type of event, you can then choose whether to allow it or to reject it.

As you saw earlier in the Solution section of this recipe, you can instantiate an instance of WKWebView using its constructor. This method takes the frame for the web view and the configuration, which must be of type WKWebViewConfiguration. You can leave this configuration empty, or create a proper instance of the aforementioned class and create your configuration as you will. Configurations for WebKit web views allow you to customize how users are able to interact with the web view. For instance, you can decide what happens if the user taps on a link that opens a new window.

Another handy navigation method that has been defined in the WKNavigationDelegate protocol is the webView:decidePolicyForNavigationResponse:decisionHandler: method. This method gets called when the navigation of a certain request on the web view has been finished and the results are now known by the web view. For instance, if the user taps on a link, the web view won’t know what the content will be and what type it will have, whether it will be a media file, etc. until the content is loaded. But after the request is sent to the server and the response has been received, the aforementioned method gets called on the navigation delegate of the web view, informing it of content that is about to be loaded on the web view. You can implement this method to understand what content your web view is loading, such as the MIME type of the content. You can also allow or cancel the loading of these contents into your web view.

See Also

Recipe 1.20

1.20. Loading Web Pages with UIWebView

Problem

You want to load a web page dynamically right inside your iOS app.

Solution

Use the UIWebView class.

Discussion

A web view is what the Safari browser uses on iOS to load web content. You have the whole power of Safari in your iOS apps through the UIWebView class. All you have to do is place a web view on your UI and use one of its loading methods:

loadData:MIMEType:textEncodingName:baseURL:

Loads an instance of NSData into the web view.

loadHTMLString:baseURL:

Loads an instance of NSString into the web view. The string should be valid HTML, or in other words, something that a web browser can render.

loadRequest:

Loads an instance of NSURLRequest. This is useful when you want to load the contents of a remote URL into a web view inside your application.

Let’s see an example. I would like to load the string iOS Programming into the web view. To prove things are working as expected and that our web view is capable of rendering rich text, I will go ahead and make the Programming part bold while leaving the rest of the text intact:

import UIKit

class ViewController: UIViewController {

  override func viewDidLoad() {
    super.viewDidLoad()

    let webView = UIWebView(frame: view.bounds)
    let htmlString = "<br/>iOS <strong>Programming</strong>"
    webView.loadHTMLString(htmlString, baseURL: nil)
    view.addSubview(webView)

  }

}

Another way to use a web view is to load a remote URL into it. For this purpose, we can use the loadRequest: method. Let’s go ahead and look at an example where we will load Apple’s main page into a web view in our iOS app:

import UIKit

class ViewController: UIViewController {

  /* Hide the status bar to give all the screen real estate */
  override func prefersStatusBarHidden() -> Bool {
    return true
  }

  override func viewDidLoad() {
    super.viewDidLoad()

    let webView = UIWebView(frame: view.bounds)
    webView.scalesPageToFit = true
    view.addSubview(webView)

    let url = NSURL(string: "http://www.apple.com")
    let request = NSURLRequest(URL: url!)

    webView.loadRequest(request)

    view.addSubview(webView)

  }

}

It might take quite a while for a web view to load the contents that you pass to it. You might have noticed that when loading content in Safari, you get a little activity indicator in the top-left corner of the screen telling you that the device is busy loading the contents. Figure 1-44 shows an example.

A progress bar indicating a loading process
Figure 1-44. A progress bar indicating a loading process

iOS accomplishes this through delegation. We will subscribe as the delegate of a web view, and the web view will notify us when it starts to load content. When the content is fully loaded, we get a message from the web view informing us about this. We do this through the delegate property of the web view. A delegate of a web view must conform to the UIWebViewDelegate protocol.

Let’s go ahead and implement the little activity indicator in our view controller. Please bear in mind that the activity indicator is already a part of the application and we don’t have to create it. We can control it using the setNetworkActivityIndicatorVisible: method of UIApplication. So let’s start:

import UIKit

class ViewController: UIViewController, UIWebViewDelegate

Then do the implementation. Here we will use three of the methods declared in the UIWebViewDelegate protocol:

webViewDidStartLoad:

This method gets called as soon as the web view starts loading content.

webViewDidFinishLoad:

This method gets called as soon as the web view finishes loading content.

webView:didFailLoadWithError:

This method gets called when the web view stops loading content, for instance because of an error or a broken network connection.

func webViewDidStartLoad(webView: UIWebView!){
  UIApplication.sharedApplication().networkActivityIndicatorVisible = true
}

func webViewDidFinishLoad(webView: UIWebView!){
  UIApplication.sharedApplication().networkActivityIndicatorVisible = false
}

func webView(webView: UIWebView!, didFailLoadWithError error: NSError!){
  UIApplication.sharedApplication().networkActivityIndicatorVisible = false
}

override func viewDidLoad() {
  super.viewDidLoad()

  /* Render the web view under the status bar */
  var frame = view.bounds
  frame.origin.y = UIApplication.sharedApplication().statusBarFrame.height
  frame.size.height -= frame.origin.y

  let webView = UIWebView(frame: frame)
  webView.delegate = self
  webView.scalesPageToFit = true
  view.addSubview(webView)

  let url = NSURL(string: "http://www.apple.com")
  let request = NSURLRequest(URL: url!)

  webView.loadRequest(request)

  view.addSubview(webView)

}

1.21. Displaying Progress with UIProgressView

Problem

You want to display a progress bar on the screen depicting the progress of a certain task; for instance, the progress of downloading a file from a URL.

Solution

Instantiate a view of type UIProgressView and place it on another view.

Discussion

A progress view is what programmers generally call a progress bar. An example of a progress view is depicted in Figure 1-45.

A simple progress view
Figure 1-45. A simple progress view

Progress views are generally displayed to users to show them the progress of a task that has a well-defined starting and ending point. For instance, downloading 30 files is a well-defined task with a specific starting and ending point. This task obviously finishes when all 30 files have been downloaded. A progress view is an instance of UIProgressView and is initialized using the designated constructor of this class, the initWithProgressViewStyle: method. This method takes in the style of the progress bar to be created as a parameter. This parameter is of type UIProgressViewStyle and can therefore be one of the following values:

UIProgressViewStyleDefault

This is the default style of the progress view. An example of this is the progress view shown in Figure 1-45.

UIProgressViewStyleBar

This is similar to the UIProgressViewStyleDefault but is meant to be used for progress views that are to be added to a toolbar.

An instance of UIProgressView defines a property called progress (of type float). This property tells iOS how the bar inside the progress view should be rendered. This value must be in the range +0 to +1.0. If the value of +0 is given, the progress bar won’t appear to have started yet. A value of +1.0 shows progress of 100%. The progress depicted in Figure 1-45 is 0.5 (or 50%).

To get used to creating progress views, let’s create one similar to what we saw in Figure 1-45. Instantiate an object of type UIProgressView:

import UIKit

class ViewController: UIViewController {

  override func viewDidLoad() {
    super.viewDidLoad()

    let progressView = UIProgressView(progressViewStyle: .Bar)
    progressView.center = view.center
    progressView.progress = 1/2
    progressView.trackTintColor = UIColor.lightGrayColor()
    progressView.tintColor = UIColor.blueColor()
    view.addSubview(progressView)

  }

}

Obviously, creating a progress view is very straightforward. All you really need to do is display your progress correctly, because the progress property of a progress view should be in the range +0 to +1.0, which is a normalized value. So if you have 30 tasks to take care of and you have completed 20 of them so far, you need to assign the result of the following equation to the progress property of your progress view:

progressView.progress = 20.0/30.0

In this code, we are explicitly creating two double values, 20 and 30, and then dividing the 20 by 30 in order to create the resulting value as a double value as well. Because the progress property of the progress view itself is a floating point value, the result of this division will be created as a floating point value instead of an integer. So we don’t really have to worry about type casting or loss of precision in this division.

1.22. Creating a Provision Profile

Problem

You want to to set up a provision profile that you can use for your app development. You might also be interested in setting up an Ad Hoc or a distribution provision profile for deploying your app to an enterprise or series of testers, or for submitting your app to the App Store.

Solution

Follow these steps:

  1. Create a certificate request using Keychain Access.

  2. Create a development or a distribution certificate.

  3. Create an App ID that corresponds to your application.

  4. Create a provision profile that is linked to your certificate and your App ID, as is explained in the Discussion section of this recipe.

Discussion

Throughout the years that I’ve been working as an iOS engineer, I have seen many engineers who do not really understand the whole flow of creating provision profiles, or sometimes even what provision profiles are and what they do. That is not their fault. Apple has made this extremely difficult. Even though Xcode has tried to make this process easier, it still fails often and can’t really read the developer’s mind. For this reason, I’ve decided to explain the whole thing once and for all so that we are all on the same page.

Xcode’s flow for creating provision profiles looks deceptively simple and fun, but don’t be fooled. Xcode has a long way to go before it can really read your mind and create your profiles exactly how you would want them to be created. For this reason, Apple has kept the “Certificates, Identifiers & Profiles” section of the developer page updated regularly.

So let’s get cracking. In this recipe, we are going to focus on creating a provision profile for debugging our app. This is also called a development profile. It’s a profile that can only be used for development purposes and for debugging your apps on test devices.

The first thing that we need to do is to create a certificate signing request. Every profile is linked to a certificate and every certificate is linked to a private key. When you use Keychain (as we will soon see) to create a certificate signing request to send to Apple, your Keychain will create a private key for you and keep it ready for later. After we send our signing request to Apple, Apple will create a certificate for us. We will then need to import this certificate into our Keychain by double-clicking it. Once imported, Keychain will find the relevant private key that was generated before and will hook it up to the certificate so they become a pair.

So open up Keychain Access on your computer now, go to the Keychain Access menu, then Certificate Assistant, and choose “Request a Certificate From a Certificate Authority.” You will then be presented with a screen similar to that shown in Figure 1-46. Enter your email address and your full name, then choose the “Save to disk” option. When you are done, press the Continue button and save the resulting code signing request file to your desktop.

Creating a certificate signing request in Keychain Access
Figure 1-46. Creating a certificate signing request in Keychain Access

At this point, Keychain Access has already created a private key for you, but that private key is not yet associated with any certificates. That’s OK, though, because soon we are going to download a certificate from Apple and import it into Keychain.

Now you have a file named CertificateSigningRequest.certSigningRequest on your desktop. Navigate to the iOS Dev Center website and log in there if you are not already logged in. Then move to the “Certificates, Identifiers & Profiles” section of the portal and choose Certificates. On the lefthand side, under Certificates, choose Development as shown in Figure 1-47.

On our way to create a development certificate
Figure 1-47. On our way to create a development certificate

Now press the plus button (+) to create a new development certificate. You can only have one development certificate, so if you have already created one, you might decide to revoke it and create a new one. Simply select the old certificate and press the Revoke button as shown in Figure 1-48.

Revoking an old certificate
Figure 1-48. Revoking an old certificate

After pressing the plus (+) button, choose the option indicating that you want to create a development certificate and then move to the next step. You will be prompted to upload your code signing request file, which is currently saved on your desktop, to Apple’s web site. Then wait a few seconds. After the wait is over, you will be given the ability to download the certificate. Please do so, and after your download is complete, double-click on your certificate to import it into Keychain Access.

Now navigate to the certificates section of your Keychain, find the certificate that was imported, and note that it is associated with the private key that was generated for you when you created the certificate signing request earlier, as shown in Figure 1-49.

The certificate is associated with the private key
Figure 1-49. The certificate is associated with the private key

Now in the same Certificates, Identifiers & Profiles page of iOS Dev Center, move to the Identifiers section and then choose App IDs, as shown in Figure 1-50.

App IDs section of the portal
Figure 1-50. App IDs section of the portal

Press the plus (+) button to create a new App ID. In the App ID Description section, enter a description for your application. For instance, I have entered “iOS Cookbook App.” This name will appear only in this list and not in Xcode, so if you are working in a team where a lot of people have access to one portal, make sure that you give meaningful names to your apps.

In the App ID Prefix section, ensure the default value of “Team ID” is selected. In the App ID Suffix section, ensure that the Explicit App ID is selected and in the Bundle ID: section, enter a reverse-domain-style identifier for your bundle. This identifier needs to uniquely identify your application and you have to use the same identifier in the bundle-identifier section of your app’s plist. I have chosen the value of “com.pixolity.ios.cookbook.app” for this section.

Under the App Services section, choose all the services that you want your application to be able to use. For the purpose of this recipe, I have chosen every item in this list so that my test application will be able to take advantage of all these functionalities should I need them, but you can be more selective and choose only the items that make the most sense to you and your app. After you are done, press the Continue button.

Now you are on the Confirm your App ID page. Simply review your settings for your App ID and press the Submit button. When you are done, your App ID is ready. Bear in mind that an App ID is not something you can download or import. It is just an identifier for your app that will be associated with your provision profile in the portal.

Before you move on to creating your profile, you might want to register a few devices on which your app is able to run. You can do so by navigating to the All item under the Devices section of the portal. Now press the plus (+) button to add a new device. Enter a descriptive name for your device and the UDID of your device. You can find the UDID of the device by connecting it to your computer and then looking at the UDID in iTunes. Alternatively, if the device doesn’t belong to you, you can ask the owner to use iTunes or the iPhone Configuration Utility to find the device’s UDID. When you are done with that, press the Continue button to go to the review section. If all the details are correct, move past the review section to add the device to your portal.

Please note that any device added to your portal will count towards your total device quota for your membership. Most members can only add 100 devices per year, and any device that is deleted during this period will still count towards your quota until the membership period is over, upon which you can reset your list. This is to prevent people from adding billions of devices to their portal and creating an App Store competitor on their own where they can sign their apps with their own profiles and avoid having to send their apps to Apple for approval.

Next stop is creating the profile. In the same Certificates, Identifiers & Profiles page of iOS Dev Center, navigate to the Development item of the Provision Profiles section, as shown in Figure 1-51.

Development profiles
Figure 1-51. Development profiles

Press the plus (+) button to start generating a new development provision profile. Then choose the iOS App Development option and move on to the next stage. In the Select App ID section, choose the App ID that you just generated and move to the next stage. In the “Select certificates” section, choose the development certificate that you just created and move on to the next stage. When you get to the “Select devices” section, choose the devices that you want your app to be able to run on. After this, give a meaningful name to your profile and press the Generate button. This profile name will be visible in Xcode, so please, just like all the other names, ensure that this name is descriptive and not something similar to My Profile.

After you are done generating the profile, you can download it to your computer. After the profile is downloaded, install it by dragging it and dropping it into iTunes. Do not double-click on this profile because doing so will install the profile in your system with its MD5 hash value as its name. Thus, when you move to the ~/Library/MobileDevice/Provisioning Profiles folder on your computer to see the list of your profiles, you will see really cryptic names like that shown in Figure 1-52. As you can see, only one of the profiles has a meaningful name. The others have cryptic names because they were either installed on this sytem by Xcode or installed when the user double-clicked on them. If you want to see meaningful names on your computer and be able to manage these profiles easily, I suggest that you either copy and paste the profile directly to the aforementioned folder or drag and drop the profile onto iTunes for installation.

Only one of the profiles has a proper name
Figure 1-52. Only one of the profiles has a proper name

Congratulations. You have now created your profile. All you have to do in order to use it is to go to your app in Xcode and ensure that your info.plist has the same bundle identifier as the one that you designated in your profile, as shown in Figure 1-53.

The bundle identifier in our plist has to match our profile
Figure 1-53. The bundle identifier in our plist has to match our profile

As the last step, move to the Build Settings of your project and set the correct certificate and the profile, as shown in Figure 1-54.

Setting the certificate and profile of the project
Figure 1-54. Setting the certificate and profile of the project

Build your project and ensure that it builds without errors. If it doesn’t, make sure that you have followed all the steps explained in this recipe and attempt to build again until you get it right.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required