Quantcast
Channel: Kodeco | High quality programming tutorials: iOS, Android, Swift, Kotlin, Unity, and more
Viewing all 4373 articles
Browse latest View live

CocoaPods with Orta Therox – Podcast S02 E08

$
0
0
Learn about WatchKit with Ben Morrow!

Learn about WatchKit with Ben Morrow!

Welcome back to season 2 of the raywenderlich.com podcast!

We hope you’ve been enjoying the new weekly format of the podcast so far. There’s only 2 episodes left in season 2!

In this episode, we talk with Code Team member Orta Therox, one of the core contributors to CocoaPods, to take a deep dive into CocoaPods: past, present, and future.

[Subscribe in iTunes] [RSS Feed]

Our Sponsor

  • MyAppConverter: The world’s first true native mobile code converter that lets convert your iOS source code instantly and automatically to be a native Android app.

Links and References

Contact Us

Where To Go From Here?

We hope you enjoyed this episode of our podcast. Stay tuned for a new episode next week! :]

Be sure to subscribe in iTunes to get access as soon as it comes out!

We’d love to hear what you think about the podcast, and any suggestions on what you’d like to hear in future episodes. Feel free to drop a comment here, or email us anytime at podcast@raywenderlich.com!

CocoaPods with Orta Therox – Podcast S02 E08 is a post from: Ray Wenderlich

The post CocoaPods with Orta Therox – Podcast S02 E08 appeared first on Ray Wenderlich.


New WatchKit Book: Preorders Now Available!

$
0
0
Preorders are now available for our brand new WatchKit book!

Preorders are now available for our brand new WatchKit book!

Ever since WatchKit was announced, the team and I have been digging into the SDK and releasing a bunch of articles, written tutorials, and video tutorials.

And as you may have guessed – we’re also already hard at work on a brand new WatchKit book! :]

The book is called WatchKit by Tutorials, and we are happy to announce that today it is available for preorder!

Keep reading to find out what’s in the book, and how you can save by preordering!

Book Overview

WatchKit by Tutorials is tailored toward folks who already have some iOS experience, but are looking to learn how to develop apps for the Apple Watch – all the way from beginning to advanced topics.

In the first part of the book, you’ll start with an iOS app that helps you choose recipes and shop for ingredients, and then you will create Glances, Notifications, and an Apple Watch app that works hand-in-hand with the iOS app.

In the second part of the book, you’ll dive into more advanced topics like advanced text, image caching and animation, performance, and more.

Here is the tentative table of contents for the book (note this is subject to change):

  • Chapter 1, Hello Apple Watch!: You’ll click File\New Project and write a simple Apple Watch app from scratch!
  • Chapter 2, Architecture: Apple Watch apps have a very interesting architecture; part of the app resides on your iPhone, and part on the Apple Watch itself. Learn how it works!
  • Chapter 3, UI Controls: Learn about the new WatchKit-specific UI controls, such as WatchKit labels, images, buttons, switches, sliders, maps, and more.
  • Chapter 4, Layout: Apple Watch apps don’t use Auto Layout; they have their own layout system. Learn how it works and how to support different watch screen sizes!
  • Chapter 5, Tables: Tables are an extremely useful control in Apple Watch development – learn how to use them here!
  • Chapter 6, Menus: Learn how to use menus to let users perform tasks in your app, rather than cluttering up your user interface with buttons.
  • Chapter 7, Navigation: Learn about the three styles of navigation you can use in your WatchKit apps: hierarchy, page-based, and modal.
  • Chapter 8, Glances: Give your users a quick preview of your app’s content on their Apple Watch, using Glances.
  • Chapter 9, Basic Notifications: Learn how to present notifications of events from your app directly on the Apple Watch.
  • Chapter 10, Custom Notifications: Take your notifications to the next level through the power of custom notifications!
  • Chapter 11, Deep Linking with Handoff: Learn how to tap a glance or notification and go to a particular screen inside your app, by using deep linking with Handoff.
  • Chapter 12, Sharing Code and Data: Learn how to share code and data (such as a Core Data database) between your iOS app and WatchKit extension.
  • Chapter 13, Advanced Text: In WatchKit, there is more to text than meets the eye! Learn about standard font styles, custom fonts, internationalization, and more.
  • Chapter 14, Image Caching and Animation: The only type of animation supported in WatchKit is playing a pre-made sequence of images. Learn how to generate and work with these in practice!
  • Chapter 15, iCloud Document Storage: iCloud documents are a great way to transfer data between your apps. Learn how to use them here!
  • Chapter 16, Performance and Tips/Tricks: This chapter includes a bunch of tips and tricks to get the best performance from your apps.
  • Appendix, Setting up a Push Notification Server: Learn how to set up your own push notification server so you can send notifications upon events to your Apple Watch users.

By the time you’re done the book, you’ll know everything you need to make your own Apple Watch apps!

Preorder Now and Save!

When the WatchKit book is released, we will sell it for $54, just like the rest of the books on our site. If you preorder now, you can save $10 off the final price!

So be sure to preorder now and get your savings while you still can!

The team and I hope you enjoy this new WatchKit book, and we can’t wait to share it with you!

New WatchKit Book: Preorders Now Available! is a post from: Ray Wenderlich

The post New WatchKit Book: Preorders Now Available! appeared first on Ray Wenderlich.

Video Tutorial: WatchKit Part 6: Table Rows

How To Make A View Controller Transition Animation Like in the Ping App

$
0
0

Ping

The makers of the anonymous social networking app Secret recently released a new app called Ping, which allows users to receive notifications about topics they’re interested in.

One thing that stood out about Ping is its nice, circular animation between the main screen and the menu, as you can see in the animation to the right.

Every time I see a really neat animation, I do what everybody does: I think “Now how would I implement that on iOS…” — wait, normal people don’t think that?! :]

In this tutorial, you’ll learn how to implement this cool animation in Swift. In the process, you’ll learn about using shape layers, masking, the UIViewControllerAnimatedTransitioning protocol, the UIPercentDrivenInteractiveTransition class, and more.

Note this tutorial assumes you know the basics of iOS development and Swift. If you are a beginner, check out some of the many other tutorials on our site.

Overall Strategy

In Ping, the animation happens when you transition from one view controller to another.

In iOS, you can make custom animations between view controllers by putting both view controllers inside a UINavigationController, and implement iOS 7’s UIViewControllerAnimatedTransitioning protocol to animate the transition.

You’ll get into the details below, but essentially this protocol allows you to:

  • Specify the duration of the animation
  • Create a container view with references two both view controllers
  • Have the freedom to write any animation you can imagine!

You do all this with higher-level UIView animations or lower-level Core Animation animations (in this tutorial, you’ll do the latter).

Implementation Strategy

Now that you know where the coding action happens, the next bit of discussion revolves around how to actually implement the circle transition.

If I were to try to describe the animation in words it would be some thing like:

  • There’s a circle that originates from the button on the top right; it acts as a viewport into the view that appears.
  • In other words, the circle acts as a mask that shows everything inside its bounds, and hides everything that’s outside.

You can achieve this effect by using mask on CALayer, and also its alpha channel that decides which portions of the layer to show.

An alpha value of 1 shows the layer content underneath, while an alpha value of 0 hides content beneath. Anything in-between partially reveals the layer’s content. Here’s a diagram to explain this:

mask diagram

Now that you know about mask, the next step is to decide what kind of mask to apply. Since the animation has a circular mask, the natural choice is CAShapeLayer. To animate the circle, you simply increase the radius of the circle mask.

Getting Started

Note: This section is optional for those who want to build the project from scratch. If you’re an advanced iOS developer, feel free to skip to the Custom Animation section, where you’ll find a starter project and can dive right into the animations.

Now that you’ve sorted out the strategy, it’s time to write some code!

Create a new project in Xcode by clicking select File\New\Project, and choose iOS\Application\Single View Application.

step 1

Name the project CircleTransition, select Swift for Language, and select iPhone for Devices.

step 2

Start by opening Main.storyboard. You’ll see a single view controller, but the transition needs multiple view controllers to switch between.

But first, you should embed the view controller in a navigation controller. To do this, select the view controller, either in the Document Outline or on the canvas, and select Editor\Embed In\Navigation Controller.

Next select the navigation controller, and in the Utilities panel on the right open the Attributes Inspector (4th tab) and uncheck the Shows Navigation Bar checkbox, because the design doesn’t have a navigation bar.

Screenshot 2014-10-25 03.25.11

Now add another view controller to the storyboard. Line up both view controllers horizontally with the navigation controller for clarity.

ViewControllers

Select the new view controller, and in the Utilities panel on the right, select the Identity Inspector (on the third tab). Change the class type to ViewController, so it corresponds with the ViewController class file Xcode created for you.

Screenshot 2014-10-23 03.20.25

Next, add a button to the top right of each view controller. For both buttons, double-click and press backspace to set the button title to an empty string.

Screenshot 2014-10-23 12.16.11

Also set each button’s background color to black.

Now it’s time to position the buttons with Auto Layout. Select the button on the first view controller, then select the Pin button in the lower-right corner, and configure it as follows:

  • Click the light red brackets for the top and right, and set them each to 10
  • Set the Width and Height to 44
  • Set Update Frames to Items of New Constraints

PinConstraints2

Click Add 4 Constraints, and the button will resize. Repeat this for the other button as well.

The last thing to configure is the shape of the buttons — you need to make them circular by setting a corner radius. Rather than painstakingly coding it, switch to the Identity Inspector and use the User Defined Runtime Attributes to define the key path and set the cornerRadius for the button’s layer.

Screenshot 2014-10-23 12.54.26

Interface Builder will not reflect the circular shape of the buttons, but build and run your app and you’ll see a black circle in the top right corner.

iOS Simulator Screen Shot Nov 3, 2014, 10.27.11 PM

Now you need some content in those view controllers. Why not start giving each a background color?

For the first view controller, set it to have a green background color, and for the second view controller, set it to have a yellow background.

Screenshot 2014-10-23 13.42.48

Now add image views to both view controllers. Pin both their width and height to 300 points and center them in their superviews by selecting Align in the lower-right corner and selecting Horizontal Center in Container and Vertical Center in Container.

Screen Shot 2014-11-03 at 10.33.41 PM

Adjust their frames to the correct values by selecting the buttons, clicking Resolve Auto Layout Issues, then Update Frames, and your canvas should look like this:

Screenshot 2014-10-25 14.36.26

Download these images of iPhones and iPads, add them to your project and then assign them as the image for each image view. Ensure that the content mode of both image views is Aspect Fit.

Screen Shot 2014-11-03 at 10.37.33 PM

Your canvas should now look similar to this:
2014-10-25_15-40-43

Wire It Up

Congrats! You have the skeleton of an app. Now, it’s time to give it some digital “flesh” by wiring up the view controllers and buttons to their actions.

Right click the button on the first view controller, and then drag the action outlet to the second view controller.

Screenshot 2014-10-23 14.33.38

You’ll see a popup menu appear: select show.

Screenshot 2014-10-23 14.33.40
Doing this will push the second view controller when the button is tapped.

Later in this tutorial you’ll need a reference to this segue, so click on it, and open the Attributes Inspector on the left. Name the segue identifier PushSegue.

Screen Shot 2014-11-04 at 11.13.41 PM

Build and run the app to ensure that the second view controller is being pushed.

Now you’ll wire the button on the second view controller. You want to “pop” the view controller, so you’ll need to write a simple instance method in the ViewController class:

@IBAction func circleTapped(sender:UIButton) {
  self.navigationController?.popViewControllerAnimated(true)
}

While you’re in the ViewController class, add a weak property to hold a reference to the button.

@IBOutlet weak var button: UIButton!

Go back to Main.storyboard and do the following for both view controllers:

  • Right-click on the button
  • Drag the Touch Up Inside circle to the View Controller item at the top of the scene
  • Select circleTapped()

Screenshot 2014-10-23 15.04.58

Right-click each button once more, and this time, drag a referencing outlet to each view controller and connect it to the button property.

Screenshot 2014-10-23 21.01.32

Screenshot 2014-10-23 21.01.35

Build and run again, and you’ll see that you now have fully functional push and pop.

normal push


Custom Animation

If you skipped the previous sections, then download this starter project so you can jump in with fully configured view controllers and buttons.

To write a custom push or pop animation, you need to implement the UINavigationControllerDelegate protocol’s animationControllerForOperation method.

Create a new file with the iOS\Source\Cocoa Touch Class template. Set the class name to NavigationControllerDelegate.

After creating the file, mark class as implementing UINavigationControllerDelegate as follows:

class NavigationControllerDelegate: NSObject, UINavigationControllerDelegate {
 
}

Next open Main.storyboard to assign an instance of this class as the storyboard’s UINavigationController’s delegate.

To do this, search for Object in the library on the right, and drag and drop it under Navigation Controller Source on the left.
Screenshot 2014-10-23 15.39.30
Now click on the object, go to the Identity Inspector on the right, and change its class to NavigationControllerDelegate.
Screenshot 2014-10-23 15.40.25
Next, assign this object as the UINavigationController’s delegate by right-clicking the UINavigationController in the left panel, and dragging its delegate property to the NavigationControllerDelegate object:
Screenshot 2014-10-23 15.41.18

Head back to NavigationControllerDelegate and add this placeholder method:

func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
  return nil
}

Note that the body of the method empty; you’ll be working on that in a moment.

This method receives the two view controllers that the navigation controller is transitioning between, and its job is to return an object that implements UIViewControllerAnimatedTransitioning.

So you need to create one of those! To do this, create a new Cocoa Touch Class by navigating to File\New\File and name it CircleTransitionAnimator.

Screenshot 2014-10-23 15.52.17

Declare that you’re implementing the UIViewControllerAnimatedTransitioning protocol:

class CircleTransitionAnimator: NSObject, UIViewControllerAnimatedTransitioning {

Next you need to add the required methods for those protocols.

Start by adding the first method as follows:

func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
    return 0.5
}

In this method, you need to return the duration of the animation. You want an animation that lasts 0.5 seconds, so you simply return 0.5:

Next, add this property to the class:

weak var transitionContext: UIViewControllerContextTransitioning?

You’ll need this in a moment to store the transition context.

Next, add the second required method from the protocol:

func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
 
  //1
  self.transitionContext = transitionContext
 
  //2
  var containerView = transitionContext.containerView()
  var fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey) as ViewController
  var toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey) as ViewController
  var button = fromViewController.button
 
  //3
  containerView.addSubview(toViewController.view)
 
  //4
  var circleMaskPathInitial = UIBezierPath(ovalInRect: button.frame)
  var extremePoint = CGPoint(x: button.center.x - 0, y: button.center.y - CGRectGetHeight(toViewController.view.bounds))
  var radius = sqrt((extremePoint.x*extremePoint.x) + (extremePoint.y*extremePoint.y))
  var circleMaskPathFinal = UIBezierPath(ovalInRect: CGRectInset(button.frame, -radius, -radius))
 
  //5
  var maskLayer = CAShapeLayer()
  maskLayer.path = circleMaskPathFinal.CGPath
  toViewController.view.layer.mask = maskLayer
 
  //6
  var maskLayerAnimation = CABasicAnimation(keyPath: "path")
  maskLayerAnimation.fromValue = circleMaskPathInitial.CGPath
  maskLayerAnimation.toValue = circleMaskPathFinal.CGPath
  maskLayerAnimation.duration = self.transitionDuration(transitionContext)
  maskLayerAnimation.delegate = self
  maskLayer.addAnimation(maskLayerAnimation, forKey: "path")
}

Let’s go over this step by step:

  1. Lets you keep a reference to the transitionContext out of the scope of this method, so you can access it later.
  2. Gets references to the container view, the from and to view controller, as well as the button from where the action was triggered. The container view is the view in which the animation happens; the from and to view controllers are the same view controllers that take part in the animation.
  3. Adds the toViewController as a subview to containerView.
  4. Creates two circular UIBezierPath instances; one is the size of the button, and the second has a radius large enough to cover the entire screen. The final animation will be between these two bezier paths.
  5. Creates a new CAShapeLayer to represent the circle mask. You assign its path value with the final circular path after the animation to avoid the layer snapping back after the animation completes.
  6. Creates a CABasicAnimation on the path key path that goes from circleMaskPathInitial to circleMaskPathFinal. You also register a delegate, as you’ll do some cleanup after the animation completes.

Next, implement animationDidStop() in the same class to do a little cleanup:

override func animationDidStop(anim: CAAnimation!, finished flag: Bool) {
  self.transitionContext?.completeTransition(!self.transitionContext!.transitionWasCancelled())
  self.transitionContext?.viewControllerForKey(UITransitionContextFromViewControllerKey)?.view.layer.mask = nil
}

The first line is a way to tell iOS the transition finished. Because the animation is complete, you can remove the mask.

The final step is to actually use CircleTransitionAnimator.

Go back to NavigationControllerDelegate.swift and modify the stub method you added earlier as follows:

func navigationController(navigationController: UINavigationController,
 animationControllerForOperation operation: UINavigationControllerOperation,
 fromViewController fromVC: UIViewController,
 toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    return CircleTransitionAnimator()
}

This is a simple modification to return a new instance of the CircleTransitionAnimator you just created.

Build and run the app, and you should now see the animation in full glory!

circle

Congrats, you have replicated the animation from the Ping app! If that’s all you wanted, you can stop reading here; but if you want to learn how to make the animation interactive as well, keep reading!

An Interactive Gesture Animation

Once you have the animation up and running, you can turn your attention to another feature of custom view controller transitions: an interactive “back” gesture. Since tapping is passé, make sure you implement this to add depth to the UI.

The interactive gesture starts off with a call to navigationController:interactionControllerForAnimationController:. This is a UINavigationControllerDelegate method that expects you to return an object that conforms to UIViewControllerInteractiveTransitioning.

The iOS SDK provides you a class called UIPercentDrivenInteractiveTransition that already implements this protocol, and it does a lot of the interactive gesture handling for you.

To use this, open NavigationControllerDelegate.swift and add this property and new method:

var interactionController: UIPercentDrivenInteractiveTransition?
 
func navigationController(navigationController: UINavigationController, 
interactionControllerForAnimationController animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
  return self.interactionController
}

Now go back to thinking about this swipe back gesture. Obviously, you need a gesture recognizer.

I Knew That!

You’ll be adding the gesture recognizer to the navigation controller, within it’s navigation controller delegate. To do this, you’ll need a reference to the navigation controller, so open NavigationControllerDelegate.swift and add this property:

@IBOutlet weak var navigationController: UINavigationController?

Open Main.storyboard, and connect this property to the navigation controller by right-clicking on the Navigation Controller Delegate object on the left, and then dragging from the navigationController property to the navigation controller in the storyboard.
Screenshot 2014-10-24 02.18.12

Now hop back to NavigationControllerDelegate.swift and implement awakeFromNib() as follows:

override func awakeFromNib() {
  super.awakeFromNib()
  var panGesture = UIPanGestureRecognizer(target: self, action: Selector("panned:"))
  self.navigationController!.view.addGestureRecognizer(panGesture)
}

This creates UIPanGestureRecognizer, and adds this object to the navigation controller’s view. You’ll get gesture callbacks in the panned: method inside the same class.

Next, implement the method as follows:

//1
@IBAction func panned(gestureRecognizer: UIPanGestureRecognizer) {
  switch gestureRecognizer.state {
  case .Began:
    self.interactionController = UIPercentDrivenInteractiveTransition()
    if self.navigationController?.viewControllers.count > 1 {
      self.navigationController?.popViewControllerAnimated(true)
    } else {
      self.navigationController?.topViewController.performSegueWithIdentifier("PushSegue", sender: nil)
    }
 
    //2
  case .Changed:
    var translation = gestureRecognizer.translationInView(self.navigationController!.view)
    var completionProgress = translation.x/CGRectGetWidth(self.navigationController!.view.bounds)
    self.interactionController?.updateInteractiveTransition(completionProgress)
 
    //3
  case .Ended:
    if (gestureRecognizer.velocityInView(self.navigationController!.view).x > 0) {
      self.interactionController?.finishInteractiveTransition()
    } else {
      self.interactionController?.cancelInteractiveTransition()
    }
    self.interactionController = nil
 
    //4
  default:
    self.interactionController?.cancelInteractiveTransition()
    self.interactionController = nil
  }
}

Let’s break this code block down, case by case.

  1. .Began: As soon as the gesture gets recognised, it initializes a UIPercentDrivenInteractiveTransition object and assigns it to the interactionController property.
  • If you’re on the first view controller, it initiates a push; and if the second then it initiates a pop. Popping is fairly easy, but to push you’ll have to manually perform the segue from the button you created earlier.
  • In turn, the push or pop call triggers the NavigationControllerDelegate method call that returns self.interactionController. So by then, you have a non-nil value in the property.
  • .Changed: In this state, you complete the progress of the gesture and update the interactionController with the progress. It does the tough job of interpolating the animation, and with this part, Apple does all the hard work, so you don’t have to do anything! :]
  • .Ended: Here, you see the velocity of the pan gesture. If it’s positive, the transition completes, and if not, it’s cancelled. You also set the interactionController to nil so it acts as the cleanup crew.
  • default: If any other state, you simply cancel the transition and set the interactionController to nil.
  • Build and run the app, then swipe from left to right — you should see the same animation, but this time its under the control of your finger.

    circle interactive

    Where To Go From Here?

    Here is the completed project from the above tutorial.

    I hope you enjoyed this tutorial about how to make this simple, but cool animation that’s much like what you see in Ping. You can implement similar animations in your apps, and can change the look and feel by modifying the button, background colors and animation speed.

    You learned quite a few things in here, including using shape layers, masking, UIViewControllerAnimatedTransitioning protocol, the UIPercentDrivenInteractiveTransition class, and more.

    If you have questions, comments or would like to show off how you took the concepts in this lesson to the next level, please join the discussion below!

    How To Make A View Controller Transition Animation Like in the Ping App is a post from: Ray Wenderlich

    The post How To Make A View Controller Transition Animation Like in the Ping App appeared first on Ray Wenderlich.

    Video Tutorial: Introduction to WatchKit Part 7: Tables

    Storyboards Tutorial in Swift: Part 1

    $
    0
    0

    35_sb_square_image-250x250

    Update note: This storyboards tutorial was updated to iOS 8 and Swift by Caroline Begbie. Original post by Tutorial Team member Matthijs Hollemans.

    Storyboards are an exciting feature first introduced with iOS 5 that save you a lot of time building user interfaces for your apps.

    To show you what a storyboard is, I’ll let a picture do the talking. This is the storyboard that you will be building in this tutorial:

    The full storyboard for the app

    You may not know exactly yet what the app does but you can clearly see which screens it has and how they are related. That is the power of using storyboards.

    If you have an app with many different screens then storyboards can help reduce the amount of glue code you have to write to go from one screen to the next. In the old days, developers used to create a separate interface file (also knows as “nib” or “xib” files) for the design of each view controller. But now your app can use a single storyboard that contains the designs of all of these view controllers and the relationships between them.

    Storyboards have a number of advantages:

    • With a storyboard you have a better conceptual overview of all the screens in your app and the connections between them. It’s easy to keep track of everything because the entire design can be contained in a single file rather than spread out over many separate nibs.
    • Storyboards can describe the transitions between the various views. These transitions are called “segues” and you create them by connecting your view controllers right in the storyboard. Thanks to segues you need less code to take care of your UI.
    • Storyboards make working with table views a lot easier with prototype cells and static cells features. You can design your table views almost completely in the storyboard editor, something else that cuts down on the amount of code you have to write.
    • Storyboards make it easier to use Auto Layout, a feature that allows you to define mathematical relationships between elements that defined their position and sizing. This powerful feature makes it much easier to handle devices of varying screen sizes and dimensions. It is outside of scope for this tutorial, but you can read more about it in Beginning Auto Layout.

    If you’re the type who hates Interface Builder and who really wants to create the entire UI programmatically, then storyboards are probably not for you. Personally, I prefer to write as little code as possible — especially UI code! — so this tool is a welcome addition to my arsenal.

    And if you want to use nibs then go right ahead, but know that you can combine storyboards with nibs. It’s not an either-or situation.

    In this storyboards tutorial you’ll take a look at what you can do with storyboards. You’re going to build a simple app that lets you create a list of players and games, and rate their skill levels. In the process, you’ll learn the most common tasks that you’ll be using storyboards for.

    Getting Started

    Fire up Xcode and create a new project. Use the Single View Application template as the starting point.

    01_sb_newproject

    Fill in the template options as follows:

    • Product Name: Ratings
    • Organization Name: fill this in however you like
    • Company Identifier: the identifier that you use for your apps, in reverse domain notation
    • Language: Swift
    • Devices: iPhone
    • Use Core Data: not checked

    After Xcode has created the project, the main Xcode window looks like this:

    initial project config

    The new project consists of two classes, AppDelegate and ViewController, and the star of this tutorial: the Main.storyboard file.

    This is a portrait-only app, so before you continue, uncheck the Landscape Left and Landscape Right options under Deployment Info > Device Orientation seen in the General project settings shown above .

    Let’s take a look at that storyboard. Click Main.storyboard in the project navigator to open it in Interface Builder:

    The initial storyboard

    The official storyboard terminology for a view controller is “scene”, but you can use the terms interchangeably. The scene is what represents a view controller in the storyboard.

    Here you see a single view controller containing an empty view. The arrow pointing at the view controller from the left indicates it is the initial view controller to be displayed for this storyboard.

    Designing a layout in the storyboard editor is done by dragging controls from the Object Library (see bottom-right corner) into your view controller. You’ll see how easy that is just ahead.

    Note: You’ll notice that the default scene size is a square. Xcode 6 enables Auto Layout and Size Classes by default for storyboard and nib files. Auto Layout and Size Classes are cool new technologies for making flexible user interfaces that can easily resize, which is useful for supporting the various sizes of iPhones and iPads.

    Auto Layout was introduced in iOS 6, and Size Classes in iOS 8. They do have a bit of a learning curve, which is why you’re not using them in this tutorial, but you’ll definitely want to get your head around them so that you’ll be able to support the different device sizes. To learn more about size classes, see our book iOS 8 by Tutorials.

    Before you get to exploring, disable Auto Layout and Size Classes from the File inspector for this storyboard as seen below.

    Disabling auto layout

    When prompted, keep size class data for iPhone, and click Disable Size Classes:

    Disabling size classes

    The scene is now the size of a 4-inch iPhone.

    To get some feel for how the storyboard editor works, drag some controls from the Object Library in the lower right into the blank view controller:

    Dragging controls into storyboard

    As you drag the controls in, they should show up on the Document Outline on the left:

    Document outline

    If you don’t see a Document Outline, click this button at the bottom left of the storyboard canvas:

    The document outline button

    The storyboard shows the contents of all your view controllers. Currently there is only one view controller (or scene) in your storyboard, but over the course of this tutorial you’ll be adding several others.

    There is a miniature version of this Document Outline above the scene called the Dock:

    Dock

    The Dock shows the top-level objects in the scene. Each scene has at least a View Controller object, a First Responder object, and an Exit item, but it can potentially have other top-level objects as well. The Dock is convenient for making connections to outlets and actions. If you need to connect something to the view controller, you can simply drag to its icon in the Dock.

    Note: You probably won’t be using the First Responder very much. This is a proxy object that refers to whatever object has first responder status at any given time. As an example, you can hook up the Touch Up Inside event from a button to First Responder’s cut: selector. If at some point a text field has input focus then you can press that button to make the text field, which is now the first responder, cut its text to the pasteboard.

    Run the app and it should look exactly like what you designed in the editor (yours may look different than the screenshot below – this is just for demonstration and will not be used later in the tutorial):

    First app in the simulator

    The single View Controller you defined was set as the Initial View Controller – but how did the app load it? Take a peek at the application delegate to find the answer. Open up AppDelegate.swift and you’ll see the source starts with this:

    import UIKit
     
    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
      var window: UIWindow?
     
      func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
        // Override point for customization after application launch.
        return true
      }

    The @UIApplicationMain attribute at the top of the file designates the AppDelegate class as the entry point for the module. It is a requirement for using storyboards that your application delegate inherits from UIResponder and that it has a UIWindow property. All the methods are practically empty. Even application(_:didFinishLaunchingWithOptions:) simply returns true.

    The secret is in the Info.plist file. Click on Info.plist (you can find it in the Supporting Files group) and you’ll see this:

    Info.plist

    Storyboard apps use the key UIMainStoryboardFile, also known as “Main storyboard file base name”, to specify the name of the storyboard that must be loaded when the app starts. When this setting is present, UIApplication will load the named storyboard file, automatically instantiate the “Initial View Controller” from that storyboard, and then put that controller’s view into a new UIWindow object.

    You can also see this in the Project Settings under the General tab and Deployment Info section:

    Project Settings

    Now to create the real Ratings app with several view controllers.

    Just Add It To My Tab

    The Ratings app you’re about to build has a tabbed interface with two screens. With a storyboard it is really easy to create tabs.

    You’ll want to start with a clean storyboard, so switch back to Main.storyboard and delete the view controller you worked with earlier. This can be done by clicking on View Controller in the Document Outline and pressing the Delete key.

    Drag a Tab Bar Controller from the Object Library into the canvas. You may want to maximize your Xcode window first, because the Tab Bar Controller comes with two view controllers attached and you’ll need some room to maneuver. You can zoom in and out by double-clicking the canvas, or you can set the zoom scale by ctrl-clicking the canvas and selecting the zoom level.

    Tab bar controller

    The new Tab Bar Controller comes pre-configured with two additional view controllers – one for each tab. UITabBarController is a so-called container view controller because it contains one or more other view controllers. Two other common containers are the Navigation Controller and the Split View Controller (you’ll use the Navigation Controller later).

    The container Relationship is represented by the arrows between the Tab Bar Controller and the view controllers that it contains. An embed Relationship in particular is signified by the icon seen below in the middle of the arrow body.

    Container Relationship

    Note: If you want to move the Tab Bar Controller and its attached view controllers as a group, zoom out, and then you can ⌘-click or click and drag to select multiple scenes. This makes it possible to move them around together. (Selected scenes have a thin blue outline.)

    Drag a label into the first view controller (currently titled “Item 1″), double click it, and give it the text “First Tab”. Also drag a label into the second view controller (“Item 2″) and give it the text “Second Tab”. This allows you to actually see something happen when you switch between the tabs.

    Note: You can’t drag stuff into the scenes when the editor is zoomed out. You’ll need to return to the normal zoom level first by double-clicking in the canvas.

    Build & Run, and you’ll see something similar to this in the console:
    Ratings[18955:1293100] Failed to instantiate the default view controller for UIMainStoryboardFile 'Main' - perhaps the designated entry point is not set?

    Fortunately, the error is pretty clear here – you never set an entry point, meaning you didn’t set the Initial View Controller after you deleted the scene used earlier. To fix this, select the Tab Bar Controller and go to the Attributes Inspector. Check the box that says Is Initial View Controller.

    Set Initial View Controller

    In the canvas, the arrow that used to point to the deleted view controller now points at the Tab Bar Controller:

    Is Initial View Controller

    This means that when you run the app, UIApplication will make the Tab Bar Controller the main screen. Run the app and try it out. The app now has a tab bar and you can switch between the two view controllers with the tabs:

    App-with-tabs

    Tip: To change the initial view controller, you can also drag the arrow between view controllers.

    Xcode actually comes with a template for building a tabbed app (unsurprisingly called the Tabbed Application template) that you could have used, but it’s good to know how this works so you can also create a Tab Bar Controller by hand if you have to.

    Note: If you connect more than five scenes to the Tab Bar Controller, it automatically gets a More… tab when you run the app. Pretty neat!

    Adding a Table View Controller

    The two scenes that are currently attached to the Tab Bar Controller are both regular UIViewController instances. You are going to replace the scene from the first tab with a UITableViewController instead.

    Click on that first view controller in the Document Outline to select it, and then delete it. From the Object Library drag a new Table View Controller into the canvas in the place where that previous scene used to be:

    Table view controller

    Next, you want to place the Table View Controller inside a navigation controller. With the Table View Controller selected, choose Editor\Embed In\Navigation Controller from Xcode’s menubar. This adds yet another controller to the canvas:

    Navigation controller

    You could also have dragged in a Navigation Controller from the Object Library and embedded the tableview, but this Embed In command is a nice time saver for a common action.

    Because the Navigation Controller is also a container view controller (just like the Tab Bar Controller), it has a relationship arrow pointing at the Table View Controller. You can also see these relationships in the Document Outline:

    Relationship arrow

    Notice that embedding the Table View Controller gave it a navigation bar. Interface Builder automatically put it there because this scene will now be displayed inside the Navigation Controller’s frame. It’s not a real UINavigationBar object, but a simulated one.

    If you look at the Attributes inspector for the Table View Controller, you’ll see the Simulated Metrics section at the top:

    Simulated metrics

    “Inferred” is the default setting for storyboards and it means the scene will show a navigation bar when it’s inside of a Navigation Controller, a tab bar when it’s inside of a Tab Bar Controller, and so on. You could override these settings if you wanted to, but keep in mind they are here only to help you design your screens. The Simulated Metrics aren’t used during runtime; they’re just a visual design aid that shows what your screen will end up looking like.

    Next you need to connect these two new scenes to the Tab Bar Controller. Ctrl-drag from the Tab Bar Controller to the Navigation Controller. When you let go, a small popup menu appears. Choose the Relationship Segue – view controllers option:

    Relationship Segue

    This creates a new relationship arrow between the two scenes. This is also an embed Relationship as you saw with the other controllers contained by the Tab Bar Controller:

    Relationship arrow

    The Tab Bar Controller has two such relationships, one for each tab. The Navigation Controller itself has an embed Relationship with the Table View Controller.

    When you made this new connection, a new tab was added to the Tab Bar Controller, simply named “Item”. For this app, you want this new scene to be the first tab, so drag the tabs around to change their order:

    Drag tab items

    Run the app and try it out. The first tab now contains a table view inside a navigation controller.

    First tab with table view

    Before you put some actual functionality into this app, you need to clean up the storyboard a little. You will name the first tab “Players” and the second “Gestures”. You don’t change this on the Tab Bar Controller itself, but in the view controllers that are connected to these tabs.

    As soon as you connect a view controller to a Tab Bar Controller, it is given a Tab Bar Item object which you can see in the Document Outline or the bottom of the scene. You use this Tab Bar Item to configure the tab’s title and image seen on the Tab Bar Controller.

    Select the Tab Bar Item inside the Navigation Controller, and in the Attributes inspector set its Title to Players:

    Rename

    Rename the Tab Bar Item for the view controller from the second tab to Gestures in the same manner.

    A well-designed app should also put some pictures on these tabs. The resources for this tutorial contains a subfolder named Images. Drag that folder into the project, select ‘Copy items if needed’, and click Finish:

    Copy Resources

    In the Attributes inspector for the Players Tab Bar Item, choose the Players.png image.

    Players Image

    You probably guessed it, but give the Gestures item the image Gestures.png.

    A view controller that is embedded inside a Navigation Controller has a Navigation Item that is used to configure the navigation bar. Select the Navigation Item for the Table View Controller (you can find it in the Document Outline) and change its title in the Attributes inspector to Players.

    Alternatively, you can double-click the navigation bar and change the title there. Note that you should double-click the simulated navigation bar in the Table View Controller, not the actual Navigation Bar object in the Navigation Controller.

    Run the app and marvel at your pretty tab bar, created without writing a single line of code!

    App with tab bar images

    Prototype Cells

    Prototype cells allow you to easily design a custom layout for your table view cells directly from within the storyboard editor.

    The Table View Controller comes with a blank prototype cell. Click on that cell to select it and in the Attributes inspector set the Style option to Subtitle. This immediately changes the appearance of the cell to include two labels.

    With so much stackable content on a storyboard, it can sometimes be difficult to click on exactly what you want. If you have trouble, there are several options. One is that you can select the item in the Document Outline to the left of the canvas. The second is a handy hotkey: hold control + option + shift and click on the area you’re interested in. A popup will appear allowing you to select any element directly under your cursor. That latest – starting in Xcode 6 – is that you can single click multiple times to cycle through the different layers.

    If you’ve used table views before and created your own cells by hand, you may recognize this as the UITableViewCellStyle.Subtitle style. With prototype cells you can either pick one of the built-in cell styles as you just did, or create your own custom design (which you’ll do shortly).

    Set the Accessory attribute to Disclosure Indicator and in the Identifier field type PlayerCell. All prototype cells are still regular UITableViewCell objects and therefore should have a reuse identifier.

    Cell setup

    Run the app, and… nothing has changed. That’s not so strange: you still have to make a data source for the table so it will know what rows to display. That’s exactly what you’re going to do next.

    Add a new file to the project. Choose the Cocoa Touch Class template under iOS/Source. Name the class PlayersViewController and make it a subclass of UITableViewController. The Also create XIB file option should be unchecked because you already have the design of this view controller in the storyboard. No nibs today! Choose the Swift language and hit Next followed by Create.

    Players view controller

    Go back to the storyboard and select the Table View Controller (make sure you select the actual view controller and not one of the views inside it). In the Identity inspector, set its Class to PlayersViewController. That is the essential step for hooking up a scene from the storyboard with your custom view controller subclass. Don’t forget this or your class won’t be used!

    Custom class

    From now on when you run the app that table view controller from the storyboard is an instance of the PlayersViewController class.

    The table view will display a list of players, so now you will create the main data model for the app – an array that contains Player objects. Add a new file to the project using the Swift File template under iOS/Source. Name the file Player.

    Add the following to the end of Player.swift:

    import UIKit
     
    class Player: NSObject {
      var name: String
      var game: String
      var rating: Int
     
      init(name: String, game: String, rating: Int) {
        self.name = name
        self.game = game
        self.rating = rating
        super.init()
      }
    }

    There’s nothing special going on here. Player is simply a container object for these three properties: the name of the player, the game they’re playing, and a rating of 1 to 5 stars.

    You’ll next make an array of test Player objects and then assign it to an array in PlayersViewController. Start by creating a new file using the Swift File template named SampleData. Add this to the end of SampleData.swift:

    //Set up sample data
     
    let playersData = [ Player(name:"Bill Evans", game:"Tic-Tac-Toe", rating: 4),
      Player(name: "Oscar Peterson", game: "Spin the Bottle", rating: 5),
      Player(name: "Dave Brubeck", game: "Texas Hold 'em Poker", rating: 2) ]

    Here you’ve defined a constant called playersData and assigned an array of hard coded Player objects to it.

    Now add a Player array property just below class PlayersTableViewController: UITableViewController in PlayersViewController.swift to hold the list of players:

    var players: [Player] = playersData

    You could simply have set up the sample data in PlayersViewController when defining the players variable. But because this data might later be provided from a plist or an SQL file, it’s wise to handle loading the data outside of the view controller.

    Now that you have an array full of Player objects, you can continue hooking up the data source in PlayersViewController. Still in PlayersViewController.swift, replace the table view data source methods with the following:

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

    The real work happens in cellForRowAtIndexPath. Replace this method, which is currently commented out, with:

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
     -> UITableViewCell {
      let cell = tableView.dequeueReusableCellWithIdentifier("PlayerCell", forIndexPath: indexPath)
        as UITableViewCell
     
      let player = players[indexPath.row] as Player
      cell.textLabel?.text = player.name
      cell.detailTextLabel?.text = player.game
      return cell
    }

    The method dequeueReusableCellWithIdentifier(_:forIndexPath:) will check to see if there is an existing cell that can be recycled. If not, it will automatically allocate a prototype cell and return it to you. All you need to do is supply the re-use identifier that you set on the prototype cell in the storyboard editor – in this case PlayerCell. Don’t forget to set that identifier, or this little scheme won’t work!

    Run the app, and lo and behold, the table view has players in it!

    App with players

    It takes just a few lines of code to use these prototype cells. I think that’s just great!

    Note: In this app you’re using only one prototype cell but if your table needs to display different kinds of cells then you can simply add additional prototype cells to the storyboard. You can either duplicate the existing cell to make a new one, or increment the value of the Table View’s Prototype Cells attribute. Be sure to give each cell its own re-use identifier, though.

    Designing Your Own Prototype Cells

    Using a standard cell style is OK for many apps, but for this app you want to add an image on the right-hand side of the cell that shows the player’s rating (one to five stars). Having an image view in that spot is not supported by the standard cell styles, so you’ll have to make a custom design.

    Switch back to Main.storyboard, select the prototype cell in the table view, and on the Attributes inspector, set its Style attribute to Custom. The default labels now disappear.

    First make the cell a little taller. Either drag its handle at the bottom or change the Row Height value in the Size inspector (after checking Custom). Make the cell 55 points high.

    Drag two Label objects from the Objects Library into the cell and place them roughly where the standard labels were previously. Just play with the font and colors in the Attributes Inspector and pick something you like. Set the text of the top label to Name and the bottom label to Game.

    Drag an Image View into the cell and place it on the right, next to the disclosure indicator. Make it 81 points wide; the height isn’t very important. Set its Mode to Center (under View in the Attributes inspector) so that whatever image you put into this view is not stretched.

    Make the labels 190 points wide by setting their width under the View section in the Size Inspector. The labels shouldn’t overlap the image view. The final design for the prototype cell looks something like this:

    Custom cell design

    Because this is a custom designed cell, you can no longer use UITableViewCell’s textLabel and detailTextLabel properties to put text into the labels. These properties refer to labels that aren’t on this cell anymore; they are only valid for the standard cell types. Instead, you will use tags to find the labels.

    You could alternatively create a custom class that inherits from UITableViewCell and contains properties corresponding to the labels on your cell view. Tags are used here for simplicity, and they’re a perfectly good solution for simple cases. However, later in this tutorial you’ll experiment with the custom class method.

    In the Attributes inspector, set the tag value for the Name label to 100, Game label to 101, and the Image View label 102.

    Then open PlayersViewController.swift and add a new method called imageForRating at the end as follows:

    func imageForRating(rating:Int) -> UIImage? {
      switch rating {
      case 1:
        return UIImage(named: "1StarSmall")
      case 2:
        return UIImage(named: "2StarsSmall")
      case 3:
        return UIImage(named: "3StarsSmall")
      case 4:
        return UIImage(named: "4StarsSmall")
      case 5:
        return UIImage(named: "5StarsSmall")
      default:
        return nil
      }
    }

    Pretty simple – this returns a different star image depending on the rating. Still in PlayersViewController, change tableView(_:cellForRowAtIndexPath:) to the following:

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
      let cell = tableView.dequeueReusableCellWithIdentifier("PlayerCell", forIndexPath: indexPath) as UITableViewCell //1
     
      let player = players[indexPath.row] as Player //2
     
      if let nameLabel = cell.viewWithTag(100) as? UILabel { //3
        nameLabel.text = player.name
      }
      if let gameLabel = cell.viewWithTag(101) as? UILabel {
        gameLabel.text = player.game
      }
      if let ratingImageView = cell.viewWithTag(102) as? UIImageView {
        ratingImageView.image = self.imageForRating(player.rating)
      }
      return cell
    }

    Here’s the breakdown of what you’ve done:

    1. dequeueReusableCellWithIdentifier will dequeue an existing cell with the reuse identifier PlayerCell if available or create a new one if not.
    2. You look up the Player object corresponding to the row being populated and assign it to player.
    3. The labels and images are looked up by their tag on the cell and populated with data from the player object.

    That should do it. Now run the app again, and it will probably look something like this:

    Wrong table cell height

    Hmm, that doesn’t look quite right – the cells appear to overlap one another. You did change the height of the prototype cell, but the table view doesn’t take that into consideration. There are two ways to fix it: you can change the table view’s Row Height attribute, or implement the tableView(tableView:heightForRowAtIndexPath:) method. The former is fine in this case because we only have one type of cell and we know the height in advance.

    Note: You would use tableView(tableView:heightForRowAtIndexPath:) if you did not know the height of your cells in advance, or if different rows can have different heights.

    Back in Main.storyboard, in the Size inspector of the Table View, set Row Height to 55:

    Right table cell height

    If you run the app now, it looks a lot better!

    App with proper row height

    By the way, if you changed the height of the cell by dragging its handle rather than typing in the value, then the table view’s Row Height property was automatically changed too. So it may have worked correctly for you the first time around.

    Using a Subclass for the Cell

    The table view already works pretty well but I’m not a big fan of using tags to access the labels and other subviews of the prototype cell. It would be much more clean if you could connect these labels to outlets and then use the corresponding properties. As it turns out, you can.

    Add a new file to the project, with the Cocoa Touch Class template. Name it PlayerCell and make it a subclass of UITableViewCell. Don’t check the option to create a XIB, as you already have the cell in your storyboard.

    Add these properties in the PlayerCell class, just below the class definition:

    @IBOutlet weak var gameLabel: UILabel!
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var ratingImageView: UIImageView!

    All these variables are IBOutlets, which can be connected up to your scene in the storyboard.

    Back in Main.storyboard, select the prototype cell PlayerCell and change its class to PlayerCell on the Identity inspector. Now whenever you ask the table view data source for a new cell with dequeueReusableCellWithIdentifier(_:forIndexPath:), it will return a PlayerCell instance instead of a regular UITableViewCell.

    Note that you gave this class the same name as the reuse identifier – they’re both called PlayerCell – but that’s only because I like to keep things consistent. The class name and reuse identifier have nothing to do with each other, so you could name them differently if you wanted to.

    Now connect the labels and the image view to these outlets. Navigate to the Connections Inspector in the storyboard and then select the Player Cell from either the canvas or Document Outline. Drag from the nameLabel Outlet in the Connections inspector to the Name label object in either the Document Outline, or the canvas. Repeat for gameLabel and ratingImageView.

    Connect outlet

    Important: You should hook up the controls to the table view cell, not to the view controller! You see, whenever your data source asks the table view for a new cell with dequeueReusableCellWithIdentifier, the table view doesn’t give you the actual prototype cell but a copy (or one of the previous cells is recycled if possible).

    This means there will be more than one instance of PlayerCell at any given time. If you were to connect a label from the cell to an outlet on the view controller, then several copies of the label will try to use the same outlet. That’s just asking for trouble. (On the other hand, connecting the prototype cell to actions on the view controller is perfectly fine. You would do that if you had custom buttons or other UIControls on your cell.)

    An alternative to using the Connections inspector is to ctrl-drag from the PlayerCell to the control, and choose the outlet name from the popup menu:

    IBOutlet connection

    Now that you’ve hooked up the properties, you can simplify the data source code a bit. Change tableView(_:cellForRowAtIndexPath:) to:

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
     -> UITableViewCell {
      let cell = tableView.dequeueReusableCellWithIdentifier("PlayerCell", forIndexPath: indexPath)
        as PlayerCell
     
      let player = players[indexPath.row] as Player
      cell.nameLabel.text = player.name
      cell.gameLabel.text = player.game
      cell.ratingImageView.image = imageForRating(player.rating)
      return cell
    }

    That’s more like it. You now cast the object that you receive from dequeueReusableCellWithIdentifier to a PlayerCell, and then you can simply use the properties that are wired up to the labels and the image view. Isn’t it great how using prototype cells makes table views a whole lot less messy?

    Run the app and try it out. It should still look the same as before, but behind the scenes it’s now using your own table view cell subclass!

    Where To Go From Here?

    Click here to download the full source code for the project up to this point.

    Check out part two of this tutorial, where we’ll cover segues, static table view cells, the Add Player screen, a game picker screen, and the full downloadable example project for this tutorial!

    If you felt lost at any point during this tutorial, you also might want to brush up on the basics with our iOS Apprentice series. In that series, you’ll learn the foundational knowledge you need as an iOS developer from the ground up — perfect for complete beginners, or those looking to fill in some gaps.

    If you have any questions or comments on this tutorial or on storyboards, please join the forum discussion below!

    Storyboards Tutorial in Swift: Part 1 is a post from: Ray Wenderlich

    The post Storyboards Tutorial in Swift: Part 1 appeared first on Ray Wenderlich.

    Storyboards Tutorial in Swift: Part 2

    $
    0
    0

    35_sb_square_image

    Update note: This tutorial was updated to iOS 8 and Swift by Caroline Begbie. Original post by Tutorial Team member Matthijs Hollemans.

    If you want to learn about storyboards, you’ve come to the right place!

    In the first part of this storyboards tutorial series, you covered the basics of using Interface Builder to create and connect various view controllers, along with how to make custom table view cells directly from the storyboard editor.

    In this second and final part of this storyboards tutorial series, we’ll cover segues, static table view cells, the Add Player screen, and a game picker screen!

    We’ll start where we left off last tutorial, so open your project from last time, or download the example code from the previous tutorial first.

    OK, let’s dive into some of the other cool features in storyboards!

    Introducing Segues

    It’s time to add more view controllers to the storyboard. You’re going to create a screen that allows users to add new players to the app.

    Open up Main.storyboard and drag a Bar Button Item into the right slot of the navigation bar on the Players scene with your table view. In the Attributes inspector change its Identifier to Add to make it a standard + button.

    Add button

    When the user taps this button, you want the app to pop up a new modal screen for entering details of a new player.

    Drag a new Navigation Controller into the canvas to the right of the Players scene. Remember that you can double-click the canvas to zoom out so you have more room to work. This new Navigation Controller comes with a Table View Controller attached, so that’s handy.

    Here’s the trick: Select the + button that you just added on the Players screen and ctrl-drag to the new Navigation Controller. Release the mouse button and a small popup menu shows up. Select modal from the popup menu:

    Reminder: You can’t add to or modify the contents of a storyboard when zoomed out. If you’re having issues creating the segue, try double clicking to zoom back in!

    Add button drag

    This places a new arrow between the Players screen and the Navigation Controller:

    Modal relationship

    This type of connection is known as a segue (pronounce: seg-way) and represents a transition from one screen to another. The storyboard connections you’ve seen so far were relationships and they described one view controller containing another. A segue, on the other hand, changes what is on the screen. Segues are triggered by taps on buttons, table view cells, gestures, and so on.

    The cool thing about using segues is that you no longer have to write any code to present the new screen, nor do you have to hook up your buttons to IBAction methods. What you just did, dragging from the Bar Button Item to the next screen, is enough to create the transition. (Note: If your control already had an IBAction connection, then the segue overrides that.)

    Run the app and press the + button. A new table view will slide up the screen.

    Modal appears

    This is a so-called “modal” segue. The new screen completely obscures the previous one. The user cannot interact with the underlying screen until they close the modal screen first. Later on you’ll also see “push” segues that push new screens on the navigation stack of a Navigation Controller.

    The new screen isn’t very useful yet – you can’t even close it to go back to the main screen. That’s because segues only go one way – so while it can go from the Players scene to this new one, it can’t go back.

    Storyboards provide the ability to ‘go back’ with something called an unwind segue, which you’ll implement next. There are three main steps:

    1. Create an object for the user to select, usually a button.
    2. Create an unwind method in the controller that you want to return to.
    3. Hook up the method and the object in the storyboard.

    First, open Main.storyboard and select the new Table View Controller scene (the one that says “Root View Controller”). Change the title of the screen to Add Player (by double-clicking in the navigation bar). Then add two Bar Button Items to the navigation bar. In the Attributes inspector, set the Identifier of the button to the left to Cancel, and the one on the right to Done (also change this one’s Style from Bordered to Done).

    Cancel and done buttons

    Next, add a new file to the project using the Cocoa Touch Class template – name it PlayerDetailsViewController and make it a subclass of UITableViewController. To hook this new class up to the storyboard, switch back to Main.storyboard and select the Add Player scene. In the Identity inspector set its Class to PlayerDetailsViewController. I always forget this very important step, so to make sure you don’t; I’ll keep pointing it out.

    Now you can finally create the unwind segue. In PlayersViewController.swift (not the detail controller), add the unwind methods just below the class definition:

    @IBAction func cancelToPlayersViewController(segue:UIStoryboardSegue) {
      dismissViewControllerAnimated(true, completion: nil)
    }
     
    @IBAction func savePlayerDetail(segue:UIStoryboardSegue) {
      dismissViewControllerAnimated(true, completion: nil)
    }

    Both of these methods simply dismiss the controller when called. Later, you’ll make some changes to savePlayerDetail to allow it to live up to it’s name!

    Lastly, switch back to Interface Builder and hook up the Cancel and Done buttons to their respective action methods. Ctrl-drag from the bar button to the exit object above the view controller and then pick the correct action name from the popup menu:

    Make connections

    Note the name that you gave the cancel method. When you create an unwind segue, the list will show all unwind methods (ie ones with the signature @IBAction func methodname(segue:UIStoryboardSegue)) in the entire app, so ensure that you create a name that you recognize.

    Run the app, press the + button, and test the Cancel and Done buttons. A lot of functionality for very little code!

    Static Cells

    When you’re finished with this section, the Add Player screen will look like this:

    Add Player screen

    That’s a grouped table view, of course, but you don’t have to create a data source for this table. You can design it directly in Interface Builder — no need to write cellForRowAtIndexPath for this one. The feature that makes this possible is called static cells.

    Select the table view in the Add Player scene and in the Attributes inspector change Content to Static Cells. Change Style from Plain to Grouped and give the table view 2 sections.

    Static cells

    When you change the value of the Sections attribute, the editor will clone the existing section. (You can also select a specific section in the Document Outline on the left and duplicate it.)

    The finished screen will have only one row in each section, so select the superfluous cells and delete them either using the canvas or the Document Outline.

    Select the top-most Table View Section (from the Document Outline). In its Attributes inspector, give the Header field the value Player Name.

    11_sb2_staticcellsheader

    Drag a new Text Field into the cell for this section. Stretch out its width and remove its border so you can’t see where the text field begins or ends. Set the Font to System 17.0 and uncheck Adjust to Fit.

    Player Name Cell

    You’re going to make an outlet for this text field on the PlayerDetailsViewController using the Assistant Editor feature of Xcode. While still in the storyboard, open the Assistant Editor with the button from the toolbar (the one that looks like a tuxedo / alien face). It should automatically open on PlayerDetailsViewController.swift (if it doesn’t, use the jumpbar in the right hand split window to select that .swift file).

    Select the new text field and ctrl-drag to the top of the .swift file, just below the class definition. When the popup appears, name the new outlet nameTextField, and click Connect. After you click Connect, Xcode will add the property to the PlayersDetailViewController class and connect to it in the storyboard:

    12_sb2_dragoutlet

    Creating outlets for views on your table cells is exactly the kind of thing I said you shouldn’t try with prototype cells, but for static cells it is OK. There will be only one instance of each static cell and so it’s perfectly acceptable to connect their subviews to outlets on the view controller.

    Set the Style of the static cell in the second section to Right Detail. This gives you a standard cell style to work with. Change the label on the left to read Game by double clicking it and give the cell a Disclosure Indicator accessory.

    12_sb2_gamecell

    Just as you did for the Name text field, make an outlet for the label on the right (the one that says “Detail”) and name it detailLabel. The labels on this cell are just regular UILabel objects. You might need to click a few times on the text “Detail” to select the label (and not the whole cell) before cntl clicking and dragging to PlayerDetailsViewController.swift. Once done, it will look something like this:

    13_sb2_selecdetaillabel

    The final design of the Add Player screen looks like this:

    14_sb2_staticcellsfinal

    The screens you have designed so far in this storyboard all have the width and height of the 4-inch screen of the iPhone 5, which is 568 points tall. Obviously, your app should work properly with all the different screen sizes, and you can preview all these sizes within your Storyboard.

    Open the Assistant Editor from the toolbar, and use the jump bar to select Preview. At the bottom left of the assistant editor, click the + symbol to add new screen sizes to preview. To remove a screen size, select it and hit the Delete key.

    15_screen_preview

    For the Ratings app, you don’t have to do anything fancy. It only uses table view controllers and they automatically resize to fit the screen space. When you do need to support different layouts for different sized devices, you will use Auto Layout and the new Size Classes.

    Build and run now, and you’ll notice that the Add Player screen is still blank!
    add player blank

    When you use static cells, your table view controller doesn’t need a data source. Because you used an Xcode template to create the PlayerDetailsViewController class, it still has some placeholder code for the data source and that will prevent the static cells from working properly – that’s why your static content wasn’t visible here. Time to fix it!

    Open PlayerDetailsViewController.swift and delete everything from the following line down (except for the class closing bracket):

    // MARK: - Table view data source

    That should silence Xcode about the warnings it has been giving ever since you added this class to the project.

    Run the app and check out the new screen with the static cells. All without writing a line of code – in fact, you threw away a bunch of code!

    One more thing about static cells: they only work in UITableViewController. Even though Interface Builder will let you add them to a Table View object inside a regular UIViewController, this won’t work during runtime. The reason for this is that UITableViewController provides some extra magic to take care of the data source for the static cells. Xcode even prevents you from compiling such a project with the error message: “Illegal Configuration: Static table views are only valid when embedded in UITableViewController instances”.

    Prototype cells, on the other hand, work just fine in a table view that you place inside a regular view controller. Neither work for nibs, though. At the moment, if you want to use prototype cells or static cells, you’ll have to use a storyboard.

    It is not unthinkable that you might want to have a single table view that combines both static cells and regular dynamic cells, but this isn’t very well supported by the SDK. If this is something you need to do in your own app, then see this post on the Apple Developer Forums for a possible solution.

    Note: If you’re building a screen that has a lot of static cells — more than can fit in the visible frame — then you can scroll through them in Interface Builder with the scroll gesture on the mouse or trackpad (2 finger swipe). This might not be immediately obvious, but it does work.

    You can’t always avoid writing code altogether though, even for a table view of static cells. When you dragged the text field into the first cell, you probably noticed it didn’t fit completely. There is a small margin of space around the text field. The user can’t see where the text field begins or ends, so if they tap in the margin and the keyboard doesn’t appear, they’ll be confused.

    To avoid that, you should let a tap anywhere in that row bring up the keyboard. That’s pretty easy to do – just open PlayerDetailsViewController.swift and add a tableView(_:didDeselectRowAtIndexPath:) method as follows:

    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
      if indexPath.section == 0 {
        nameTextField.becomeFirstResponder()
      }
    }

    This just says that if the user tapped the first cell, the app should activate the text field. There is only one cell in the section so you only need to test for the section index. Making the text field the first responder will automatically bring up the keyboard. It’s just a little tweak, but one that can save users a bit of frustration.

    Tip: when adding a delegate method, or overriding a view controller method, just start typing the method name (without preceding it with “func”), and then you will be able to select the correct method from the list available.

    You should also set the Selection Style for that cell to None (instead of Default) in the storyboard Attributes inspector, otherwise the row appears highlighted if the user taps in the margin around the text field.

    Selection Style

    All right, that’s the design of the Add Player screen. Now let’s actually make it work.

    The Add Player Screen at Work

    For now you will ignore the Game row and just let users enter the name of the player.

    When the user presses the Cancel button the screen should close and whatever data they entered will be lost. That part already works with the unwind segue.

    When the user presses Done, however, you should create a new Player object and fill in its properties and update the list of players.

    The prepareForSegue(:sender:) method is invoked whenever a segue is about to take place. You’ll override this method to store the data entered into a new Player object before dismissing the view.

    Note: You never call prepareForSegue yourself. It’s a message from UIKit to let you know that a segue has just been triggered.

    Inside PlayerDetailsViewController.swift, first add a property at the top of the class:

    var player:Player!

    This does not instantiate the property but the exclamation mark, defining it as an implicitly unwrapped optional, means that it must be instantiated and have a value before using it.

    Next, add the following method to PlayerDetailsViewController.swift:

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
      if segue.identifier == "SavePlayerDetail" {
        player = Player(name: self.nameTextField.text, game: "Chess", rating: 1)
      }
    }

    The prepareForSegue(_:sender:) method creates a new Player instance with default values for game and rating. It does this only for a segue that has the identifier of SavePlayerDetail. If you were to run the application at this point, it would crash, because you don’t have any identifier called "SavePlayerDetail".

    Tip: If you get mysterious crashes that you can’t track down, often they come from having deleted or changed names of objects in the code so that the storyboard does not reference the correct object any more.

    In Main.storyboard, find the Add Player scene in the Document Outline and select the unwind segue tied to the savePlayerDetail Action. Change its identifier to "SavePlayerDetail":

    16_sb2_unwind_identifier

    Next, select the unwind segue tied to cancelToPlayersViewController, and change the identifier to CancelPlayerDetail. This is necessary now, as the prepareForSegue(_:sender:) method tests the identifier string, and if it does not have one, the app will crash.

    Hop over to PlayersViewController and change the unwind segue method savePlayerDetail(segue:) to look like this:

    @IBAction func savePlayerDetail(segue:UIStoryboardSegue) {
      let playerDetailsViewController = segue.sourceViewController as PlayerDetailsViewController
     
      //add the new player to the players array
      players.append(playerDetailsViewController.player)
     
      //update the tableView
      let indexPath = NSIndexPath(forRow: players.count-1, inSection: 0)
      tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
     
      //hide the detail view controller
      dismissViewControllerAnimated(true, completion: nil)
    }

    This obtains a reference to the PlayerDetailsViewController via the segue reference passed to the method. It uses that to add the new Player object to the array of players used in the datasource. Then it tells the table view that a new row was added (at the bottom), because the table view and its data source must always be in sync.

    You could have just done tableView.reloadData() but it looks nicer to insert the new row with an animation. UITableViewRowAnimation.Automatic automatically picks the proper animation, depending on where you insert the new row. Very handy.

    Try it out, you should now be able to add new players to the list!

    App-with-new-players

    Performance

    Now that you have several view controllers in the storyboard, you might be wondering about performance. Loading a whole storyboard at once isn’t a big deal. The Storyboard doesn’t instantiate all the view controllers right away – only the initial view controller is immediately loaded. Because your initial view controller is a Tab Bar Controller, the two view controllers that it contains are also loaded (the Players scene from the first tab and the scene from the second tab).

    The other view controllers are not instantiated until you segue to them. When you close these view controllers they are immediately deallocated, so only the actively used view controllers are in memory, just as if you were using separate nibs.

    Let’s see that in practice. Add an initializer and deinitializer to PlayerDetailsViewController:

    required init(coder aDecoder: NSCoder) {
      println("init PlayerDetailsViewController")
      super.init(coder: aDecoder)
    }
     
    deinit {
      println("deinit PlayerDetailsViewController")
    }

    You’re overriding init(coder:) and deinit, and making them log a message to the Xcode Debug pane. Now run the app again and open the Add Player screen. You should see that this view controller did not get allocated until that point.

    When you close the Add Player screen, either by pressing Cancel or Done, you should see the println() from deinit. If you open the screen again, you should also see the message from init(coder:) again. This should reassure you that view controllers are loaded on-demand only, just as they would if you were loading nibs by hand.

    Note: If you’ve worked with nibs before, then init(coder:) will be familiar. That part has stayed the same with storyboards; init(coder:), awakeFromNib(), and viewDidLoad() are still the methods to use. You can think of a storyboard as a collection of nibs with additional information about the transitions and relationships between them. But the views and view controllers inside the storyboard are still encoded and decoded in the same way.

    The Game Picker Screen

    Tapping the Game row in the Add Player screen should open a new screen that lets the user pick a game from a list. That means you’ll be adding yet another table view controller, although this time you’re going to push it on the navigation stack rather than show it modally.

    Drag a new Table View Controller into the storyboard. Select the Game table view cell in the Add Player screen (be sure to select the entire cell, not one of the labels) and ctrl-drag to the new Table View Controller to create a segue between them. Make this a Push segue (under Selection Segue in the popup, not Accessory Action) and give it the identifier PickGame from the Attribute Inspector for the segue.

    Double-click the navigation bar and name this new scene Choose Game. Set the Style of the prototype cell to Basic, and give it the reuse identifier GameCell. That’s all you need to do for the design of this screen:

    16_sb2_pickgame

    Add a new Swift file to the project, using the Cocoa Touch Class template and name it GamePickerViewController, subclass of UITableViewController. Go back to your new Choose a Game scene in the storyboard and set its Custom Class to GamePickerViewController.

    Now let’s give this new screen some data to display. In GamePickerViewController.swift, add a games property to the top and override the viewDidLoad function so that the beginning of the class looks like this:

    var games:[String]!
     
    override func viewDidLoad() {
      super.viewDidLoad()
      games = ["Angry Birds",
               "Chess",
               "Russian Roulette",
               "Spin the Bottle",
               "Texas Hold'em Poker",
               "Tic-Tac-Toe"]
    }

    You just added a new String dictionary called games and populated it with some hardcoded values in viewDidLoad().

    Now replace the data source methods from the template with:

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
      return 1
    }
     
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
      return games.count
    }
     
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
      let cell = tableView.dequeueReusableCellWithIdentifier("GameCell", forIndexPath: indexPath) as UITableViewCell
      cell.textLabel?.text = games[indexPath.row]
      return cell
    }

    Standard stuff here – you’re just setting up the data source to use the games array and placing the string values in the cell’s textLabel.

    That should do it as far as the data source is concerned. Run the app and tap the Game row. The new Choose Game screen will slide into view. Tapping the rows won’t do anything yet, but because this screen is presented on the navigation stack, you can always press the back button to return to the Add Player screen.

    17_sb2_choosegame

    This is pretty cool, huh? You didn’t have to write any code to invoke this new screen. You just ctrl-dragged from the static table view cell to the new scene and that was it. The only code you wrote was to populate the contents of the tableView, which is typically something more dynamic rather than a hardcoded list.

    Of course, this new screen isn’t very useful if it doesn’t send any data back, so you’ll have to add a new unwind segue for that.

    At the top of the GamePickerViewController class, add properties to hold the name and the index of the currently selected game:

    var selectedGame:String? = nil
    var selectedGameIndex:Int? = nil

    Next, change cellForRowAtIndexPath: to:

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
      let cell = tableView.dequeueReusableCellWithIdentifier("GameCell", forIndexPath: indexPath) as UITableViewCell
      cell.textLabel?.text = games[indexPath.row]
     
      if indexPath.row == selectedGameIndex {
        cell.accessoryType = .Checkmark
      } else {
        cell.accessoryType = .None
      }
      return cell
    }

    This sets a checkmark on the cell that contains the name of the currently selected game. Small gestures such as these will be appreciated by the users of the app.

    Now add the tableview(tableview:didSelectRowAtIndexPath:) method:

    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
      tableView.deselectRowAtIndexPath(indexPath, animated: true)
     
      //Other row is selected - need to deselect it
      if let index = selectedGameIndex {
        let cell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: index, inSection: 0))
        cell?.accessoryType = .None
      }
     
      selectedGameIndex = indexPath.row
      selectedGame = games[indexPath.row]
     
      //update the checkmark for the current row
      let cell = tableView.cellForRowAtIndexPath(indexPath)
      cell?.accessoryType = .Checkmark
    }

    First this deselects the row after it was tapped. That makes it fade from the gray highlight color back to the regular white. Then it removes the checkmark from the cell that was previously selected, and puts it on the row that was just tapped.

    Run the app now to test that this works. Tap the name of a game and its row will get a checkmark. Tap the name of another game and the checkmark moves along with it.

    Game-picker-checkmark

    The screen ought to close as soon as you tap a row but that doesn’t happen yet because you haven’t actually hooked up an unwind segue. Sounds like a great next step!

    In PlayerDetailsViewController.swift, at the top of the class, add a property to hold the selected game so that you can store it in the Player object later. Give it a default of “Chess” so you always have a game selected for new players.

    var game:String = "Chess"

    In the same file, change viewDidLoad() to display the name of the game in the static table cell:

    override func viewDidLoad() {
      super.viewDidLoad()
      detailLabel.text = game
    }

    Add the unwind segue method:

    @IBAction func selectedGame(segue:UIStoryboardSegue) {
      let gamePickerViewController = segue.sourceViewController as GamePickerViewController
      if let selectedGame = gamePickerViewController.selectedGame {
        detailLabel.text = selectedGame
        game = selectedGame
      }
      self.navigationController?.popViewControllerAnimated(true)
    }

    This code will get executed once the user selects a game from the Choose Game Scene. This method updates both the label on screen and the game property based on the game selected. It also pops the GamePickerViewController off the navigation controller’s stack.

    In Main.storyboard, ctrl-drag from the tableview cell to the Exit as you did before, and choose selectedGame: from the popup list:

    18_sb2_unwind_game

    Give the unwind segue the name “SaveSelectedGame”.

    Run the app to check it out so far. Create a new player, select the player’s game row and choose a game.

    19_sb2_selectedGame

    Unfortunately, the unwind segue method is performed before the tableView(_:didSelectRowAtIndexPath:) method, so that the selectedGameIndex is not updated in time. Fortunately, you can override prepareForSegue(_:sender:) and complete that operation before the unwind happens.

    In GamePickerViewController, add the prepareForSegue(segue:) method:

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
      if segue.identifier == "SaveSelectedGame" {
        let cell = sender as UITableViewCell
        let indexPath = tableView.indexPathForCell(cell)
        selectedGameIndex = indexPath?.row
        if let index = selectedGameIndex {
          selectedGame = games[index]
        }
      }
    }

    The sender parameter of prepareForSegue(_:sender:) is the object that initiated the segue, which in this case was the game cell that was selected. So you can use that cell’s indexPath to locate the selected game in the games array then set selectedGame so it is available in the unwind segue.

    Now when you run the app and select the game, it will update the player’s game details!

    20_sb2_it_works

    Next, you need to change the PlayerDetailsViewController’s prepareForSegue method to return the selected game, rather than the hardcoded “Chess”. This way, when you complete adding a new player, their actual game will be displayed on the Players scene.

    In PlayerDetailsViewController.swift, change prepareForSegue(_:sender:) to this:

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
      if segue.identifier == "SavePlayerDetail" {
        player = Player(name: nameTextField.text, game:game, rating: 1)
      }
    }

    When you complete the Add Player screen and press done, the list of players will now update with the correct game.

    One more thing – when you choose a game, return to the Add Player screen, then try to choose a game again, the game you chose before should have a checkmark by it. The solution is to pass the selected game stored in PlayerDetailsViewController over to the GamePickerViewController when you segue.

    Still in PlayerDetailsViewController.swift, add this to the end of that prepareForSegue(segue:,sender:) method:

    if segue.identifier == "PickGame" {
      let gamePickerViewController = segue.destinationViewController as GamePickerViewController
      gamePickerViewController.selectedGame = game
    }

    Note that you now have two if statements checking segue.identifier. SavePlayerDetail is the unwind segue going back to the Players list, and PickGame is the push segue going forwards to the Game Picker screen. The code you added will set the selectedGame on the GamePickerViewController just before that view is loaded.

    Now open GamePickerViewController.swift and add the following lines to the bottom of viewDidLoad():

    if let game = selectedGame {
      selectedGameIndex = find(games, game)!
    }

    This takes the selectedGame you passed in from the PlayerDetailsViewController and translates it to an index that will be used to place a checkmark on that game. The find() will search the games array for a String matching selectedGame and will set the selectedGameIndex to the index where the match was found. You’ll use that index to set a checkmark in the table view cell.

    Awesome. You now have a functioning Choose Game screen!

    Marin-Danger

    Where To Go From Here?

    Here is the final Ratings iOS 8 example project with all of the code from the above tutorial.

    Congratulations, you now know the basics of using the Storyboard Editor, and can create apps with multiple view controllers transitioning between each other with segues! Editing multiple view controllers and their connections to each other in one place makes it easy to visualize your app as a whole.

    You’ve also seen how easy it is to customize table views and table view cells. Static cells also make it easy to set up an interface without implementing all the data source methods.

    If you want to learn more about Storyboards, check out our book iOS 8 by Tutorials, where you’ll find the latest on universal storyboards.

    If you have any questions or comments on this tutorial or on storyboards in general, please join the forum discussion below!

    Storyboards Tutorial in Swift: Part 2 is a post from: Ray Wenderlich

    The post Storyboards Tutorial in Swift: Part 2 appeared first on Ray Wenderlich.

    Video Tutorial: WatchKit Part 8: Table Actions


    Apple Pay Tutorial

    $
    0
    0
    Learn how to integrate Apple Pay into your application!

    Learn how to integrate Apple Pay into your application!

    Apple took a big step into the world of mobile payments with the introduction of the iPhone 6 and Apple Pay. There are two ways you can use Apple Pay to purchase items: at the point of sale using Near Field Communication (NFC), or within an iOS app.

    Since creating your own NFC payment system wouldn’t go over too well with Apple, this tutorial will instead look at how to integrate Apple Pay into your own iOS apps. This is different from in-app purchases for digital content — Apple Pay lets you sell goods to your users from within an app.

    In this Apple Pay tutorial, you’ll learn how to write an app that lets users buy really cool RayWenderlich.com tutorials and gear using nothing but the convenience of their fingerprints!

    Just in case you’re worried, you won’t incur any real charges on your account by working through the project in this tutorial — so feel free to go on a virtual shopping spree! :]

    Note: You’ll need a paid active Apple developer account to complete this tutorial.

    Getting Started

    Download the starter project for this tutorial; it’s named ApplePaySwag.

    Build and run to make sure the project works out of the box. You should see the startup screen as follows:

    ApplePaySwag startup screen.

    The app as it stands is a simple Master/Detail application that shows a list of RayWenderlich.com “swag” in the master view. Tap on any piece of swag to navigate to a detail view which shows a bigger picture of the swag as well as a more detailed description.

    Here’s a quick overview of the classes and objects contained in the starter project:

    • SwagListViewController: The master view controller that lists the swag available to purchase.
    • BuySwagViewController: The detail view controller that shows details of the swag and lets you purchase the item.
    • Swag: The primary swag model object.
    • SwagCell: A UITableViewCell subclass that displays the list of swag in SwagListViewController.
    • Main.storyboard: The sole storyboard in the app that contains both scenes.

    Feel free to browse through the swag for a moment, but soon you’ll have to tear yourself away and hook this mini-store up to Apple Pay to allow your users to grab some cool gear. Before you jump into the code, there’s a bit of Apple Developer Portal setup work you’ll need to complete first.

    Setting Up Your App for Apple Pay

    Head over to http://developer.apple.com and log in to your developer account. Go to Member Center and click on Certificates, Identifiers & Profiles\Identifiers\App IDs.

    Click on the + button to create a new App ID, name it Apple PaySwag and give it a Bundle ID of the format com.YOURDOMAIN.ApplePaySwag. Make sure that Explicit App ID is selected, as wildcard App IDs aren’t able to make payments with Apple Pay. Finally, check the Apple Pay checkbox under App Services, click Continue and then click Submit to complete the creation of your new App ID.

    Next, click on Merchant IDs under Identifiers in the left navigation pane:

    Merchant ID Locations

    Click + to create a new merchant ID; use whatever description and merchant identifier you’d like. Generally, it’s recommended to create merchant identifiers in the reverse domain style that start with merchant, similar to bundle IDs. Click Continue and then click Register to create your new merchant ID.

    Now that your App ID and merchant ID are set up, head back to Xcode to get your project ready for Apple Pay.

    Select the ApplePaySwag project in the left navigation bar, then select the ApplePaySwag target and change the Bundle Identifier to match the one you created above. Ensure that the Team selection box is pointing to the development team under which you created your App ID and merchant ID.

    Next, click the Capabilities tab. Expand the Apple Pay section and ensure that the switch on the right is set to ON. Then push the refresh button below the merchant ID list; you should see the list populate with the merchant ID you added on the developer portal, if it wasn’t there already.

    Finally, check the checkbox next to your merchant ID; your screen should look like the image below:

    Merchant ID selected

    The three items in the Steps section should all have checkmarks next to them to indicate that you’ve satisfied all of the requirements for using Apply Pay in your app. If one isn’t checked, retrace your steps to make sure you’ve taken care of all the details.

    You now have Apple Pay enabled in your app. Time to get to the fun part — the coding! :]

    Adding the Apple Pay Button

    Open Main.storyboard and take a look at the the Buy Swag scene:

    Buy Swag Scene

    This view has a larger and more prominent picture of the swag, the price, a detailed description of the swag and a basic button to buy the swag. This is where you’ll hook in the magic of Apple Pay!

    You’ll want something more interesting than a simple out-of-the-box button to entice your users to buy. Apple has a very specific set of Apple Pay guidelines to adhere to, which extends to the buttons in your app. Take a few minutes to review these guidelines at the Apple Pay developer site https://developer.apple.com/apple-pay/.

    Note: The Apple Pay Buttons and Resources link at the Apple Pay developer site above provides you with a zip file containing an extensive collection of approved button resources for Apple Pay.

    The Apple Pay Guidelines provide explanations of the allowable modifications you can make to the provided buttons, as well as guidelines on what colors you may choose to provide the best amount of contrast between the button and your view’s background. In general, you are not allowed to create your own button artwork, but can “stretch” the provided artwork to be wider if necessary.

    Since the purpose of this tutorial is not to test your Photoshop skills, you’ll find a set of Apple Pay images ready for use in the starter project’s Image.xcassets.

    Head back to the Buy Swag scene in Interface Builder, select the Apple Pay button and change the image to ApplePaySwagButton. Give your button an empty title instead of the default “button” title. Your scene should now look as follows:

    Scene with Apple Pay Button

    Now that you have an Apple Pay button hooked up to an action method, it’s time to invoke the Apple Pay APIs!

    Creating a Payment Request

    Open BuySwagViewController.swift and add the following import to the top of the file:

    import PassKit

    The Apple Pay classes are actually part of PassKit, so you need that import to do anything useful.

    Next, locate purchase(sender:); you execute this when the user attempts to purchase an item. To do this, you’ll need to create a PKPaymentRequest and a PKPaymentAuthorizationViewController.

    Add the following code to the body of purchase(sender:):

    let request = PKPaymentRequest()
    let applePayController = PKPaymentAuthorizationViewController(paymentRequest: request)
    self.presentViewController(applePayController, animated: true, completion: nil)

    This code creates a simple PKPaymentRequest object that represents a single Apple Pay payment, as well as the creation of a PKPaymentAuthorizationViewController constructed with the PKPaymentRequest instance responsible for displaying the Apple Pay payment sheet. Finally, the BuySwagViewController presents the PKPaymentAuthorizationViewController.

    You’ll need to populate the required elements of PKPaymentRequest next to see your Apple Pay sheet in action.

    Populating PKPaymentRequest

    Add the following code just under the IBOutlet properties of BuySwagViewController:

    let SupportedPaymentNetworks = [PKPaymentNetworkVisa, PKPaymentNetworkMasterCard, PKPaymentNetworkAmex]
    let ApplePaySwagMerchantID = "merchant.com.YOURDOMAIN.ApplePaySwag" // Fill in your merchant ID here!

    SupportedPaymentNetworks defines an array of payment networks you are able to accept. You set these depending on your ability to process each of these payment networks; in this tutorial you’ll accept all three. ApplePaySwagMerchantID is a string that matches the merchant ID you created on the developer portal and set in your app’s Capabilities.

    It would be a good idea to hide the Apple Pay button if the user isn’t able to make payments for some reason, such as parental control settings or not having the right hardware. In that case, you’ll just let them window shop.

    Add the following code to viewDidLoad():

    applePayButton.hidden = !PKPaymentAuthorizationViewController.canMakePaymentsUsingNetworks(SupportedPaymentNetworks)

    canMakePaymentsUsingNetworks returns a Boolean if the user can make payments, so you negate this value with ! to set whether the button should be hidden or not.

    Add the following lines to purchase(sender:), below the point where you instantiate PKPaymentRequest:

    request.merchantIdentifier = ApplePaySwagMerchantID
    request.supportedNetworks = SupportedPaymentNetworks
    request.merchantCapabilities = PKMerchantCapability.Capability3DS
    request.countryCode = "US"
    request.currencyCode = "USD"

    These five fields tell the payment request about the capabilities of your transaction:

    1. merchantIdentifier is your merchant ID. This is used to decrypt the cryptogram on the backend.
    2. supportedNetworks tells the request which networks you support. This affects which of your user’s cards show up in the Apple Pay sheet.
    3. merchantCapabilities is the security standard you want to use. The details of this are outside the scope of this tutorial, but for now you’ll use 3DS which is the most popular standard in the US.
    4. countryCode is the 2-character country code where your transaction takes place. For now, this is set to US as it is the only supported country at the time this tutorial was published; more countries will be available in the future.
    5. currencyCode is the currency of your transaction; since you set countryCode to US, set this to USD.

    Now you’ll add some code specific to the swag that will tell the customer the most important detail of this interaction — how much this swag is going to cost them! :]

    Add the following code below the PKPaymentRequest setup code you just added:

    request.paymentSummaryItems = [
        PKPaymentSummaryItem(label: swag.title, amount: swag.price),
        PKPaymentSummaryItem(label: "Razeware", amount: swag.price)
    ]

    Here, you create an array of PKPaymentSummaryItem objects that provide the user with a breakdown the items they’re purchasing. You might notice that the same price is repeated with different labels. When creating arrays of PKPaymentSummaryItem, the last summary item will be the amount charged and the label will be prepended with the text PAY TO.

    Build and run your app on a physical device; select your swag of choice and press the Apple Pay button. You should see the Apple Pay sheet pop up on the screen like so:

    ApplePay-Lite

    It’s exciting to see that fingerprint icon on the screen! Scan your programmed-finger-of-choice on the touch ID sensor, and remember, your account won’t be charged. Instead, you’ll see the wait spinner spin forever; tap Cancel to exit out of this state.

    Nothing happens here because there’s more interaction you’ll need to handle using a delegate on the PKPaymentAuthorizationViewController named PKPaymentAuthorizationViewControllerDelegate.

    Implementing Delegates to Handle Payment Requests

    In BuySwagViewController.swift, add the following extension to BuySwagViewController that implements PKPaymentAuthorizationViewControllerDelegate:

    extension BuySwagViewController: PKPaymentAuthorizationViewControllerDelegate {
      func paymentAuthorizationViewController(controller: PKPaymentAuthorizationViewController!, didAuthorizePayment payment: PKPayment!, completion: ((PKPaymentAuthorizationStatus) -> Void)!) {
        completion(PKPaymentAuthorizationStatus.Success)
      }
     
      func paymentAuthorizationViewControllerDidFinish(controller: PKPaymentAuthorizationViewController!) {
        controller.dismissViewControllerAnimated(true, completion: nil)
      }
    }

    This implements the two required methods of PKPaymentAuthorizationViewControllerDelegate:

    • paymentAuthorizationViewController(controller:didAuthorizePayment:completion:): This handles the user authorization to complete the purchase.
    • paymentAuthorizationViewControllerDidFinish(controller:): This is called when the payment request completes.

    The PKPayment object holds the Apple Pay authorization token, as well as final shipping, billing, and contact information for the order, which you’ll handle later in this tutorial.

    paymentAuthorizationViewController(controller:didAuthorizePayment:completion:) is where you’ll eventually send the payment request to your backend for processing. This is also why you saw the spinner spin indefinitely. The Apple Pay sheet will remain in place until you invoke the completion handler; this gives you the amount of time you need to complete the transaction. For now though, you simply hardcode the parameter to the completion block with PKPaymentAuthorizationStatus.Success.

    The responsibility of paymentAuthorizationViewControllerDidFinish(controller:), for now, is simply to dismiss the view controller when finished.

    Add the following line to purchase(sender:) right after the creation of your PKPaymentAuthorizationViewController to set its delegate:

    applePayController.delegate = self

    Build and run your project; select a piece of swag and tap the Apple Pay button one more time. Scan your finger on the Touch ID and… darn, an error alert!

    Not Available

    You thought you had everything set up properly for Apple Pay — so why the error?

    Your app is not currently permitted to use Apple Pay because you haven’t yet added a certificate from your payment provider — you’ll do that a bit later in the tutorial.

    The Apple Pay sheet you present to the user is fairly simple; it only has a method to select which credit card to use to complete the payment. That’s sufficient for payment purposes — but not enough information for your shipping department to send the user the swag they just purchased! You’ll need to tell PKPaymentRequest what kind of information you require from the user to complete the transaction.

    Handling Shipping, Billing, and Contact Information

    Add the following code to purchase(sender:) just after the rest of your PKPaymentRequest setup code:

    request.requiredShippingAddressFields = PKAddressField.All

    Build and run your project; navigate to the Apple Pay sheet and take a look at all of the details filled out for you:

    Add-shipping-info

    That looks pretty impressive, but part of being a good Apple Pay citizen is to only ask the user for the information that’s absolutely necessary to complete the order.

    In your case, you’ll need the shipping address for any physical swag that needs to be shipped, and possibly a phone number in case something goes wrong with the shipping. For digital items, you’ll just need the email address where to send the product or download link once purchased. The PKAddressField is a bitmask, so you can simply use bitwise OR (the | operator) on the shipping flags you need.

    Modify the code that sets requiredShippingAddressFields as follows:

    switch (swag.swagType) {
      case SwagType.Delivered:
        request.requiredShippingAddressFields = PKAddressField.PostalAddress | PKAddressField.Phone
      case SwagType.Electronic:
        request.requiredShippingAddressFields = PKAddressField.Email
    }

    Build and run your project; select a piece of swag and check out the new, lightweight Apple Pay sheet:

    Only ask for the information you need.

    You’ll also need to add shipping costs to the order — in this case, a flat $5 to keep this part of the project simple.

    Adding Shipping Costs

    Open Swag.swift and add the following code below the property declarations:

    let shippingPrice: NSDecimalNumber = NSDecimalNumber(string: "5.0")

    This sets your shipping price to a fixed nominal amount.

    You now need to calculate the total price; this is the base price of the product plus the shipping cost for physical products only.

    Add the following method to the class:

    func total() -> NSDecimalNumber {
      if (swagType == SwagType.Delivered) {
        return price.decimalNumberByAdding(shippingPrice)
      } else {
        return price
      }
    }

    If this swag item need to be delivered, you add the shipping cost; otherwise, it’s an electronic product and the total price is just the price of the item.

    Finally, go back to BuySwagViewController.swift and modify the creation of your paymentSummaryItems to reflect your new summary item list:

    var summaryItems = [PKPaymentSummaryItem]()
    summaryItems.append(PKPaymentSummaryItem(label: swag.title, amount: swag.price))
     
    if (swag.swagType == .Delivered) {
      summaryItems.append(PKPaymentSummaryItem(label: "Shipping", amount: swag.shippingPrice))
    }
     
    summaryItems.append(PKPaymentSummaryItem(label: "Razeware", amount: swag.total()))
     
    request.paymentSummaryItems = summaryItems

    Build and run your app; select a physical product like a T-shirt and you should see all line items, including shipping, as well as the new calculated total at the bottom. For electronic purchases, such as PDF books, you should see only the price of the book and the total without any shipping costs applied. Leaving out the line item for “shipping” avoids confusing your user when they’re purchasing a downloadable product.

    address-noaddress

    Now that shipping addresses show up in the Apple Pay sheet for delivered items, you’ll need to manage changes to the shipping address.

    Responding to Changes in the Shipping Address

    Add the following code to the BuySwagViewController extension:

    func paymentAuthorizationViewController(controller: PKPaymentAuthorizationViewController!, didSelectShippingAddress address: ABRecord!, completion: ((status: PKPaymentAuthorizationStatus, shippingMethods: [AnyObject]!, summaryItems: [AnyObject]!) -> Void)!) {
        completion(status: PKPaymentAuthorizationStatus.Success, shippingMethods: nil, summaryItems: nil)
    }

    This delegate method works much like paymentAuthorizationViewController(controller:payment:completion:) as it lets long-running tasks complete due to address or shipping changes made on the Apple Pay sheet. In real-world apps, you might make a service call to calculate sales tax, determine if you can ship to the new address, or if it is even a real address at all!

    The callback has two additional parameters:

    • shippingMethods: An updated list of shipping methods applicable to this address — you’ll deal with this a bit later in the tutorial.
    • summaryItems: An updated list of summary items based on the new address, such as appropriate tax amounts for the selected state.

    You can pass nil for any of these callback parameters, which results in no changes to that field. If the new address resulted in new shipping methods or additional tax, then you would pass those new values into the callback.

    You’ll notice that the address supplied is an AddressBook of type ABAddress. It will take a bit of work to convert this to something your app can use.

    Create a new Swift file, name it Address.swift and add the following struct definition to the file:

    struct Address {
      var Street: String?
      var City: String?
      var State: String?
      var Zip: String?
      var FirstName: String?
      var LastName: String?
     
      init() {
      }
    }

    This Address struct will store your address information.

    Head back to BuySwagViewController.swift and add the following method:

    func createShippingAddressFromRef(address: ABRecord!) -> Address {
      var shippingAddress: Address = Address()
     
      shippingAddress.FirstName = ABRecordCopyValue(address, kABPersonFirstNameProperty)?.takeRetainedValue() as? String
      shippingAddress.LastName = ABRecordCopyValue(address, kABPersonLastNameProperty)?.takeRetainedValue() as? String
     
      let addressProperty : ABMultiValueRef = ABRecordCopyValue(address, kABPersonAddressProperty).takeUnretainedValue() as ABMultiValueRef
      if let dict : NSDictionary = ABMultiValueCopyValueAtIndex(addressProperty, 0).takeUnretainedValue() as? NSDictionary {
        shippingAddress.Street = dict[String(kABPersonAddressStreetKey)] as? String
        shippingAddress.City = dict[String(kABPersonAddressCityKey)] as? String
        shippingAddress.State = dict[String(kABPersonAddressStateKey)] as? String
        shippingAddress.Zip = dict[String(kABPersonAddressZIPKey)] as? String
      }
     
      return shippingAddress
    }

    This does the heavy lifting of moving data from an ABRecord into the Address struct. If you’re unfamiliar with AddressBook, check out the Address Book Tutorial in iOS on our site to help get you up to speed.

    The Apple Pay address book is pretty relaxed in what information it requires for an address, so you’ll have to make sure you have all the information you need.

    Find the empty implementation of paymentAuthorizationViewController(controller:didSelectShippingAddress:completion:) you added earlier, and add the following code:

    let shippingAddress = createShippingAddressFromRef(address)
     
    switch (shippingAddress.State, shippingAddress.City, shippingAddress.Zip) {
      case (.Some(let state), .Some(let city), .Some(let zip)):
        completion(status: PKPaymentAuthorizationStatus.Success, shippingMethods: nil, summaryItems: nil)
      default:
        completion(status: PKPaymentAuthorizationStatus.InvalidShippingPostalAddress, shippingMethods: nil, summaryItems: nil)
    }

    This tests whether the city, state and ZIP values are valid. If so, you call the completion handler with the .Success status; otherwise, you use the .InvalidShippingPostalAddress and Apple Pay will prompt the user to fix the invalid field.

    Build and run your app; create a new address without a ZIP code in your Apple Pay address book and watch what happens when you invoke the InvalidShippingPostalAddress callback:

    bad-address

    The address field turns red which indicates to the user that they’ve missed a required detail in their shipping address.

    Note: If you put a breakpoint after the call to createShippingAddressFromRef(address:), you’ll notice that even though the selected address might have all the information you asked for, only City, State, and Zip are populated.

    This is a privacy feature of Apple Pay; you only have access to all the user’s information after they authorize the payment. The basic information available to you before authorization should be sufficient to determine if you can ship to this location, and how much tax to apply.

    Now you have a near-fully functional Apple Pay app! Although a flat-fee shipping makes the decision easier for your users, what if they want that cool shirt right now? You can be an awesome digital storekeeper and give them an option to get it delivered sooner.

    Adding Variable Shipping Costs

    Open Swag.swift and add the following struct to the top of the file:

    struct ShippingMethod {
      let price: NSDecimalNumber
      let title: String
      let description: String
     
      init(price: NSDecimalNumber, title: String, description: String) {
        self.price = price
        self.title = title
        self.description = description
      }
     
      static let ShippingMethodOptions = [
        ShippingMethod(price: NSDecimalNumber(string: "5.00"), title: "Carrier Pigeon", description: "You'll get it someday."),
        ShippingMethod(price: NSDecimalNumber(string: "100.00"), title: "Racecar", description: "Vrrrroom! Get it by tomorrow!"),
        ShippingMethod(price: NSDecimalNumber(string: "9000000.00"), title: "Rocket Ship", description: "Look out your window!"),
      ]
    }

    This creates a ShippingMethod struct that includes the price, title, and a description of the shipping method. It also defines the set of shipping methods you offer — unfortunately, your users now know why you are able to offer $5 shipping! :]

    Modify the SwagType enum as shown below:

    enum SwagType {
      case Delivered(method: ShippingMethod)
      case Electronic
    }

    Your enum now includes an associated value of type ShippingMethod with SwagType.Delivered.

    Now that you have a non-fixed shipping price and an associated value, delete the hardcoded shippingPrice in the Swag struct and modify the total() method as shown below:

    func total() -> NSDecimalNumber {
      switch (swagType) {
      case .Delivered(let swagType):
        return price.decimalNumberByAdding(swagType.method.price)
      case .Electronic:
        return price
      }
    }

    Now open up SwagListViewController.swift and initialize every SwagType.Delivered enum in the swagList declaration with the cheapest ShippingMode value:

    SwagType.Delivered(method: ShippingMethod.ShippingMethodOptions.first!)

    Open BuySwagViewController.swift and update the purchase(sender:) method as follows:

    switch (swag.swagType) {
    case .Delivered(let method):
      summaryItems.append(PKPaymentSummaryItem(label: "Shipping", amount: method.method.price))
    case .Electronic:
      break
    }

    This adds the shipping line item to reflect the new associated shipping values.

    Finally, replace the switch statement in the same method that determines the requiredShippingAddressFields with the following:

    switch (swag.swagType) {
    case .Delivered(let method):
      var shippingMethods = [PKShippingMethod]()
     
      for shippingMethod in ShippingMethod.ShippingMethodOptions {
        let method = PKShippingMethod(label: shippingMethod.title, amount: shippingMethod.price)
        method.identifier = shippingMethod.title
        method.detail = shippingMethod.description
        shippingMethods.append(method)
      }
     
      request.shippingMethods = shippingMethods
    case .Electronic:
      break
    }

    This code iterates through the available shipping methods and creates an instance of PKShippingMethod for each one. The title, price, and detail will all be visible on the Apple Pay sheet, while the identifier will be used later to reference the selected shipping method.

    Notice that you only set the shippingMethods property if you have PKShippingMethods to add to it. The Apple Pay APIs can be very finicky and fail if you don’t add anything to the shippingMethods array.

    Build and run your app; select a deliverable physical item to see your new shipping methods in action:

    full-shipping-with-method

    Each shipping method has an associated shipping cost, so you’ll want to update the line items and total price when the user selects a new shipping method. Fortunately, this is very similar to the way you handled the selection of shipping addresses earlier.

    Responding to Changes in the Shipping Method

    Add the following code to your BuySwagViewController extension:

    func paymentAuthorizationViewController(controller: PKPaymentAuthorizationViewController!, didSelectShippingMethod shippingMethod: PKShippingMethod!, completion: ((PKPaymentAuthorizationStatus, [AnyObject]!) -> Void)!) {
      let shippingMethod = ShippingMethod.ShippingMethodOptions.filter {(method) in method.title == shippingMethod.identifier}.first!
      swag.swagType = SwagType.Delivered(method: shippingMethod)
      completion(PKPaymentAuthorizationStatus.Success, nil)
    }

    In the above method, you determine which delivery method is selected by matching the title with the identifier. The SwagType is set to Delivered, which is associated with the newly selected ShippingMethod.

    For the time being, you invoke the callback with nil. This means the shipping method will update, but the line items and total won’t update. For this to happen, you’ll need to re-calculate the summary items.

    Break out the code from purchase(sender:) that builds the summary items into a new method and call it calculateSummaryItemsFromSwag(swag:):

    func calculateSummaryItemsFromSwag(swag: Swag) -> [PKPaymentSummaryItem] {
      var summaryItems = [PKPaymentSummaryItem]()
      summaryItems.append(PKPaymentSummaryItem(label: swag.title, amount: swag.price))
     
      switch (swag.swagType) {
      case .Delivered(let method):
        summaryItems.append(PKPaymentSummaryItem(label: "Shipping", amount: method.method.price))
      case .Electronic:
        break
      }
     
      summaryItems.append(PKPaymentSummaryItem(label: "Razeware", amount: swag.total()))
     
      return summaryItems
    }

    Don’t forget to remove the old code, and modify purchase(sender:) to call your new method as follows:

    request.paymentSummaryItems = calculateSummaryItemsFromSwag(swag)

    Finally, replace the call to the completion handler at the end of paymentAuthorizationViewController(controller:, didSelectShippingMethod:, completion:) with the following:

    completion(PKPaymentAuthorizationStatus.Success, calculateSummaryItemsFromSwag(swag))

    Here you simply pass the re-calculated totals as part of signalling a successful payment.

    Build and run your app; tap any physical item to see your new shipping choices and totals in action. Now you can have your set of RayWenderlich.com stickers sent to your door via rocketship! Let’s hope you have a landing pad in your front yard! :]

    Fulfilling Payment Transactions

    Now that you have a fully functional Apple Pay sheet, you’ll want to request that these charges be fulfilled. Apple Pay, of course, doesn’t fulfill payment transactions; it only only authorizes transactions and creates tokens that allow payments to be processed.

    To process transactions, you’ll use the online payment processor Stripe. One of the nice things about Stripe, besides being easy to set up, is that it comes with a built-in test payment environment so you can easily test purchases in your app without incurring real charges — which is important when selecting the “Rocket Ship” shipping method! :]

    Note:This section is meant to demonstrate the server side of completing an Apple Pay transaction. To follow this portion of the tutorial, sign up for a free Stripe account at www.stripe.com.

    Depending on your situation, your company may already process payments using existing systems other than Stripe. In that case, you can still follow along with this section, but you might have slightly different ways of managing Certificate Signing Requests and private keys.

    Generating Apple Pay Certificates

    The first things you’ll need to do after creating your Stripe account is to tell Stripe about your app and generate a certificate using a Certificate Signing Request, or CSR provided by Stripe.

    Head to the Apple Pay section of your Stripe account at https://dashboard.stripe.com/account/apple_pay. Press Create New Certificate to download a .certSigningRequest file.

    Uploaded Stripe certificate

    Now go to your developer portal and navigate to Member Center\Certificates, Identifiers & Profiles\Identifier\Merchant IDs. Select your app’s merchant ID and click Edit.
    Navigate to Create Certificate\Continue\Choose File, select the .certSigningRequest you downloaded from Stripe and then click Generate. Click Download to receive your .cer file.

    Go back to Stripe, in the Apple Pay section where you created the CSR and upload your new certificate file. Click on the API Keys section of your account; record the Test Secret Key and Test Publishable Key for use later in your app. These test keys will let you to make “fake” payments from Apple Pay — use the live ones at your own risk! :]

    You’re all set to send payment requests with your merchant ID to Stripe to be decrypted and processed.

    Right now your app isn’t doing anything other than invoking a successful completion handler in paymentAuthorizationViewController(controller:, didAuthorizePayment:, completion:) when the user authorizes a payment.

    Your task is to take the authorization token and send it to Stripe for processing. This consists of three steps:

    1. Send the authorization token via the PKPayment object to Stripe for decryption. If successful, Stripe returns their own “Stripe” token.
    2. Send the Stripe token to a server of your own to let your backend know about the order and perform any necessary processing.
    3. Sending the Stripe token back to Stripe to trigger the charge.

    Creating a Basic Order Management Server

    For any app that uses Apple Pay, you’ll likely have a corresponding backend to handle the actual order fulfillment. For this tutorial, you’ll create a lightweight server to receive payment requests from your app and send them to Stripe for processing.

    Stripe provides several libraries you can find on their website to help creating your payment request. For now, you’ll create a single-file Python server using the lightweight Python REST framework Flask along with the Stripe Python SDK.

    First, you’ll need pip, which is a command-line utility for installing python packages. If you don’t have pip installed, you can install it by following the instructions found here.

    Next, open Terminal and use pip to install Flask by entering the following command:

    sudo pip install Flask

    Next, install the Python Stripe library with the following command:

    sudo pip install --index-url https://code.stripe.com --upgrade stripe

    Next, use a text editor to create a file called ApplePaySwagServer.py. You can place this in the same directory as your Xcode project, if you like.

    In your text editor of choice, add the following code:

    import stripe
    from flask import Flask
    from flask import request
    from flask import json
     
    app = Flask(__name__)
     
    #1
    @app.route('/pay', methods=['POST'])
    def pay():
     
      #2
      # Set this to your Stripe secret key (use your test key!)
      stripe.api_key = "sk_test_YOUR_TEST_KEY_HERE"
     
      #3
      # Parse the request as JSON
      json = request.get_json(force=True)
     
      # Get the credit card details
      token = json['stripeToken']
      amount = json['amount']
      description = json['description']
     
      # Create the charge on Stripe's servers - this will charge the user's card
      try:
        #4
        charge = stripe.Charge.create(
    				  amount=amount,
    				  currency="usd",
    				  card=token,
    				  description=description
    			          )
      except stripe.CardError, e:
        # The card has been declined
        pass
     
      #5
        return "Success!"
     
    if __name__ == '__main__':
      # Set as 0.0.0.0 to be accessible outside your local machine
      app.run(debug=True, host= '0.0.0.0')

    Following the numbered comments above, here’s what the code does:

    1. Creates a “route” that accepts an HTTP POST at /pay.
    2. Sets your Stripe Secret Key. Make sure you use your own Secret Key!
    3. Parses the JSON request.
    4. Creates a charge using the Stripe Python SDK. The amount is measured in cents.
    5. Returns the string Success back to your app.

    Start your the server by executing the Python script in Terminal:

    python ApplePaySwagServer.py

    You’ll know it’s running when you see something like the following in your console:

     * Running on http://0.0.0.0:5000/
     * Restarting with reloader

    Of course, knowing the ins and outs of Python and Flask are not important to learning Apple Pay, but the mini-server you created above helps demonstrate the role your own backend server plays with Apple Pay. In your real-world app, you’d likely add the customer’s order, along with the requisite shipping address, product IDs, and other order information, to a database so the order could be fulfilled.

    Integrating the Stripe Apple Pay SDK

    Now that you have a lightweight server to accept payments, you just need to send them from your app!

    Stripe provides an iOS framework available on GitHub that does most of the heavy lifting for you; the best way to manage this framework is through CocoaPods.

    Note: If you aren’t familiar with CocoaPods, check out the Introduction to CocoaPods tutorial on our site for more information.

    Create a file in the same directory as your .xcodeproj file and name it Podfile.

    Open Podfile and add the following line to declare the Stripe Apple Pay library as a dependency:

    pod 'Stripe/ApplePay'

    Next, open Terminal and navigate to the directory containing your Podfile.

    Run the following command to bring in the Stripe SDK:

    pod install

    As always with CocoaPods, ensure you close your project in Xcode and re-open it using .xcworspace instead of the .xcodeproj

    You’ll also need to add a simple preprocessor symbol to your project to enable Apple Pay within the Stripe SDK.

    In the project navigator, navigate to ApplePaySwag project\ApplePaySwag target\Build Settings and add the string STRIPE_ENABLE_APPLEPAY to both Debug and Release under Preprocessor Macros, as shown below:

    Preprocessor macro for Stripe

    Since the Stripe SDK is written in Objective-C, you’ll need to create a bridging header to use in your Swift code.

    In the project navigator, right-click on the root ApplePaySwag folder and select New File. Select iOS\Source\Header File to create a bridging file and name it ApplePaySwag-Bridging-Header.h.

    Under your project / target settings, set the path of the Objective-C Bridging Header to ApplePaySwag/ApplePaySwag-Bridging-Header.h as shown below:

    Bridging header.

    Now open ApplePaySwag-Bridging-Header.h and replace its contents with the following import:

    #import <Stripe/Stripe.h>
    #import <Stripe/Stripe+ApplePay.h>

    The Stripe APIs will now be available to your Swift code.

    Open BuySwagViewController.swift and replace the hardcoded PKPaymentAuthorizationStatus.Success in paymentAuthorizationViewController(controller:,didAuthorizePayment:completion) with the following code:

    // 1
    let shippingAddress = self.createShippingAddressFromRef(payment.shippingAddress)
     
    // 2
    Stripe.setDefaultPublishableKey("pk_test_YOUR_API_KEY")  // Replace With Your Own Key!
     
    // 3
    Stripe.createTokenWithPayment(payment) {
      (token, error) -> Void in
     
      if (error != nil) {
        println(error)
        completion(PKPaymentAuthorizationStatus.Failure)
        return
      }
     
      // 4
      let shippingAddress = self.createShippingAddressFromRef(payment.shippingAddress)
     
      // 5
      let url = NSURL(string: "http://<your ip address>/pay")  // Replace with computers local IP Address!
      let request = NSMutableURLRequest(URL: url!)
      request.HTTPMethod = "POST"
      request.setValue("application/json", forHTTPHeaderField: "Content-Type")
      request.setValue("application/json", forHTTPHeaderField: "Accept")
     
      // 6
      let body = ["stripeToken": token.tokenId,
                   "amount": self.swag!.total().decimalNumberByMultiplyingBy(NSDecimalNumber(string: "100")),
                    "description": self.swag!.title,
                    "shipping": [
                         "city": shippingAddress.City!,
                         "state": shippingAddress.State!,
                         "zip": shippingAddress.Zip!,
                         "firstName": shippingAddress.FirstName!,
                         "lastName": shippingAddress.LastName!]
      ]
     
      var error: NSError?
      request.HTTPBody = NSJSONSerialization.dataWithJSONObject(body, options: NSJSONWritingOptions(), error: &error)
     
      // 7
      NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) { (response, data, error) -> Void in
        if (error != nil) {
          completion(PKPaymentAuthorizationStatus.Failure)
        } else {
          completion(PKPaymentAuthorizationStatus.Success)
        }
      }
    }

    This modified authorization uses the Stripe SDK to convert a PKPayment object into an STPToken object by sending the PKPayment to Stripe’s servers for decryption. You can then send the returned STPToken object to your server.

    If everything goes well, you invoke your completion block with PKPaymentAuthorizationStatus.Success. If you encounter an issue such as a network error, you simply return PKPaymentAuthorizationStatus.Failure.

    Here’s a more detailed look at the code above, comment by comment:

    1. Grab and parse the final shipping address information from PKPayment. This will give you all the information from the selected address.
    2. Set the publishable Stripe key for your app in the Stripe SDK. Make sure to replace the key above with your own publishable key.
    3. Invoke the Stripe API with the authorized Apple Pay token, which sends the token to Stripe. You invoke a completion block when this action completes; if successful, this returns an STPToken.
    4. Create an Address struct from the final shippingAddress for the final payment amount.
    5. Build an NSMutableRequest to invoke a POST call to the /pay URL. Ensure you replace the IP above with your own server’s IP. This is your computer’s IP on your network, followed by the port listed from your Python server, such as http://192.168.1.18:5000/pay. For this to work, your iOS device and your Mac need to be on the same network.
    6. Construct the JSON for the request. This includes the token property of STPToken to be sent to Stripe, the amount, and the description — in this case, the title of the ordered swag. In a real-life scenario, you might also include things such as product IDs in your app so your server knows which item or items were ordered.
    7. Send the request to the server. You invoke the completion block with success or failure depending on the error result.

    Build and run your app one last time; order all the swag you want and have it sent to your address via race car. The rocket ship option is certainly tempting, but it’s a bit of a spoiler that that the amount is over Stripe’s limit — and probably that of your credit card as well! :]

    Finally, head to your Stripe dashboard at https://dashboard.stripe.com/test/dashboard and set the Live/Test switch to Test. You should now see all of your “fake” transactions in your dashboard:

    w00t, money!

    W00t — look at all that money! Well, it’s fake money, but it still looks impressive. :]

    Where to Go From Here?

    You can download the final project source here.

    You’ve successfully created a fully functional app — and server! — capable of making payments using Apple Pay. Along the way, you’ve learned a lot about the various frameworks, libraries and APIs involved in payment transactions.

    If you’d like to read more in depth on Apple Pay, you can check out the developer site at https://developer.apple.com/apple-pay/. The site also has a list of the other payment platforms other than Stripe that support Apple Pay.

    There are many other features of Apple Pay that you could challenge yourself to add to your app:

    • Calculate sales tax on the server and update the tax amount in summaryItems.
    • Change the available shipping methods based on the ZIP code.
    • Read the order information on the server and verify that the address is valid as a shipping destination.
    • Store products, shipping methods, and prices for each product on the server instead of hardcoded into your app.
    • Create your own customized Apple Pay button by following the Apple Pay guidelines.

    I hope you enjoyed this tutorial; Apple Pay is one of the best new features of iOS 8 and you can bet it will be a popular way to perform online financial transactions. If you have any questions or comments on this tutorial or Apple Pay, feel free to join the discussion below!

    Apple Pay Tutorial is a post from: Ray Wenderlich

    The post Apple Pay Tutorial appeared first on Ray Wenderlich.

    Video Tutorial: WatchKit Part 9: Context Menus

    Metal with Warren Moore – Podcast S02 E09

    $
    0
    0
    Learn about Metal with Warren Moore!

    Learn about Metal with Warren Moore!

    Welcome back to season 2 of the raywenderlich.com podcast!

    We hope you’ve been enjoying the new weekly format of the podcast so far. There’s only 1 episodes left in season 2!

    In this episode, we talk with Warren Moore, author of the upcoming book Metal by Example, to take a deep dive into Metal, Apple’s new API for GPU-accelerated 3D graphics.

    [Subscribe in iTunes] [RSS Feed]

    Our Sponsor

    • Mandrill: Mandrill is a scalable, reliable, and secure email infrastructure service from the folks at MailChimp. Sign up with promo code ray, and you’ll receive 50,000 free email sends per month for your first six months of service!

    Interested in sponsoring a podcast episode? We sell ads via Syndicate Ads, check it out!

    Links and References

    Contact Us

    Where To Go From Here?

    We hope you enjoyed this episode of our podcast. Stay tuned for a new episode next week! :]

    Be sure to subscribe in iTunes to get access as soon as it comes out!

    We’d love to hear what you think about the podcast, and any suggestions on what you’d like to hear in future episodes. Feel free to drop a comment here, or email us anytime at podcast@raywenderlich.com!

    Metal with Warren Moore – Podcast S02 E09 is a post from: Ray Wenderlich

    The post Metal with Warren Moore – Podcast S02 E09 appeared first on Ray Wenderlich.

    Reminder: Free Live Tech Talk (The Great CALayer Tour) Tomorrow (Tuesday)!

    $
    0
    0
    Free live tech talk (The Great CALayer Tour) tomorrow!

    Free live tech talk (The Great CALayer Tour) tomorrow!

    This is a reminder that we are having a free live tech talk on “The Great CALayer Tour” tomorrow (Tuesday Dec 9), and you’re all invited! Here are the details:

    • When: Tuesday, Dec 9 at 2:00 PM EST – 3:00 PM EST
    • What: “The Great CALayer Tour” Tech Talk/Demo followed by live Q&A (come w/ questions!)
    • Who: Scott Gardner (Tutorial Team member)
    • Where: Google Hangouts Event Page
    • Why: For learning and fun!
    • How: Visit the event page and a video URL should be posted. Follow the instructions there to submit your Q&A (via text) as the talk runs.

    We hope to see some of you at the tech talk, and we hope you enjoy!

    Reminder: Free Live Tech Talk (The Great CALayer Tour) Tomorrow (Tuesday)! is a post from: Ray Wenderlich

    The post Reminder: Free Live Tech Talk (The Great CALayer Tour) Tomorrow (Tuesday)! appeared first on Ray Wenderlich.

    Video Tutorial: WatchKit Part 10: Page-Based Interfaces I

    The iOS Apprentice Updated for Xcode 6.1.1

    $
    0
    0
    The iOS Apprentice Updated for Xcode 6.1!

    The iOS Apprentice Updated for Xcode 6.1!

    Good news – Matthijs Hollemans has updated The iOS Apprentice Series yet again – for Xcode 6.1.1!

    Xcode 6.1.1 changed UITableViewCell‘s textLabel and imageView to regular optionals (i.e. ?) rather than the former implicitly unwrapped optionals (i.e. !), so they now require unwrapping with ! or if let.

    This change was confusing to beginners, so Matthijs made this minor update so everything still works OK.

    Here’s how you can get the update:

    • If you’re an iOS Apprentice PDF customer, you can download the update for free on your My Loot page (version 3.2).
    • If you haven’t picked up a copy of the iOS Apprentice yet, grab your copy now.

    Matthijs and I hope you enjoy this update!

    The iOS Apprentice Updated for Xcode 6.1.1 is a post from: Ray Wenderlich

    The post The iOS Apprentice Updated for Xcode 6.1.1 appeared first on Ray Wenderlich.

    Introducing iOS Design Patterns in Swift – Part 1/2

    $
    0
    0

    Update note: This tutorial was updated for iOS 8 and Swift by Vincent Ngo. Original post by Tutorial team member Eli Ganem.

    iOS Design Patterns – you’ve probably heard the term, but do you know what it means? While most developers probably agree that design patterns are very important, there aren’t many articles on the subject and we developers sometimes don’t pay too much attention to design patterns while writing code.

    Design patterns are reusable solutions to common problems in software design. They’re templates designed to help you write code that’s easy to understand and reuse. They also help you create loosely coupled code so that you can change or replace components in your code without too much of a hassle.

    If you’re new to design patterns, then I have good news for you! First, you’re already using tons of iOS design patterns thanks to the way Cocoa is built and the best practices you’re encouraged to use. Second, this tutorial will bring you up to speed on all the major (and not so major) iOS design patterns that are commonly used in Cocoa.

    In this two-part tutorial, you will create a Music Library app that will display your albums and their relevant information.

    In the process of developing this app, you’ll become acquainted with the most common Cocoa design patterns:

    • Creational: Singleton.
    • Structural: MVC, Decorator, Adapter, Facade.
    • Behavioral: Observer, and, Memento

    Don’t be misled into thinking that this is an article about theory; you’ll get to use most of these design patterns in your music app. Your app will look like this by the end of the tutorial:

    swiftDesignPattern1

    Let’s get started!

    Getting Started

    Download the starter project, extract the contents of the ZIP file, and open BlueLibrarySwift.xcodeproj in Xcode.

    There are three things to note in the project:

    1. The ViewController has two IBOutlet connecting the table view and toolbar in storyboard.
    2. The storyboard has 3 components which are setup with constraints for your convenience. The top component is where the album covers will be displayed. Below the album covers will be a table view which list information related to an album cover. Lastly the tool bar has two buttons, one to undo an action and another to delete an album that you select. The storyboard is shown below: swiftDesignPatternStoryboard
    3. A starter HTTP Client class (HTTPClient) with an empty implementation for you to fill in later.

    Note: Did you know that as soon as you create a new Xcode project your code is already filled with design patterns? Model-View-Controller, Delegate, Protocol, Singleton – You get them all for free! :]

    Before you dive into the first design pattern, you must create two classes to hold and display the album data.

    Navigate to “File\New\File…” (or simply press Command+N). Select iOS > Cocoa Touch Class and then click Next. Set the class name to Album and the subclass to NSObject. Lastly choose Swift as the language. Click Next and then Create.

    Open Album.swift and add the following properties to the class definition:

    var title : String!
    var artist : String!
    var genre : String!
    var coverUrl : String!
    var year : String!

    Here you create five properties. The Album class will keep track of the title, artist, genre, album cover, and the year of the album.
    Next add the following object initializer after the properties:

    init(title: String, artist: String, genre: String, coverUrl: String, year: String) {
      super.init()
     
      self.title = title
      self.artist = artist
      self.genre = genre
      self.coverUrl = coverUrl
      self.year = year
    }

    This code creates an initializer for the Album class. When you create a new album, you’ll pass in the album name, the artist, the genre, the album cover URL, and the year.

    Next add the following method:

    func description() -> String {
      return "title: \(title)" +
       "artist: \(artist)" +
       "genre: \(genre)" +
       "coverUrl: \(coverUrl)" +
       "year: \(year)"
    }

    The method description() returns a string representation of the album’s attributes.

    Again, navigate to File\New\File…. Select Cocoa Touch Class and then click Next. Set the class name to AlbumView, but this time set the subclass to UIView. Make sure the language is set to Swift and then click Next and then Create.

    Open AlbumView.swift and add the following properties inside the class definition:

    private let coverImage: UIImageView! 
    private let indicator: UIActivityIndicatorView!

    The coverImage represents the album cover image. The second property is an indicator that spins to indicate activity while the cover is being downloaded.

    The properties are marked as private because no class outside AlbumView needs to know of the existence of these properties; they are used only in the implementation of the class’s internal functionality. This convention is extremely important if you’re creating a library or framework for other developers to use to keep private state information private.

    Next, add the initializers to the class:

    required init(coder aDecoder: NSCoder) {
      super.init(coder: aDecoder)
    }
     
    init(frame: CGRect, albumCover: String) {
      super.init(frame: frame)
      backgroundColor = UIColor.blackColor()
      coverImage = UIImageView(frame: CGRectMake(5, 5, frame.size.width - 10, frame.size.height - 10))
      addSubview(coverImage)
      indicator = UIActivityIndicatorView()
      indicator.center = center
      indicator.activityIndicatorViewStyle = .WhiteLarge
      indicator.startAnimating()
      addSubview(indicator)
    }

    The NSCoder initializer is required because UIView conforms to NSCoding. You have no reason to encode or decode instances of your AlbumView in this app, so you can just leave this be, calling it’s super init.

    In “real” initializer that you’ll use in the rest of the app, you set some nice defaults for the album view. You set the background to black, create the image view with a small margin of 5 pixels and create and add the activity indicator.

    Finally, add the following method:

    func highlightAlbum(#didHighlightView: Bool) {
      if didHighlightView == true {
        backgroundColor = UIColor.whiteColor()
      } else {
        backgroundColor = UIColor.blackColor()
      }
    }

    This will toggle the album’s background color to white if it’s highlighted, and black when it’s not.

    Build your project (Command+B) just to make sure everything is in order. All good? Then get ready for your first design pattern! :]

    MVC – The King of Design Patterns

    mvcking

    Model-View-Controller (MVC) is one of the building blocks of Cocoa and is undoubtedly the most-used design pattern of all. It classifies objects according to their general role in your application and encourages clean separation of code based on role.

    The three roles are:

    • Model: The object that holds your application data and defines how to manipulate it. For example, in your application the Model is your Album class.
    • View: The objects that are in charge of the visual representation of the Model and the controls the user can interact with; basically, all the UIView-derived objects. In your application the View is represented by your AlbumView class.
    • Controller: The controller is the mediator that coordinates all the work. It accesses the data from the model and displays it with the views, listens to events and manipulates the data as necessary. Can you guess which class is your controller? That’s right: ViewController.

    A good implementation of this design pattern in your application means that each object falls into one of these groups.

    The communication between View to Model through Controller can be best described with the following diagram:

    mvc0

    The Model notifies the Controller of any data changes, and in turn, the Controller updates the data in the Views. The View can then notify the Controller of actions the user performed and the Controller will either update the Model if necessary or retrieve any requested data.

    You might be wondering why you can’t just ditch the Controller, and implement the View and Model in the same class, as that seems a lot easier.

    It all comes down to code separation and reusability. Ideally, the View should be completely separated from the Model. If the View doesn’t rely on a specific implementation of the Model, then it can be reused with a different model to present some other data.

    For example, if in the future you’d also like to add movies or books to your library, you could still use the same AlbumView to display your movie and book objects. Furthermore, if you want to create a new project that has something to do with albums, you could simply reuse your Album class, because it’s not dependent on any view. That’s the strength of MVC!

    How to Use the MVC Pattern

    First, you need to ensure that each class in your project is either a Controller, a Model or a View; don’t combine the functionality of two roles in one class. You’ve already done a good job so far by creating an Album class and an AlbumView class.

    Second, in order to ensure that you conform to this method of work you should create three project groups to hold your code, one for each category.

    Navigate to File\New\Group (or press on Command+Option+N) and name the group Model. Repeat the same process to create View and Controller groups.

    Now drag Album.swift to the Model group. Drag AlbumView.swift to the View group, and finally drag ViewController.swift to the Controller group.

    At this point the project structure should look like this:
    swiftDesignPattern2

    Your project already looks a lot better without all those files floating around. Obviously you can have other groups and classes, but the core of the application is contained in these three categories.

    Now that your components are organized, you need to get the album data from somewhere. You’ll create an API class to use throughout your code to manage the data — which presents an opportunity to discuss your next design pattern — the Singleton.

    The Singleton Pattern

    The Singleton design pattern ensures that only one instance exists for a given class and that there’s a global access point to that instance. It usually uses lazy loading to create the single instance when it’s needed the first time.

    Note: Apple uses this approach a lot. For example: NSUserDefaults.standardUserDefaults(), UIApplication.sharedApplication(), UIScreen.mainScreen(), NSFileManager.defaultManager() all return a Singleton object.

    You’re likely wondering why you care if there’s more than one instance of a class floating around. Code and memory is cheap, right?

    There are some cases in which it makes sense to have exactly one instance of a class. For example, there’s only one instance of your application and one main screen for the device, so you only want one instance of each. Or, take a global configuration handler class: it’s easier to implement a thread-safe access to a single shared resource, such as a configuration file, than to have many class modifying the configuration file possibly at the same time.

    How to Use the Singleton Pattern

    Take a look at the diagram below:

    singleton

    The above image shows a Logger class with a single property (which is the single instance), and two methods: sharedInstance and init.

    The first time a client asks for the sharedInstance, the instance property isn’t yet initialized, so you create a new instance of the class and return a reference to it.

    The next time you call sharedInstance, instance is immediately returned without any initialization. This logic ensures that only one instance exists at one time.

    You’ll implement this pattern by creating a singleton class to manage all the album data.

    You’ll notice there’s a group called API in the project; this is where you’ll put all the classes that will provide services to your app. Create a new file inside this group by right-clicking the group and selecting New File. Select iOS > Cocoa Touch Class and then click Next. Set the class name to LibraryAPI, and the subclass to NSObject. Lastly choose Swift as the language. Click Next and then Create.

    Now go to LibraryAPI.swift and insert this code inside the class definition.

    //1
    class var sharedInstance: LibraryAPI {
      //2
      struct Singleton {
        //3
        static let instance = LibraryAPI()
      }
      //4
      return Singleton.instance
    }

    There’s a lot going on in this short method:

    1. Create a class variable as a computed type property. The class variable, like class methods in Objective-C, is something you can call without having to instantiate the class LibraryAPI For more information about type properties please refer to Apple’s Swift documentation on
      properties
    2. Nested within the class variable is a struct called Singleton.
    3. Singleton wraps a static constant variable named instance. Declaring a property as static means this property only exists once. Also note that static properties in Swift are implicitly lazy, which means that Instance is not created until it’s needed. Also note that since this is a constant property, once this instance is created, it’s not going to create it a second time. This is the essence of the Singleton design pattern. The initializer is never called again once it has been instantiated.
    4. Returns the computed type property.

    Note: To learn more about different ways to create a singleton in Swift refer to this: Github page

    You now have a Singleton object as the entry point to manage the albums. Take it a step further and create a class to handle the persistence of your library data.

    Now within the group API create a new file. Select iOS > Cocoa Touch class and then click Next. Set the class name to PersistencyManager, and make it a subclass of NSObject.

    Open PersistencyManager.swift Add the following code inside the curly braces

    private var albums = [Album]()

    Here you declare a private property to hold album data. The array is mutable, so you can easily add and delete albums.

    Now add the following initializer to the class:

    override init() {
      //Dummy list of albums
      let album1 = Album(title: "Best of Bowie",
             artist: "David Bowie",
             genre: "Pop",
             coverUrl: "http://www.coversproject.com/static/thumbs/album/album_david%20bowie_best%20of%20bowie.png",
             year: "1992")
     
      let album2 = Album(title: "It's My Life",
             artist: "No Doubt",
             genre: "Pop",
             coverUrl: "http://www.coversproject.com/static/thumbs/album/album_no%20doubt_its%20my%20life%20%20bathwater.png",
             year: "2003")
     
      let album3 = Album(title: "Nothing Like The Sun",
             artist: "Sting",
             genre: "Pop",
             coverUrl: "http://www.coversproject.com/static/thumbs/album/album_sting_nothing%20like%20the%20sun.png",
             year: "1999")
     
      let album4 = Album(title: "Staring at the Sun",
             artist: "U2",
             genre: "Pop",
             coverUrl: "http://www.coversproject.com/static/thumbs/album/album_u2_staring%20at%20the%20sun.png",
             year: "2000")
     
      let album5 = Album(title: "American Pie",
             artist: "Madonna",
             genre: "Pop",
             coverUrl: "http://www.coversproject.com/static/thumbs/album/album_madonna_american%20pie.png",
             year: "2000")
     
      albums = [album1, album2, album3, album4, album5]
    }

    In the initializer, you’re populating the array with five sample albums. If the above albums aren’t to your liking, feel free to replace them with the music you enjoy. :]

    Now add the following functions to the class:

    func getAlbums() -> [Album] {
      return albums
    }
     
    func addAlbum(album: Album, index: Int) {
      if (albums.count >= index) { 
        albums.insert(album, atIndex: index)
      } else {
        albums.append(album)
      }
    }
     
    func deleteAlbumAtIndex(index: Int) {
      albums.removeAtIndex(index)
    }

    These methods allow you to get, add, and delete albums.

    Build your project just to make sure everything still compiles correctly.

    At this point, you might wonder where the PersistencyManager class comes in since it’s not a Singleton. You’ll see the relationship between LibraryAPI and PersistencyManager in the next section where you’ll look at the Facade design pattern.

    The Facade Design Pattern

    facade

    The Facade design pattern provides a single interface to a complex subsystem. Instead of exposing the user to a set of classes and their APIs, you only expose one simple unified API.

    The following image explains this concept:

    facade2

    The user of the API is completely unaware of the complexity that lies beneath. This pattern is ideal when working with a large number of classes, particularly when they are complicated to use or difficult to understand.

    The Facade pattern decouples the code that uses the system from the interface and implementation of the classes you’re hiding; it also reduces dependencies of outside code on the inner workings of your subsystem. This is also useful if the classes under the facade are likely to change, as the facade class can retain the same API while things change behind the scenes.

    For example, if the day comes when you want to replace your backend service, you won’t have to change the code that uses your API as it wont’ change.

    How to Use the Facade Pattern

    Currently you have PersistencyManager to save the album data locally and HTTPClient to handle the remote communication. The other classes in your project should not be aware of this logic, as they will be hiding behind the facade of LibraryAPI.

    To implement this pattern, only LibraryAPI should hold instances of PersistencyManager and HTTPClient. Then, LibraryAPI will expose a simple API to access those services.

    The design looks like the following:

    design-patterns-facade-uml

    LibraryAPI will be exposed to other code, but will hide the HTTPClient and PersistencyManager complexity from the rest of the app.

    Open LibraryAPI.swift and add the following constant properties to the class:

    private let persistencyManager: PersistencyManager
    private let httpClient: HTTPClient
    private let isOnline: Bool

    isOnline determines if the server should be updated with any changes made to the albums list, such as added or deleted albums.

    You now need to initialize these variables via init. Add the initializer to the class next:

    override init() {
      persistencyManager = PersistencyManager()
      httpClient = HTTPClient()
      isOnline = false
     
      super.init()
    }

    The HTTP client doesn’t actually work with a real server and is only here to demonstrate the usage of the facade pattern, so isOnline will always be false.

    Next, add the following three methods to LibraryAPI.swift:

    func getAlbums() -> [Album] {
      return persistencyManager.getAlbums()
    }
     
    func addAlbum(album: Album, index: Int) {
      persistencyManager.addAlbum(album, index: index)
      if isOnline {
        httpClient.postRequest("/api/addAlbum", body: album.description())
      }
    }
     
    func deleteAlbum(index: Int) {
      persistencyManager.deleteAlbumAtIndex(index)
      if isOnline {
        httpClient.postRequest("/api/deleteAlbum", body: "\(index)")
      }
    }

    Take a look at addAlbum(_:index:). The class first updates the data locally, and then if there’s an internet connection, it updates the remote server. This is the real strength of the Facade; when some class outside of your system adds a new album, it doesn’t know — and doesn’t need to know — of the complexity that lies underneath.

    Note: When designing a Facade for classes in your subsystem, remember that nothing prevents the client from accessing these “hidden” classes directly. Don’t be stingy with defensive code and don’t assume that all the clients will necessarily use your classes the same way the Facade uses them.

    Build and run your app. You’ll see two empty views, and a toolbar. The top view will be used to display your album covers, and the bottom view will be used to display a table of information related to that album.

    designPatternInitialScreen

    You’ll need something to display the album data on screen — which is a perfect use for your next design pattern: the Decorator.

    The Decorator Design Pattern

    The Decorator pattern dynamically adds behaviors and responsibilities to an object without modifying its code. It’s an alternative to subclassing where you modify a class’s behavior by wrapping it with another object.

    In Swift there are two very common implementations of this pattern: Extensions and Delegation.

    Extensions

    Adding extensions is an extremely powerful mechanism that allows you to add new functionality to existing classes, structures or enumeration types without having to subclass. What’s also really awesome is you can extend code you don’t have access to, and enhance their functionality. That means you can add your own methods to Cocoa classes such as UIView and UIImage!

    For example, new methods that are added at compile time can be executed like normal methods of the extended class. It’s slightly different from the classic definition of a decorator, because a extension doesn’t hold an instance of the class it extends.

    How to Use Extensions

    Imagine a situation in which you have an Album object that you want to present inside a table view:
    swiftDesignPattern3

    Where will the album titles come from? Album is a Model object, so it doesn’t care how you present the data. You’ll need some external code to add this functionality to the Album class, but without modifying the class directly.

    You’ll create a extension that will extend the Album class; it will define a new method that returns a data structure which can be used easily with UITableView.

    The data structure will look like the following:

    delegate2

    To add a Extensions to Album, navigate to File\New\File… and select the iOS > Source > Swift File template, and then click Next. Enter AlbumExtensions and click Create.

    Go to AlbumExtensions.swift and add the following extension:

    extension Album {
      func ae_tableRepresentation() -> (titles:[String], values:[String]) {
        return (["Artist", "Album", "Genre", "Year"], [artist, title, genre, year])
      }
    }

    Notice there’s a ae_ at the beginning of the method name, as an abbreviation of the name of the extension: AlbumExtension. Conventions like this will help prevent collisions with methods (including possible private methods you might not know about) in the original implementation.

    Note: Classes can of course override a superclass’s method, but with extensions you can’t. Methods or properties in an extension cannot have the same name as methods or properties in the original class.

    Consider for a moment how powerful this pattern can be:

    • You’re using properties directly from Album.
    • You have added to the Album class but you haven’t subclassed it. If you need to sub-class Album, you can still do that too.
    • This simple addition lets you return a UITableView-ish representation of an Album, without modifying Album‘s code.

    Delegation

    The other Decorator design pattern, Delegation, is a mechanism in which one object acts on behalf of, or in coordination with, another object. For example, when you use a UITableView, one of the methods you must implement is tableView(_:numberOfRowsInSection:).

    You can’t expect the UITableView to know how many rows you want to have in each section, as this is application-specific. Therefore, the task of calculating the amount of rows in each section is passed on to the UITableView delegate. This allows the UITableView class to be independent of the data it displays.

    Here’s a pseudo-explanation of what’s going on when you create a new UITableView:

    delegate

    The UITableView object does its job of displaying a table view. However, eventually it will need some information that it doesn’t have. Then, it turns to its delegates and sends a message asking for additional information. In Objective-C’s implementation of the delegate pattern, a class can declare optional and required methods through a protocol. You’ll cover protocols a bit later in this tutorial.

    It might seem easier to just subclass an object and override the necessary methods, but consider that you can only subclass based on a single class. If you want an object to be the delegate of two or more other objects, you won’t be able to achieve this by subclassing.

    Note: This is an important pattern. Apple uses this approach in most of the UIKit classes: UITableView, UITextView, UITextField, UIWebView, UIAlert, UIActionSheet, UICollectionView, UIPickerView, UIGestureRecognizer, UIScrollView. The list goes on and on.

    How to Use the Delegate Pattern

    Open up ViewController.swift and add these private properties to the class:

    private var allAlbums = [Album]()
    private var currentAlbumData : (titles:[String], values:[String])?
    private var currentAlbumIndex = 0

    Next, replace viewDidLoad with this code:

    override func viewDidLoad() {
      super.viewDidLoad()
      //1
      self.navigationController?.navigationBar.translucent = false
      currentAlbumIndex = 0
     
      //2
      allAlbums = LibraryAPI.sharedInstance.getAlbums()
     
      // 3
      // the uitableview that presents the album data
      dataTable.delegate = self
      dataTable.dataSource = self
      dataTable.backgroundView = nil
      view.addSubview(dataTable!)		
    }

    Here’s a breakdown of the above code:

    1. Turn off translucency on the navigation bar.
    2. Get a list of all the albums via the API. Remember, the plan is to use the facade of LibraryAPI rather than PersistencyManager directly!
    3. This is where you setup the UITableView. You declare that the view controller is the UITableView delegate/data source; therefore, all the information required by UITableView will be provided by the view controller. Note that you can actually set the delegate and datasource in a storyboard, if your table view is created there.

    Now, add the following method to ViewController.swift:

    func showDataForAlbum(albumIndex: Int) {
      // defensive code: make sure the requested index is lower than the amount of albums
      if (albumIndex < allAlbums.count && albumIndex > -1) {
        //fetch the album
        let album = allAlbums[albumIndex]
        // save the albums data to present it later in the tableview
        currentAlbumData = album.ae_tableRepresentation()
      } else {
        currentAlbumData = nil
      }
      // we have the data we need, let's refresh our tableview
      dataTable!.reloadData()
    }

    showDataForAlbum() fetches the required album data from the array of albums. When you want to present the new data, you just need to call reloadData. This causes UITableView to ask its delegate such things as how many sections should appear in the table view, how many rows in each section, and how each cell should look.

    Add the following line to the end of viewDidLoad

    self.showDataForAlbum(currentAlbumIndex)

    This loads the current album at app launch. And since currentAlbumIndex was previously set to 0, this shows the first album in the collection.

    Now it’s time to implement the data source protocol! You can add the list of protocols implemented by the class right on the class declaration line. Or, to keep things tidy you can add them as extensions, which you’re already familiar with.

    Add the following extensions to the bottom of the file. Make sure you add these lines after the closing brace of the class definition!

    extension ViewController: UITableViewDataSource {
    }
     
    extension ViewController: UITableViewDelegate {
    }

    This is how you make your delegate conform to a protocol — think of it as a promise made by the delegate to fulfill the method’s contract. Here, you indicate that ViewController will conform to the UITableViewDataSource and UITableViewDelegate protocols. This way UITableView can be absolutely certain that the required methods are implemented by its delegate.

    Add the following code to the UITableViewDataSource extension:

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
      if let albumData = currentAlbumData {
        return albumData.titles.count
      } else {
        return 0
      }
    }
     
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
      var cell:UITableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
      if let albumData = currentAlbumData {
        cell.textLabel?.text = albumData.titles[indexPath.row]
          if let detailTextLabel = cell.detailTextLabel {
            detailTextLabel.text = albumData.values[indexPath.row]
          }
      }
      return cell
    }

    tableView(_:numberOfRowsInSection:) returns the number of rows to display in the table view, which matches the number of titles in the data structure.

    tableView(_:cellForRowAtIndexPath:) creates and returns a cell with the title and its value.

    Note: You can actually add the methods to the main class declaration or to the extension; the compiler doesn’t care that the data source methods are actually inside the UITableViewDataSource extension. For humans reading the code though, this kind of organization really helps with readability.

    Build and run your project. Your app should start and present you with the following screen:

    designPatternDataTable

    Table view data source success!

    Where to go from here?

    Things are looking pretty good so far! You have the MVC pattern in place, and you’ve also seen the singleton, facade, and decorator patterns in action. You can see how these are used within Cocoa by Apple, and also how to apply the patterns to your own code.

    Here are the project files up to this point if you want to have a look or compare.

    There’s a lot more in store: there are still the adapter, observer, and memento patterns to cover in part two of this tutorial. And if that’s not enough, we have a follow-up tutorial coming up covering even more design patterns as you work on refactoring a simple iOS game.

    If you have questions or just want to talk about your favorite design patterns, join in on the forum discussion below!

    Introducing iOS Design Patterns in Swift – Part 1/2 is a post from: Ray Wenderlich

    The post Introducing iOS Design Patterns in Swift – Part 1/2 appeared first on Ray Wenderlich.


    Introducing iOS Design Patterns in Swift – Part 2/2

    $
    0
    0

    Update note: This tutorial was updated for iOS 8 and Swift by Vincent Ngo. Original post by Tutorial team member Eli Ganem.

    Welcome back to part two of this introductory tutorial on design patterns! In the first part, you learned about some fundamental patterns in Cocoa such as MVC, singletons, and decorator.

    In this final part, you’ll learn about the other basic design patterns that come up a lot in iOS and OS X development: adapter, observer, and memento. Let’s get right into it!

    Getting Started

    You can download the project source from the end of part 1 to get started.

    Here’s where you left off the sample music library app at the end of the first part:

    designPatternDataTable

    The original plan for the app included a horizontal scroller at the top of the screen to switch between albums. Instead of coding a single-purpose horizontal scroller, why not make it reusable for any view?

    To make this view reusable, all decisions about its content should be left to another object: a delegate. The horizontal scroller should declare methods that its delegate implements in order to work with the scroller, similar to how the UITableView delegate methods work. We’ll implement this when we discuss the next design pattern.

    The Adapter Pattern

    An Adapter allows classes with incompatible interfaces to work together. It wraps itself around an object and exposes a standard interface to interact with that object.

    If you’re familiar with the Adapter pattern then you’ll notice that Apple implements it in a slightly different manner – Apple uses protocols to do the job. You may be familiar with protocols like UITableViewDelegate, UIScrollViewDelegate, NSCoding and NSCopying. As an example, with the NSCopying protocol, any class can provide a standard copy method.

    How to Use the Adapter Pattern

    The horizontal scroller mentioned before will look like this:

    swiftDesignPattern7

    To begin implementing it, right click on the View group in the Project Navigator, select New File… and select, iOS > Cocoa Touch class and then click Next. Set the class name to HorizontalScroller and make it a subclass of UIView.

    Open HorizontalScroller.swift and insert the following code above the class HorizontalScroller line:

    @objc protocol HorizontalScrollerDelegate {
    }

    This defines a protocol named HorizontalScrollerDelegate. You’re including @objc before the protocol declaration so you can make use of @optional delegate methods like in Objective-C.

    You define the required and optional methods that the delegate will implement between the protocols curly braces. So add the following protocol methods:

    // ask the delegate how many views he wants to present inside the horizontal scroller
    func numberOfViewsForHorizontalScroller(scroller: HorizontalScroller) -> Int
    // ask the delegate to return the view that should appear at <index>
    func horizontalScrollerViewAtIndex(scroller: HorizontalScroller, index:Int) -> UIView
    // inform the delegate what the view at <index> has been clicked
    func horizontalScrollerClickedViewAtIndex(scroller: HorizontalScroller, index:Int)
    // ask the delegate for the index of the initial view to display. this method is optional
    // and defaults to 0 if it's not implemented by the delegate
    optional func initialViewIndex(scroller: HorizontalScroller) -> Int

    Here you have both required and optional methods. Required methods must be implemented by the delegate and usually contain some data that is absolutely required by the class. In this case, the required details are the number of views, the view at a specific index, and the behavior when the view is tapped. The optional method here is the initial view; if it’s not implemented then the HorizontalScroller will default to the first index.

    In HorizontalScroller.swift, add the following code to the HorizontalScroller class definition:

    weak var delegate: HorizontalScrollerDelegate?

    The attribute of the property you created above is defined as weak. This is necessary in order to prevent a retain cycle. If a class keeps a strong reference to its delegate and the delegate keeps a strong reference back to the conforming class, your app will leak memory since neither class will release the memory allocated to the other. All properties in swift are strong by default!

    The delegate is an optional, so it’s possible whoever is using this class doesn’t provide a delegate. But if they do, it will conform to HorizontalScrollerDelegate and you can be sure the protocol methods will be implemented there.

    Add a few more properties to the class:

    // 1
    private let VIEW_PADDING = 10
    private let VIEW_DIMENSIONS = 100
    private let VIEWS_OFFSET = 100
     
    // 2
    private var scroller : UIScrollView!
    // 3
    var viewArray = [UIView]()

    Taking each comment block in turn:

    1. Define constants to make it easy to modify the layout at design time. The view’s dimensions inside the scroller will be 100 x 100 with a 10 point margin from its enclosing rectangle.
    2. Create the scroll view containing the views.
    3. Create an array that holds all the album covers.

    Next you need to implement the initializers. Add the following methods:

    override init(frame: CGRect) {
      super.init(frame: frame)
      initializeScrollView()
    }
     
    required init(coder aDecoder: NSCoder) {
      super.init(coder: aDecoder)
      initializeScrollView()
    }
     
    func initializeScrollView() {
      //1
      scroller = UIScrollView()
      addSubview(scroller)
     
      //2
      scroller.setTranslatesAutoresizingMaskIntoConstraints(false)
      //3
      self.addConstraint(NSLayoutConstraint(item: scroller, attribute: .Leading, relatedBy: .Equal, toItem: self, attribute: .Leading, multiplier: 1.0, constant: 0.0))
      self.addConstraint(NSLayoutConstraint(item: scroller, attribute: .Trailing, relatedBy: .Equal, toItem: self, attribute: .Trailing, multiplier: 1.0, constant: 0.0))
      self.addConstraint(NSLayoutConstraint(item: scroller, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1.0, constant: 0.0))
      self.addConstraint(NSLayoutConstraint(item: scroller, attribute: .Bottom, relatedBy: .Equal, toItem: self, attribute: .Bottom, multiplier: 1.0, constant: 0.0))
     
      //4
      let tapRecognizer = UITapGestureRecognizer(target: self, action:Selector("scrollerTapped:"))
      scroller.addGestureRecognizer(tapRecognizer)
    }

    The initializers delegate most of the work to initializeScrollView(). Here’s what’s going on in that method:

    1. Create’s a new UIScrollView instance and add it to the parent view.
    2. Turn off autoresizing masks. This is so you can apply your own constraints
    3. Apply constraints to the scrollview. You want the scroll view to completely fill the HorizontalScroller
    4. Create a tap gesture recognizer. The tap gesture recognizer detects touches on the scroll view and checks if an album cover has been tapped. If so, it will notify the HorizontalScroller delegate.

    Now add this method:

    func scrollerTapped(gesture: UITapGestureRecognizer) {
      let location = gesture.locationInView(gesture.view)
      if let delegate = self.delegate {
        for index in 0..<delegate.numberOfViewsForHorizontalScroller(self) {
          let view = scroller.subviews[index] as UIView
          if CGRectContainsPoint(view.frame, location) {
            delegate.horizontalScrollerClickedViewAtIndex(self, index: index)
            scroller.setContentOffset(CGPointMake(view.frame.origin.x - self.frame.size.width/2 + view.frame.size.width/2, 0), animated:true)
            break
          }
        }
      }
    }

    The gesture passed in as a parameter lets you extract the location with locationInView().

    Next, you invoke numberOfViewsForHorizontalScroller() on the delegate. The HorizontalScroller instance has no information about the delegate other than knowing it can safely send this message since the delegate must conform to the HorizontalScrollerDelegate protocol.

    For each view in the scroll view, perform a hit test using CGRectContainsPoint to find the view that was tapped. When the view is found, call the delegate method horizontalScrollerClickedViewAtIndex. Before you break out of the for loop, center the tapped view in the scroll view.

    Next add the following to access an album cover from the scroller:

    func viewAtIndex(index :Int) -> UIView {
      return viewArray[index]
    }

    viewAtIndex simply returns the view at a particular index. You will be using this method later to highlight the album cover you have tapped on.

    Now add the following code to reload the scroller:

    func reload() {
      // 1 - Check if there is a delegate, if not there is nothing to load.
      if let delegate = self.delegate {
        //2 - Will keep adding new album views on reload, need to reset.
        viewArray = []
        let views: NSArray = scroller.subviews
     
        // 3 - remove all subviews
        views.enumerateObjectsUsingBlock {
        (object: AnyObject!, idx: Int, stop: UnsafeMutablePointer<ObjCBool>) -> Void in
          object.removeFromSuperview()
        }
        // 4 - xValue is the starting point of the views inside the scroller			
        var xValue = VIEWS_OFFSET
        for index in 0..<delegate.numberOfViewsForHorizontalScroller(self) {
          // 5 - add a view at the right position
          xValue += VIEW_PADDING
          let view = delegate.horizontalScrollerViewAtIndex(self, index: index)
          view.frame = CGRectMake(CGFloat(xValue), CGFloat(VIEW_PADDING), CGFloat(VIEW_DIMENSIONS), CGFloat(VIEW_DIMENSIONS))
          scroller.addSubview(view)
          xValue += VIEW_DIMENSIONS + VIEW_PADDING
          // 6 - Store the view so we can reference it later
         viewArray.append(view)
        }
        // 7
        scroller.contentSize = CGSizeMake(CGFloat(xValue + VIEWS_OFFSET), frame.size.height)
     
        // 8 - If an initial view is defined, center the scroller on it
        if let initialView = delegate.initialViewIndex?(self) {
          scroller.setContentOffset(CGPointMake(CGFloat(initialView)*CGFloat((VIEW_DIMENSIONS + (2 * VIEW_PADDING))), 0), animated: true)
        }
      }
    }

    The reload method is modeled after reloadData in UITableView; it reloads all the data used to construct the horizontal scroller.

    Stepping through the code comment-by-comment:

    1. Checks to see if there is a delegate before we perform any reload.
    2. Since you’re clearing the album covers, you also need to reset the viewArray. If not you will have a ton of views left over from the previous covers.
    3. Remove all the subviews previously added to the scroll view.
    4. All the views are positioned starting from the given offset. Currently it’s 100, but it can be easily tweaked by changing the constant VIEW_OFFSET at the top of the file.
    5. The HorizontalScroller asks its delegate for the views one at a time and it lays them next to each another horizontally with the previously defined padding.
    6. Store the view in viewArray to keep track of all the views in the scroll view.
    7. Once all the views are in place, set the content offset for the scroll view to allow the user to scroll through all the albums covers.
    8. The HorizontalScroller checks if its delegate implements initialViewIndex(). This check is necessary because that particular protocol method is optional. If the delegate doesn’t implement this method, 0 is used as the default value. Finally, this piece of code sets the scroll view to center the initial view defined by the delegate.

    You execute reload when your data has changed. You also need to call this method when you add HorizontalScroller to another view. Add the following code to HorizontalScroller.swift to cover the latter scenario:

    override func didMoveToSuperview() {
      reload()
    }

    didMoveToSuperview is called on a view when it’s added to another view as a subview. This is the right time to reload the contents of the scroller.

    The last piece of the HorizontalScroller puzzle is to make sure the album you’re viewing is always centered inside the scroll view. To do this, you’ll need to perform some calculations when the user drags the scroll view with their finger.

    Add the following method:

    func centerCurrentView() {
      var xFinal = scroller.contentOffset.x + CGFloat((VIEWS_OFFSET/2) + VIEW_PADDING)
      let viewIndex = xFinal / CGFloat((VIEW_DIMENSIONS + (2*VIEW_PADDING)))
      xFinal = viewIndex * CGFloat(VIEW_DIMENSIONS + (2*VIEW_PADDING))
      scroller.setContentOffset(CGPointMake(xFinal, 0), animated: true)
      if let delegate = self.delegate {
        delegate.horizontalScrollerClickedViewAtIndex(self, index: Int(viewIndex))
      }  
    }

    The above code takes into account the current offset of the scroll view and the dimensions and the padding of the views in order to calculate the distance of the current view from the center. The last line is important: once the view is centered, you then inform the delegate that the selected view has changed.

    To detect that the user finished dragging inside the scroll view, you’ll need to implement some UIScrollViewDelegate methods. Add the following class extension to the bottom of the file; remember, this must be added after the curly braces of the main class declaration!

    extension HorizontalScroller: UIScrollViewDelegate {
      func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
        if !decelerate {
          centerCurrentView()
        }
      }
     
      func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
        centerCurrentView()
      }
    }

    scrollViewDidEndDragging(_:willDecelerate:) informs the delegate when the user finishes dragging. The decelerate parameter is true if the scroll view hasn’t come to a complete stop yet. When the scroll action ends, the the system calls scrollViewDidEndDecelerating. In both cases you should call the new method to center the current view since the current view probably has changed after the user dragged the scroll view.

    Your HorizontalScroller is ready for use! Browse through the code you’ve just written; you’ll see there’s not one single mention of the Album or AlbumView classes. That’s excellent, because this means that the new scroller is truly independent and reusable.

    Build your project to make sure everything compiles properly.

    Now that HorizontalScroller is complete, it’s time to use it in your app. First, open Main.storyboard. Click on the top gray rectangular view and click on the identity inspector. Change the class name to HorizontalScroller as shown below:

    swiftDesignPattwern9

    Next, open the assistant editor and control drag from the gray rectangular view to ViewController.swift to create an outlet. Name the name the outlet scroller, as shown below:

    swiftDesignPattern10

    Next, open ViewController.swift. It’s time to start implementing some of the HorizontalScrollerDelegate methods!

    Add the following extension to the bottom of the file:

    extension ViewController: HorizontalScrollerDelegate {
      func horizontalScrollerClickedViewAtIndex(scroller: HorizontalScroller, index: Int) {
        //1
        let previousAlbumView = scroller.viewAtIndex(currentAlbumIndex) as AlbumView
        previousAlbumView.highlightAlbum(didHighlightView: false)
        //2
        currentAlbumIndex = index
        //3
        let albumView = scroller.viewAtIndex(index) as AlbumView
        albumView.highlightAlbum(didHighlightView: true)
        //4
        showDataForAlbum(index)
      }
    }

    Let’s go over the delegate method you just implemented line by line:

    1. First you grab the previously selected album, and deselect the album cover.
    2. Store the current album cover index you just clicked
    3. Grab the album cover that is currently selected and highlight the selection.
    4. Display the data for the new album within the table view.

    Next, add the following method to the extension:

    func numberOfViewsForHorizontalScroller(scroller: HorizontalScroller) -> (Int) {
      return allAlbums.count
    }

    This, as you’ll recognize, is the protocol method returning the number of views for the scroll view. Since the scroll view will display covers for all the album data, the count is the number of album records.

    Now, add this code:

    func horizontalScrollerViewAtIndex(scroller: HorizontalScroller, index: Int) -> (UIView) {
      let album = allAlbums[index]
      let albumView = AlbumView(frame: CGRectMake(0, 0, 100, 100), albumCover: album.coverUrl)
      if currentAlbumIndex == index {
        albumView.highlightAlbum(didHighlightView: true)
      } else {
        albumView.highlightAlbum(didHighlightView: false)
      }
      return albumView
    }

    Here you create a new AlbumView, next check to see whether or not the user has selected this album. Then you can set it as highlighted or not depending on whether the album is selected. Lastly, you pass it to the HorizontalScroller.

    That’s it! Only three short methods to display a nice looking horizontal scroller.

    Yes, you still need to actually create the scroller and add it to your main view but before doing that, add the following method to the main class definition:

    func reloadScroller() {
      allAlbums = LibraryAPI.sharedInstance.getAlbums()
      if currentAlbumIndex < 0 {
        currentAlbumIndex = 0
      } else if currentAlbumIndex >= allAlbums.count {
        currentAlbumIndex = allAlbums.count - 1
      }	
      scroller.reload()	
      showDataForAlbum(currentAlbumIndex)
    }

    This method loads album data via LibraryAPI and then sets the currently displayed view based on the current value of the current view index. If the current view index is less than 0, meaning that no view was currently selected, then the first album in the list is displayed. Otherwise, the last album is displayed.

    Now, initialize the scroller by adding the following code to the end of viewDidLoad:

    scroller.delegate = self
    reloadScroller()

    Since the HorizontalScroller was created in the storyboard, all you need to do is set the delegate, and call reloadScroller(), which will load the subviews for the scroller to display album data.

    Note: If a protocol becomes too big and is packed with a lot of methods, you should consider breaking it into several smaller protocols. UITableViewDelegate and UITableViewDataSource are a good example, since they are both protocols of UITableView. Try to design your protocols so that each one handles one specific area of functionality.

    Build and run your project and take a look at your awesome new horizontal scroller:

    swiftDesignPattern12

    Uh, wait. The horizontal scroller is in place, but where are the covers?

    Ah, that’s right — you didn’t implement the code to download the covers yet. To do that, you’ll need to add a way to download images. Since all your access to services goes through LibraryAPI, that’s where this new method would have to go. However, there are a few things to consider first:

    1. AlbumView shouldn’t work directly with LibraryAPI. You don’t want to mix view logic with communication logic.
    2. For the same reason, LibraryAPI shouldn’t know about AlbumView.
    3. LibraryAPI needs to inform AlbumView once the covers are downloaded since the AlbumView has to display the covers.

    Sounds like a conundrum? Don’t despair, you’ll learn how to do this using the Observer pattern! :]

    The Observer Pattern

    In the Observer pattern, one object notifies other objects of any state changes. The objects involved don’t need to know about one another – thus encouraging a decoupled design. This pattern’s most often used to notify interested objects when a property has changed.

    The usual implementation requires that an observer registers interest in the state of another object. When the state changes, all the observing objects are notified of the change.

    If you want to stick to the MVC concept (hint: you do), you need to allow Model objects to communicate with View objects, but without direct references between them. And that’s where the Observer pattern comes in.

    Cocoa implements the observer pattern in two familiar ways: Notifications and Key-Value Observing (KVO).

    Notifications

    Not be be confused with Push or Local notifications, Notifications are based on a subscribe-and-publish model that allows an object (the publisher) to send messages to other objects (subscribers/listeners). The publisher never needs to know anything about the subscribers.

    Notifications are heavily used by Apple. For example, when the keyboard is shown/hidden the system sends a UIKeyboardWillShowNotification/UIKeyboardWillHideNotification, respectively. When your app goes to the background, the system sends a UIApplicationDidEnterBackgroundNotification notification.

    Note: Open up UIApplication.swift, at the end of the file you’ll see a list of over 20 notifications sent by the system.

    How to Use Notifications

    Go to AlbumView.swift and insert the following code to the end of the init(frame: CGRect, albumCover: String) initializer:

    NSNotificationCenter.defaultCenter().postNotificationName("BLDownloadImageNotification", object: self, userInfo: ["imageView":coverImage, "coverUrl" : albumCover])

    This line sends a notification through the NSNotificationCenter singleton. The notification info contains the UIImageView to populate and the URL of the cover image to be downloaded. That’s all the information you need to perform the cover download task.

    Add the following line to init in LibraryAPI.swift, directly after super.init():

    NSNotificationCenter.defaultCenter().addObserver(self, selector:"downloadImage:", name: "BLDownloadImageNotification", object: nil)

    This is the other side of the equation: the observer. Every time an AlbumView class posts a BLDownloadImageNotification notification, since LibraryAPI has registered as an observer for the same notification, the system notifies LibraryAPI. Then LibraryAPI calls downloadImage() in response.

    However, before you implement downloadImage() you must remember to unsubscribe from this notification when your class is deallocated. If you do not properly unsubscribe from a notification your class registered for, a notification might be sent to a deallocated instance. This can result in application crashes.

    Add the following method to LibraryAPI.swift:

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

    When this object is deallocated, it removes itself as an observer from all notifications it had registered for.

    There’s one more thing to do. It would probably be a good idea to save the downloaded covers locally so the app won’t need to download the same covers over and over again.

    Open PersistencyManager.swift and add the methods below:

    func saveImage(image: UIImage, filename: String) {
      let path = NSHomeDirectory().stringByAppendingString("/Documents/\(filename)")
      let data = UIImagePNGRepresentation(image)
      data.writeToFile(path, atomically: true)
    }
     
    func getImage(filename: String) -> UIImage? {
      var error: NSError?
      let path = NSHomeDirectory().stringByAppendingString("/Documents/\(filename)")
      let data = NSData(contentsOfFile: path, options: .UncachedRead, error: &error)
      if let unwrappedError = error {
        return nil
      } else {
        return UIImage(data: data!)
      }
    }

    This code is pretty straightforward. The downloaded images will be saved in the Documents directory, and getImage() will return nil if a matching file is not found in the Documents directory.

    Now add the following method to LibraryAPI.swift:

    func downloadImage(notification: NSNotification) {
      //1
      let userInfo = notification.userInfo as [String: AnyObject]
      var imageView = userInfo["imageView"] as UIImageView?
      let coverUrl = userInfo["coverUrl"] as NSString
     
      //2
      if let imageViewUnWrapped = imageView {
        imageViewUnWrapped.image = persistencyManager.getImage(coverUrl.lastPathComponent)
        if imageViewUnWrapped.image == nil {
          //3
          dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
            let downloadedImage = self.httpClient.downloadImage(coverUrl)
            //4
            dispatch_sync(dispatch_get_main_queue(), { () -> Void in
              imageViewUnWrapped.image = downloadedImage
              self.persistencyManager.saveImage(downloadedImage, filename: coverUrl.lastPathComponent)
            })
          })
        }
      }
    }

    Here’s a breakdown of the above code:

    1. downloadImage is executed via notifications and so the method receives the notification object as a parameter. The UIImageView and image URL are retrieved from the notification.
    2. Retrieve the image from the PersistencyManager if it’s been downloaded previously.
    3. If the image hasn’t already been downloaded, then retrieve it using HTTPClient.
    4. When the download is complete, display the image in the image view and use the PersistencyManager to save it locally.

    Again, you’re using the Facade pattern to hide the complexity of downloading an image from the other classes. The notification sender doesn’t care if the image came from the web or from the file system.

    Build and run your app and check out the beautiful covers inside your HorizontalScroller:

    swiftDesignPattern13

    Stop your app and run it again. Notice that there’s no delay in loading the covers because they’ve been saved locally. You can even disconnect from the Internet and your app will work flawlessly. However, there’s one odd bit here: the spinner never stops spinning! What’s going on?

    You started the spinner when downloading the image, but you haven’t implemented the logic to stop the spinner once the image is downloaded. You could send out a notification every time an image has been downloaded, but instead, you’ll do that using the other Observer pattern, KVO.

    Key-Value Observing (KVO)

    In KVO, an object can ask to be notified of any changes to a specific property; either its own or that of another object. If you’re interested, you can read more about this on Apple’s KVO Programming Guide.

    How to Use the KVO Pattern

    As mentioned above, the KVO mechanism allows an object to observe changes to a property. In your case, you can use KVO to observe changes to the image property of the UIImageView that holds the image.

    Open AlbumView.swift and add the following code to init(frame:albumCover:), just after you add coverImage as a subView:

    coverImage.addObserver(self, forKeyPath: "image", options: nil, context: nil)

    This adds self, which is the current class, as an observer for the image property of coverImage.

    You also need to unregister as an observer when you’re done. Still in AlbumView.swift, add the following code:

    deinit {
      coverImage.removeObserver(self, forKeyPath: "image")
    }

    Finally, add this method:

    override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) {
      if keyPath == "image" {
        indicator.stopAnimating()
      }
    }

    You must implement this method in every class acting as an observer. The system executes this method every time an observed property changes. In the above code, you stop the spinner when the “image” property changes. This way, when an image is loaded, the spinner will stop spinning.

    Build and run your project. The spinner should disappear:

    swiftDesignPattern14

    Note: Always remember to remove your observers when they’re deallocated, or else your app will crash when the subject tries to send messages to these non-existent observers!

    If you play around with your app a bit and terminate it, you’ll notice that the state of your app isn’t saved. The last album you viewed won’t be the default album when the app launches.

    To correct this, you can make use of the next pattern on the list: Memento.

    The Memento Pattern

    The memento pattern captures and externalizes an object’s internal state. In other words, it saves your stuff somewhere. Later on, this externalized state can be restored without violating encapsulation; that is, private data remains private.

    How to Use the Memento Pattern

    Add the following two methods to ViewController.swift:

    //MARK: Memento Pattern
    func saveCurrentState() {
      // When the user leaves the app and then comes back again, he wants it to be in the exact same state
      // he left it. In order to do this we need to save the currently displayed album.
      // Since it's only one piece of information we can use NSUserDefaults.
      NSUserDefaults.standardUserDefaults().setInteger(currentAlbumIndex, forKey: "currentAlbumIndex")
    }
     
    func loadPreviousState() {
      currentAlbumIndex = NSUserDefaults.standardUserDefaults().integerForKey("currentAlbumIndex")
      showDataForAlbum(currentAlbumIndex)
    }

    saveCurrentState saves the current album index to NSUserDefaultsNSUserDefaults is a standard data store provided by iOS for saving application specific settings and data.

    loadPreviousState loads the previously saved index. This isn’t quite the full implementation of the Memento pattern, but you’re getting there.

    Now, Add the following line to viewDidLoad in ViewController.swift before the scroller.delegate = self:

    loadPreviousState()

    That loads the previously saved state when the app starts. But where do you save the current state of the app for loading from? You’ll use Notifications to do this. iOS sends a UIApplicationDidEnterBackgroundNotification notification when the app enters the background. You can use this notification to call saveCurrentState. Isn’t that convenient?

    Add the following line to the end of viewDidLoad:

    NSNotificationCenter.defaultCenter().addObserver(self, selector:"saveCurrentState", name: UIApplicationDidEnterBackgroundNotification, object: nil)

    Now, when the app is about to enter the background, the ViewController will automatically save the current state by calling saveCurrentState.

    As always, you’ll need to un-register for notifications. Add the following code to the class:

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

    This ensures you remove the class as an observer when the ViewController is deallocated.

    Build and run your app. Navigate to one of the albums, send the app to the background with the Home button (Command+Shift+H if you are on the simulator) and then shut down your app from Xcode. Relaunch, and check that the previously selected album is centered:

    swiftDesignPattern15

    It looks like the album data is correct, but the scroller isn’t centered on the correct album. What gives?

    This is what the optional method initialViewIndexForHorizontalScroller was meant for! Since that method’s not implemented in the delegate, ViewController in this case, the initial view is always set to the first view.

    To fix that, add the following code to ViewController.swift:

    func initialViewIndex(scroller: HorizontalScroller) -> Int {
      return currentAlbumIndex
    }

    Now the HorizontalScroller first view is set to whatever album is indicated by currentAlbumIndex. This is a great way to make sure the app experience remains personal and resumable.

    Run your app again. Scroll to an album as before, put the app in the background, stop the app, then relaunch to make sure the problem is fixed:

    swiftDesignPattern16

    If you look at PersistencyManager‘s init, you’ll notice the album data is hardcoded and recreated every time PersistencyManager is created. But it’s better to create the list of albums once and store them in a file. How would you save the Album data to a file?

    One option is to iterate through Album‘s properties, save them to a plist file and then recreate the Album instances when they’re needed. This isn’t the best option, as it requires you to write specific code depending on what data/properties are there in each class. For example, if you later created a Movie class with different properties, the saving and loading of that data would require new code.

    Additionally, you won’t be able to save the private variables for each class instance since they are not accessible to an external class. That’s exactly why Apple created the archiving mechanism.

    Archiving

    One of Apple’s specialized implementations of the Memento pattern is Archiving. This converts an object into a stream that can be saved and later restored without exposing private properties to external classes. You can read more about this functionality in Chapter 16 of the iOS 6 by Tutorials book. Or in Apple’s Archives and Serializations Programming Guide.

    How to Use Archiving

    First, you need to declare that Album can be archived by conforming to the NSCoding protocol. Open Album.swift and change the class line as follows:

    class Album: NSObject, NSCoding {

    Add the following two methods to Album.swift:

    required init(coder decoder: NSCoder) {
      super.init()
      self.title = decoder.decodeObjectForKey("title") as String?
      self.artist = decoder.decodeObjectForKey("artist") as String?
      self.genre = decoder.decodeObjectForKey("genre") as String?
      self.coverUrl = decoder.decodeObjectForKey("cover_url") as String?
      self.year = decoder.decodeObjectForKey("year") as String?
    }
     
    func encodeWithCoder(aCoder: NSCoder) {
      aCoder.encodeObject(title, forKey: "title")
      aCoder.encodeObject(artist, forKey: "artist")
      aCoder.encodeObject(genre, forKey: "genre")
      aCoder.encodeObject(coverUrl, forKey: "cover_url")
      aCoder.encodeObject(year, forKey: "year")
    }

    As part of the NSCoding protocol, encodeWithCoder will be called when you ask for an Album instance to be archived. Conversely, the init(coder:) initializer will be used to reconstruct or unarchive from a saved instance. It’s simple, yet powerful.

    Now that the Album class can be archived, add the code that actually saves and loads the list of albums.

    Add the following method to PersistencyManager.swift:

    func saveAlbums() {
      var filename = NSHomeDirectory().stringByAppendingString("/Documents/albums.bin")
      let data = NSKeyedArchiver.archivedDataWithRootObject(albums)
      data.writeToFile(filename, atomically: true)
    }

    This will be the method that’s called to save the albums. NSKeyedArchiver archives the album array into a file called albums.bin.

    When you archive an object which contains other objects, the archiver automatically tries to recursively archive the child objects and any child objects of the children and so on. In this instance, the archival starts with albums, which is an array of Album instances. Since Array and Album both support the NSCopying interface, everything in the array is automatically archived.

    Now replace init in PersistencyManager.swift with the following code:

    override init() {
      super.init()
      if let data = NSData(contentsOfFile: NSHomeDirectory().stringByAppendingString("/Documents/albums.bin")) {
        let unarchiveAlbums = NSKeyedUnarchiver.unarchiveObjectWithData(data) as [Album]?
          if let unwrappedAlbum = unarchiveAlbums {
            albums = unwrappedAlbum
          }
      } else {
        createPlaceholderAlbum()
      }
    }
     
    func createPlaceholderAlbum() {
      //Dummy list of albums
      let album1 = Album(title: "Best of Bowie",
    		     artist: "David Bowie",
    		     genre: "Pop",
    		     coverUrl: "http://www.coversproject.com/static/thumbs/album/album_david%20bowie_best%20of%20bowie.png",
    		     year: "1992")
     
    let album2 = Album(title: "It's My Life",
    		   artist: "No Doubt",
    		   genre: "Pop",
    		   coverUrl: "http://www.coversproject.com/static/thumbs/album/album_no%20doubt_its%20my%20life%20%20bathwater.png",
    		   year: "2003")
     
    let album3 = Album(title: "Nothing Like The Sun",
    	           artist: "Sting",
    		   genre: "Pop",
    		   coverUrl: "http://www.coversproject.com/static/thumbs/album/album_sting_nothing%20like%20the%20sun.png",
    		   year: "1999")
     
    let album4 = Album(title: "Staring at the Sun",
    		   artist: "U2",
    		   genre: "Pop",
    		   coverUrl: "http://www.coversproject.com/static/thumbs/album/album_u2_staring%20at%20the%20sun.png",
    		   year: "2000")
     
    let album5 = Album(title: "American Pie",
    		   artist: "Madonna",
    		   genre: "Pop",
    		   coverUrl: "http://www.coversproject.com/static/thumbs/album/album_madonna_american%20pie.png",
    		   year: "2000")
      albums = [album1, album2, album3, album4, album5]
      saveAlbums()
    }

    You have moved the placeholder album creation code into a separate method createPlaceholderAlbum() for readability. In the new code, NSKeyedUnarchiver loads the album data from the file, if it exists. If it doesn’t exist, it creates the album data and immediately saves it for the next launch of the app.

    You’ll also want to save the album data every time the app goes into the background. This might not seem necessary now but what if you later add the option to change album data? Then you’d want this to ensure that all your changes are saved.

    Since the main application accesses all services via LibraryAPI, this is how the application will let PersistencyManager know that it needs to save album data.

    Now add the method implementation to LibraryAPI.swift:

    func saveAlbums() {
      persistencyManager.saveAlbums()
    }

    This code simply passes on a call to LibraryAPI to save the albums on to PersistencyMangaer.

    Add the following code to the end of saveCurrentState in ViewController.swift:

    LibraryAPI.sharedInstance.saveAlbums()

    And the above code uses LibraryAPI to trigger the saving of album data whenever the ViewController saves its state.

    Build your app to check that everything compiles.

    Unfortunately, there’s no easy way to check if the data persistency is correct though. You can check the simulator Documents folder for your app in Finder to see that the album data file is created but in order to see any other changes you’d have to add in the ability to change album data.

    But instead of changing data, what if you added an option to delete albums you no longer want in your library? Additionally, wouldn’t it be nice to have an undo option if you delete an album by mistake?

    Final Touches

    You are going to add the final touches to your music application by allowing the user to perform delete actions to remove an album, or undo actions in case they change their mind!

    Add the following property to ViewController:

    // We will use this array as a stack to push and pop operation for the undo option
    var undoStack: [(Album, Int)] = []

    This creates an empty undo stack. The undoStack will hold a tuple of two arguments. The first is an Album and the second is the index of the album.

    Add the following code after reloadScroller() in viewDidLoad::

    let undoButton = UIBarButtonItem(barButtonSystemItem: .Undo, target: self, action:"undoAction")
    undoButton.enabled = false;
    let space = UIBarButtonItem(barButtonSystemItem: .FlexibleSpace, target:nil, action:nil)
    let trashButton = UIBarButtonItem(barButtonSystemItem: .Trash, target:self, action:"deleteAlbum")
    let toolbarButtonItems = [undoButton, space, trashButton]
    toolbar.setItems(toolbarButtonItems, animated: true)

    The above code creates a toolbar with two buttons and a flexible space between them. The undo button is disabled here because the undo stack starts off empty. Note that the toolbar is already in the storyboard, so all you need to do is set the toolbar items.

    You’ll add three method to ViewController.swift for handling album management actions: add, delete, and undo.

    The first is the method for adding a new album:

    func addAlbumAtIndex(album: Album,index: Int) {
      LibraryAPI.sharedInstance.addAlbum(album, index: index)
      currentAlbumIndex = index
      reloadScroller()
    }

    Here you add the album, set it as the current album index, and reload the scroller.

    Next comes the delete method:

    func deleteAlbum() {
      //1
      var deletedAlbum : Album = allAlbums[currentAlbumIndex]
      //2
      var undoAction = (deletedAlbum, currentAlbumIndex)
      undoStack.insert(undoAction, atIndex: 0)
      //3
      LibraryAPI.sharedInstance.deleteAlbum(currentAlbumIndex)
      reloadScroller()
      //4
      let barButtonItems = toolbar.items as [UIBarButtonItem]
      var undoButton : UIBarButtonItem = barButtonItems[0]
      undoButton.enabled = true
      //5
      if (allAlbums.count == 0) {
        var trashButton : UIBarButtonItem = barButtonItems[2]
        trashButton.enabled = false
      }
    }

    Consider each commented section below:

    1. Get the album to delete.
    2. Create a variable called undoAction which stores a tuple of Album and the index of the album. You then add the tuple into the stack
    3. Use LibraryAPI to delete the album from the data structure and reload the scroller.
    4. Since there’s an action in the undo stack, you need to enable the undo button.
    5. Lastly check to see if there are any albums left; if there aren’t any you can disable the trash button.

    Finally, add the method for the undo action:

    func undoAction() {
      let barButtonItems = toolbar.items as [UIBarButtonItem]
      //1		
      if undoStack.count > 0 {
        let (deletedAlbum, index) = undoStack.removeAtIndex(0)
        addAlbumAtIndex(deletedAlbum, index: index)
      }
      //2		
      if undoStack.count == 0 {
        var undoButton : UIBarButtonItem = barButtonItems[0]
        undoButton.enabled = false
      }
      //3		
      let trashButton : UIBarButtonItem = barButtonItems[2]
      trashButton.enabled = true
    }

    Finally consider the comments for the method above:

    1. The method “pops” the object out of the stack, giving you a tuple containing the deleted Album and its index. You then proceed to add the album back.
    2. Since you also deleted the last object in the stack when you “popped” it, you now need to check if the stack is empty. If it is, that means that there are no more actions to undo. So you disable the Undo button.
    3. You also know that since you undid an action, there should be at least one album cover. Hence you enable the trash button.

    Build and run your app to test out your undo mechanism, delete an album (or two) and hit the Undo button to see it in action:

    swiftDesignPattern1

    This is also a good place to test out whether changes to your album data is retained between sessions. Now, if you delete an album, send the app to the background, and then terminate the app, the next time you start the app the displayed album list should reflect the deletion.

    If you want to get all the albums back, just delete the app and run it again from Xcode to install a fresh copy with the starter data.

    Where to go from here?

    Here’s the source code for the finished project: BlueLibrarySwift-Final

    In this tutorial you saw how to harness the power of iOS design patterns to perform complicated tasks in a very straightforward and loosely coupled manner. You’ve learned a lot of iOS design patterns and concepts: Singleton, MVC, Delegation, Protocols, Facade, Observer, and Memento.

    Your final code is loosely coupled, reusable, and readable. If another developer looks at your code, they’ll easily be able to understand what’s going on and what each class does in your app.

    The point isn’t to use a design pattern for every line of code you write. Instead, be aware of design patterns when you consider how to solve a particular problem, especially in the early stages of designing your app. They’ll make your life as a developer much easier and your code a lot better!

    The long-standing classic book on the topic is Design Patterns: Elements of Reusable Object-Oriented Software. For code samples, check out the awesome project Design Patterns implemented in Swift on GitHub for many more design patters coded up in Swift.

    Finally, be sure to check out Intermediate Design Patterns in Swift for even more design patterns!

    Have more to say or ask about design patterns? Join in on the forum discussion below!

    Introducing iOS Design Patterns in Swift – Part 2/2 is a post from: Ray Wenderlich

    The post Introducing iOS Design Patterns in Swift – Part 2/2 appeared first on Ray Wenderlich.

    Video Tutorial: WatchKit Part 11: Page-Based Interfaces II

    The Great CALayer Tour Tech Talk Video

    $
    0
    0

    Each month, one of the members of the team gives a Tech Talk, and by popular request we also stream these live.

    Today in our December Tech Talk, tutorial team member Scott Gardner gave an excellent talk and Q&A on “The Great CALayer Tour”.

    Please excuse the few tech difficulties we had along the way – it was not our day w/ Internet connections, etc :P

    Here’s the video for anyone who didn’t get a chance to attend live!

    Helpful Links

    Here are some handy links related to the talk:

    Want to Join Us Next Month?

    Thanks again to Scott for giving a great talk and Q&A, having the guts to present to a live audience :] And thank you to everyone who attended – we hope you enjoyed it!

    Next month’s tech talk will be announced soon – we’ll post it on the sidebar of the site later, so be sure to check for it later.

    Hope to see some of you there! :]

    The Great CALayer Tour Tech Talk Video is a post from: Ray Wenderlich

    The post The Great CALayer Tour Tech Talk Video appeared first on Ray Wenderlich.

    Call for Applicants – Readers’ App Awards 2014!

    $
    0
    0
    Enter your app for our third annual Readers Apps Awards!

    Enter your app for our third annual Readers Apps Awards!

    This is just a quick note to let you know that our third annual Reader’s Apps Awards are coming up soon, where we recognize some of the best apps made by fellow raywenderlich.com readers.

    And the best part is it’s not too late for you to enter your app in the competition! :]

    We have a great set of judges lined up this year to look at all the entries:

    medal-poolosmedal-kerbermedal-rochonmedal-lowemedal-lockwoodmedal-ray

    Keep reading to learn more about the the categories, the prizes, and how to enter!

    Categories and Prizes

    To be eligible to win, you must be an active reader of this site and the tutorials or books must have helped you in some way to develop your app. Priority is given to active forum members and others we can verify are actual readers of this site.

    Also, your app must have come out this year (in 2014), obviously.

    Each app is eligible for every category but can only win one category. I’ll be selecting the finalists for each category from ALL the submissions and then the judges will select the winners. :]

    Grand Prize

    • Best Reader’s Game: Best game overall in terms of game play, polish, and graphics. Bonus points for GameCenter, Universal Binary, etc.
    • Best Reader’s App: Best app overall in terms of usefulness, polish, and interface. Bonus points for Universal Binary, iCloud, platform advantage (taking advantage of iOS specific features), etc.

    Honorable Mentions

    • Most Addicting: The App/Game that you can’t stop playing with.
    • Most Hilarious Idea: Its got that LoL factor :]
    • Most Surprisingly Good: The App/Game you didn’t think would be as good as it is at first glance.
    • Most Technically Impressive: The App/Game with particularly cool/impressive tech.
    • Most Visually Impressive: The App/Game that just looks really good!

    All winners get a free PDF of their choice from our site – plus massive bragging rights! :]

    How to Enter

    If you want a chance at winning, here’s what you should do:

    • Eligibility requirements: Again, to be eligible to win, you must be an active reader of this site and the tutorials or books must have helped you in some way to develop your app. Priority is given to active forum members and others we can verify are actual readers of this site.
    • If you’ve ever submitted your app for review on the site in the past: You’re already in the running! You don’t need to do anything, I remember all! ;]
    • If you haven’t submitted your app yet this year: You can do so right here!

    Note to be considered for this year’s Readers Apps Awards, you must submit your app before this Friday, December 12th. If you don’t make it, I’ll be here all year. ;]

    Best of luck to everyone, and stay tuned for the rewards announcements, which will be before Christmas! :]

    Call for Applicants – Readers’ App Awards 2014! is a post from: Ray Wenderlich

    The post Call for Applicants – Readers’ App Awards 2014! appeared first on Ray Wenderlich.

    Intermediate Design Patterns in Swift

    $
    0
    0
    Design patterns in Swift

    Learn design patterns in Swift with the “Tap the Larger Shape” game.

    Beginner’s note: New to design patterns? Check out our two-part tutorial, Introducing iOS Design Patterns in Swift for the basics before reading on!

    In this tutorial, you’ll learn to use design patterns in Swift to refactor a game called Tap the Larger Shape.

    Having knowledge of design patterns is crucial to writing apps that are maintainable and bug free. Knowing when to employ each design pattern is a skill that you can only learn with practice. Where better than to learn than this tutorial!

    But what exactly is a design pattern? It’s a formally documented solution to a common problem. For example, consider the common problem of looping over a collection of items — the design pattern you use here is the Iterator design pattern:

    var collection = ...
     
    // The for loop condition uses the Iterator design pattern
    for item in collection {
      println("Item is: \(item)")
    }

    The value of the Iterator design pattern is that it abstracts away the actual underlying mechanics of accessing items in the collection. Your code can access the items in a consistent manner regardless of whether collection is an array, dictionary or some other type.

    Not only that, but design patterns are part of the developer culture, so another developer maintaining or extending your code will likely understand the Iterator design pattern. They serve as a language for reasoning about software architecture.

    There are several design patterns that occur with great frequency in iOS programming, such as Model View Controller that appears in almost every app, and Delegation, a powerful, often underutilized, pattern that you certainly know if you’ve ever worked with table views. This tutorial discusses some lesser known but highly useful design patterns.

    If you’re unfamiliar with the concept of design patterns, you might want to bookmark this page, and head over to iOS Design Patterns Tutorial for an introduction.

    Getting Started

    Tap the Larger Shape is a fun but simple game where you’re presented with a pair of similar shapes and you need to tap the larger of the two. If you tap the larger shape, you gain a point. If you tap the smaller shape, you lose a point.

    It looks as though all that time you spent doodling random squares, circles and triangles as kid will finally pay off! :]

    Get started by downloading the starter project and opening it in Xcode.

    Note: You’ll want to use at least Xcode 6.1 for maximum Swift compatibility and stability.

    This starter project contains the full game. You’ll refactor the starter project throughout this tutorial and make use of design patterns to make your game more maintainable and more fun.

    Build and run the project on the iPhone 5 simulator, and tap a few shapes to understand how the game plays. You should see something like the image below:

    Tap the larger shape and gain points. :]

    Tap the larger shape and gain points. :]

    Tap the smaller shape and lose points.  :[

    Tap the smaller shape and lose points. :[

    Understanding the Game

    Before getting into the details of design patterns, take a look at the game as it’s currently written. Open Shape.swift take a look around and find the following code. You don’t need to make any changes, just look:

    import Foundation
    import UIKit
     
    class Shape {
    }
     
    class SquareShape: Shape {
      var sideLength: CGFloat!
    }

    The Shape class is the basic model for tappable shapes in the game. The concrete subclass SquareShape represents a square: a polygon with four equal-length sides.

    Next, open ShapeView.swift and take a look at the code for ShapeView:

    import Foundation
    import UIKit
     
    class ShapeView: UIView {
      var shape: Shape!
     
      // 1
      var showFill: Bool = true {
        didSet {
          setNeedsDisplay()
        }
      }
      var fillColor: UIColor = UIColor.orangeColor() {
        didSet {
          setNeedsDisplay()
        }
      }
     
      // 2
      var showOutline: Bool = true {
        didSet {
          setNeedsDisplay()
        }
      }
      var outlineColor: UIColor = UIColor.grayColor() {
        didSet {
          setNeedsDisplay()
        }
      }
     
      // 3
      var tapHandler: ((ShapeView) -> ())?
     
      override init(frame: CGRect) {
        super.init(frame: frame)
     
        // 4
        let tapRecognizer = UITapGestureRecognizer(target: self, action: Selector("handleTap"))
        addGestureRecognizer(tapRecognizer)
      }
     
      required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
      }
     
      func handleTap() {
      	// 5
        tapHandler?(self)
      }
     
      let halfLineWidth: CGFloat = 3.0
    }

    ShapeView is the view that renders a generic Shape model. Line by line, here’s what’s happening in that block:

    1. Indicate if the app should fill the shape with a color, and if so, which color. This is the solid interior color of the shape.
    2. Indicate if the app should stroke the shape’s outline with a color, and if so, which color. This is the color of the shape’s border.
    3. A closure that handles taps (e.g. to adjust the score). If you’re not familiar with Swift closures, you can review them in this Swift Functional Programming Tutorial, but keep in mind they’re similar to Objective C blocks.
    4. Set up a tap gesture recognizer that invokes handleTap when the player taps the view.
    5. Invoke the tapHandler when the gesture recognizer recognizes a tap gesture.

    Now scroll down and examine SquareShapeView:

    class SquareShapeView: ShapeView {
      override func drawRect(rect: CGRect) {
        super.drawRect(rect)
     
        // 1
        if showFill {
          fillColor.setFill()
          let fillPath = UIBezierPath(rect: bounds)
          fillPath.fill()
        }
     
        // 2
        if showOutline {
          outlineColor.setStroke()
     
          // 3
          let outlinePath = UIBezierPath(rect: CGRect(x: halfLineWidth, y: halfLineWidth, width: bounds.size.width - 2 * halfLineWidth, height: bounds.size.height - 2 * halfLineWidth))
          outlinePath.lineWidth = 2.0 * halfLineWidth
          outlinePath.stroke()
        }
      }
    }

    Here’s how SquareShapeView draws itself:

    1. If configured to show fill, then fill in the view with the fill color.
    2. If configured to show an outline, then outline the view with the outline color.
    3. Since iOS draws lines that are centered over their position, you need to inset the view bounds by halfLineWidth when stroking the path.

    Excellent, now that you understand how the game draws its shapes, open GameViewController.swift and have a look at the game logic:

    import UIKit
     
    class GameViewController: UIViewController {
     
      override func viewDidLoad() {
        super.viewDidLoad()
        // 1
        beginNextTurn()
      }
     
      override func prefersStatusBarHidden() -> Bool {
        return true
      }
     
      private func beginNextTurn() {
        // 2
        let shape1 = SquareShape()
        shape1.sideLength = Utils.randomBetweenLower(0.3, andUpper: 0.8)
        let shape2 = SquareShape()
        shape2.sideLength = Utils.randomBetweenLower(0.3, andUpper: 0.8)
     
        // 3
        let availSize = gameView.sizeAvailableForShapes()
     
        // 4
        let shapeView1: ShapeView =
          SquareShapeView(frame: CGRect(x: 0,
                                        y: 0,
                                        width: availSize.width * shape1.sideLength,
                                        height: availSize.height * shape1.sideLength))
        shapeView1.shape = shape1
        let shapeView2: ShapeView =
          SquareShapeView(frame: CGRect(x: 0,
                                        y: 0,
                                        width: availSize.width * shape2.sideLength,
                                        height: availSize.height * shape2.sideLength))
        shapeView2.shape = shape2
     
        // 5
        let shapeViews = (shapeView1, shapeView2)
     
        // 6
        shapeViews.0.tapHandler = {
          tappedView in
          self.gameView.score += shape1.sideLength >= shape2.sideLength ? 1 : -1
          self.beginNextTurn()
        }
        shapeViews.1.tapHandler = {
          tappedView in
          self.gameView.score += shape2.sideLength >= shape1.sideLength ? 1 : -1
          self.beginNextTurn()
        }
     
        // 7
        gameView.addShapeViews(shapeViews)
      }
     
      private var gameView: GameView { return view as GameView }
    }

    Here’s how the game logic works:

    1. Begin a turn as soon as the GameView loads.
    2. Create a pair of square shapes with random side lengths drawn as proportions in the range [0.3, 0.8]. The shapes will also scale to any screen size.
    3. Ask the GameView what size is available for each shape based on the current screen size.
    4. Create a SquareShapeView for each shape, and size the shape by multiplying the shape’s sideLength proportion by the appropriate availSize dimension of the current screen.
    5. Store the shapes in a tuple for easier manipulation.
    6. Set the tap handler on each shape view to adjust the score based on whether the player tapped the larger view or not.
    7. Add the shapes to the GameView so it can lay out the shapes and display them.

    That’s it. That’s the complete game logic. Pretty simple, right? :]

    Why Use Design Patterns?

    You’re probably wondering to yourself, “Hmmm, so why do I need design patterns when I have a working game?” Well, what if you want to support shapes other than just squares?

    You could add code to create a second shape in beginNextTurn, but as you add a third, fourth or even fifth type of shape the code would become unmanageable.

    And what if you want the player to be able to select the shape she plays?

    If you lump all of that code together in GameViewController you’ll end up with tightly-coupled code containing hard-coded dependencies that will be difficult to manage.

    Here’s the answer to your question: design patterns help decouple your code into nicely-separated bits.

    Before moving on, I have a confession; I already snuck in a design pattern. :]
    ragecomic1

    Solution Inside: Can You Spot the Design Pattern? SelectShow>

    Now, on to the design patterns. Each section from here on describes a different design pattern. Let’s get going!

    Design Pattern: Abstract Factory

    GameViewController is tightly coupled with the SquareShapeView, and that doesn’t allow much room to later use a different view to represent squares or introduce a second shape.

    Your first task is to decouple and simplify your GameViewController using the Abstract Factory design pattern. You’re going to use this pattern in code that establishes an API for constructing a group of related objects, like the shape views you’ll work with momentarily, without hard-coding specific classes.

    Click File\New\File… and then select iOS\Source\Swift File. Call the file ShapeViewFactory.swift, save it and then replace its contents with the code below:

    import Foundation
    import UIKit
     
    // 1
    protocol ShapeViewFactory {
      // 2
      var size: CGSize { get set }
      // 3
      func makeShapeViewsForShapes(shapes: (Shape, Shape)) -> (ShapeView, ShapeView)
    }

    Here’s how your new factory works:

    1. Define ShapeViewFactory as a Swift protocol. There’s no reason for it to be a class or struct since it only describes an interface and has no functionality itself.
    2. Each factory should have a size that defines the bounding box of the shapes it creates. This is essential to layout code using the factory-produced views.
    3. Define the method that produces shape views. This is the “meat” of the factory. It takes a tuple of two Shape objects and returns a tuple of two ShapeView objects. This essentially manufactures views from its raw materials — the models.

    Add the following code to end of ShapeViewFactory.swift:

    class SquareShapeViewFactory: ShapeViewFactory {
      var size: CGSize
     
      // 1
      init(size: CGSize) {
        self.size = size
      }
     
      func makeShapeViewsForShapes(shapes: (Shape, Shape)) -> (ShapeView, ShapeView) {
        // 2
        let squareShape1 = shapes.0 as SquareShape
        let shapeView1 = 
          SquareShapeView(frame: CGRect(x: 0,
                                        y: 0,
                                        width: squareShape1.sideLength * size.width,
                                        height: squareShape1.sideLength * size.height))
        shapeView1.shape = squareShape1
     
        // 3
        let squareShape2 = shapes.1 as SquareShape
        let shapeView2 =
          SquareShapeView(frame: CGRect(x: 0,
                                        y: 0,
                                        width: squareShape2.sideLength * size.width,
                                        height: squareShape2.sideLength * size.height))
        shapeView2.shape = squareShape2
     
        // 4
        return (shapeView1, shapeView2)
      }
    }

    Your SquareShapeViewFactory produces SquareShapeView instances as follows:

    1. Initialize the factory to use a consistent maximum size.
    2. Construct the first shape view from the first passed shape.
    3. Construct the second shape view from the second passed shape.
    4. Return a tuple containing the two created shape views.

    Finally, it’s time to put SquareShapeViewFactory to use. Open GameViewController.swift, and replace its contents with the following:

    import UIKit
     
    class GameViewController: UIViewController {
     
      override func viewDidLoad() {
        super.viewDidLoad()
     
        // 1 ***** ADDITION
        shapeViewFactory = SquareShapeViewFactory(size: gameView.sizeAvailableForShapes())
     
        beginNextTurn()
      }
     
      override func prefersStatusBarHidden() -> Bool {
        return true
      }
     
      private func beginNextTurn() {
        let shape1 = SquareShape()
        shape1.sideLength = Utils.randomBetweenLower(0.3, andUpper: 0.8)
        let shape2 = SquareShape()
        shape2.sideLength = Utils.randomBetweenLower(0.3, andUpper: 0.8)
     
        // 2 ***** ADDITION
        let shapeViews = shapeViewFactory.makeShapeViewsForShapes((shape1, shape2))
     
        shapeViews.0.tapHandler = {
          tappedView in
          self.gameView.score += shape1.sideLength >= shape2.sideLength ? 1 : -1
          self.beginNextTurn()
        }
        shapeViews.1.tapHandler = {
          tappedView in
          self.gameView.score += shape2.sideLength >= shape1.sideLength ? 1 : -1
          self.beginNextTurn()
        }
     
        gameView.addShapeViews(shapeViews)
      }
     
      private var gameView: GameView { return view as GameView }
     
      // 3 ***** ADDITION
      private var shapeViewFactory: ShapeViewFactory!
    }

    There are three new lines of code:

    1. Initialize and store a SquareShapeViewFactory.
    2. Use this new factory to create your shape views.
    3. Store your new shape view factory as an instance property.

    The key benefits are in section two, where you replaced six lines of code with one. Better yet, you moved the complex shape view creation code out of GameViewController to make the class smaller and easier to follow.

    It’s helpful to move view creation code out of your view controller since GameViewController acts as a view controller and coordinates between model and view.

    Build and run, and then you should see something like the following:

    Screenshot4

    Nothing about your game’s visuals changed, but you did simplify your code.

    If you were to replace SquareShapeView with SomeOtherShapeView, then the benefits of the SquareShapeViewFactory would shine. Specifically, you wouldn’t need to alter GameViewController, and you could isolate all the changes to SquareShapeViewFactory.

    Now that you’ve simplified the creation of shape views, you’re going to simplify the creation of shapes. Create a new Swift file like before, called ShapeFactory.swift, and paste in the following code:

    import Foundation
    import UIKit
     
    // 1
    protocol ShapeFactory {
      func createShapes() -> (Shape, Shape)
    }
     
    class SquareShapeFactory: ShapeFactory {
      // 2
      var minProportion: CGFloat
      var maxProportion: CGFloat
     
      init(minProportion: CGFloat, maxProportion: CGFloat) {
        self.minProportion = minProportion
        self.maxProportion = maxProportion
      }
     
      func createShapes() -> (Shape, Shape) {
        // 3
        let shape1 = SquareShape()
        shape1.sideLength = Utils.randomBetweenLower(minProportion, andUpper: maxProportion)
     
        // 4
        let shape2 = SquareShape()
        shape2.sideLength = Utils.randomBetweenLower(minProportion, andUpper: maxProportion)
     
        // 5
        return (shape1, shape2)
      }
    }

    Your new ShapeFactory produces shapes as follows:

    1. Again, you’ve declared the ShapeFactory as a protocol to build in maximum flexibility, just like you did for ShapeViewFactory.
    2. You want your shape factory to produce shapes that have dimensions in unit terms, for instance, in a range like [0, 1] — so you store this range.
    3. Create the first square shape with random dimensions.
    4. Create the second square shape with random dimensions.
    5. Return the pair of square shapes as a tuple.

    Now open GameViewController.swift and insert the following line at the bottom just before the closing curly brace:

    private var shapeFactory: ShapeFactory!

    Then insert the following line near the bottom of viewDidLoad, just above the invocation of beginNextTurn:

    shapeFactory = SquareShapeFactory(minProportion: 0.3, maxProportion: 0.8)

    Finally, replace beginNextTurn with this code:

    private func beginNextTurn() {
      // 1
      let shapes = shapeFactory.createShapes()
     
      let shapeViews = shapeViewFactory.makeShapeViewsForShapes(shapes)
     
      shapeViews.0.tapHandler = {
        tappedView in
        // 2
        let square1 = shapes.0 as SquareShape, square2 = shapes.1 as SquareShape
        // 3
        self.gameView.score += square1.sideLength >= square2.sideLength ? 1 : -1
        self.beginNextTurn()
      }
      shapeViews.1.tapHandler = {
        tappedView in
        let square1 = shapes.0 as SquareShape, square2 = shapes.1 as SquareShape
        self.gameView.score += square2.sideLength >= square1.sideLength ? 1 : -1
        self.beginNextTurn()
      }
     
      gameView.addShapeViews(shapeViews)
    }

    Section by section, here’s what that does.

    1. Use your new shape factory to create a tuple of shapes.
    2. Extract the shapes from the tuple…
    3. …so that you can compare them here.

    Once again, using the Abstract Factory design pattern simplified your code by moving shape generation out of GameViewController.

    Design Pattern: Servant

    At this point you can almost add a second shape, for example, a circle. Your only hard-coded dependence on squares is in the score calculation in beginNextTurn in code like the following:

    shapeViews.1.tapHandler = {
      tappedView in
      // 1
      let square1 = shapes.0 as SquareShape, square2 = shapes.1 as SquareShape
     
      // 2
      self.gameView.score += square2.sideLength >= square1.sideLength ? 1 : -1
      self.beginNextTurn()
    }

    Here you cast the shapes to SquareShape so that you can access their sideLength. Circles don’t have a sideLength, instead they have a diameter.

    The solution is to use the Servant design pattern, which provides a behavior like score calculation to a group of classes like shapes, via a common interface. In your case, the score calculation will be the servant, the shapes will be the serviced classes, and an area property plays the role of the common interface.

    Open Shape.swift and add the following line to the bottom of the Shape class:

    var area: CGFloat { return 0 }

    Then add the following line to the bottom of the SquareShape class:

    override var area: CGFloat { return sideLength * sideLength }

    You can see where this is going — you can calculate which shape is larger based on its area.

    Open GameViewController.swift and replace beginNextTurn with the following:

    private func beginNextTurn() {
      let shapes = shapeFactory.createShapes()
     
      let shapeViews = shapeViewFactory.makeShapeViewsForShapes(shapes)
     
      shapeViews.0.tapHandler = {
        tappedView in
        // 1
        self.gameView.score += shapes.0.area >= shapes.1.area ? 1 : -1
        self.beginNextTurn()
      }
      shapeViews.1.tapHandler = {
        tappedView in
        // 2
        self.gameView.score += shapes.1.area >= shapes.0.area ? 1 : -1
        self.beginNextTurn()
      }
     
      gameView.addShapeViews(shapeViews)
    }
    1. Determines the larger shape based on the shape area.
    2. Also determines the larger shape based on the shape area.

    Build and run, and you should see something like the following — the game looks the same, but the code is now more flexible.

    Screenshot6

    Congratulations, you’ve completely removed dependencies on squares from your game logic. If you were to create and use some circle factories, your game would become more…well-rounded. :]

    ragecomic2

    Leveraging Abstract Factory for Gameplay Versatility

    “Don’t be a square!” can be an insult in real life, and your game feels like it’s been boxed in to one shape — it aspires to smoother lines and more aerodynamic shapes

    You need to introduce some smooth “circley goodness.” Open Shape.swift, and then add the following code at the bottom of the file:

    class CircleShape: Shape {
        var diameter: CGFloat!
        override var area: CGFloat { return CGFloat(M_PI) * diameter * diameter / 4.0 }
    }

    Your circle only needs to know the diameter from which it can compute its area, and thus support the Servant pattern.

    Next, build CircleShape objects by adding a CircleShapeFactory. Open ShapeFactory.swift, and add the following code at the bottom of the file:

    class CircleShapeFactory: ShapeFactory {
      var minProportion: CGFloat
      var maxProportion: CGFloat
     
      init(minProportion: CGFloat, maxProportion: CGFloat) {
        self.minProportion = minProportion
        self.maxProportion = maxProportion
      }
     
      func createShapes() -> (Shape, Shape) {
        // 1
        let shape1 = CircleShape()
        shape1.diameter = Utils.randomBetweenLower(minProportion, andUpper: maxProportion)
     
        // 2
        let shape2 = CircleShape()
        shape2.diameter = Utils.randomBetweenLower(minProportion, andUpper: maxProportion)
     
        return (shape1, shape2)
      }
    }

    This code follows a familiar pattern: Section 1 and Section 2 create a CircleShape and assign it a random diameter.

    You need to solve another problem, and doing so might just prevent a messy Geometry Revolution. See, what you have right now is “Geometry Without Representation,” and you know how wound up shapes can get when they feel underrepresented. (haha!)

    It’s easy to please your constituents; all you need to is represent your new CircleShape objects on the screen with a CircleShapeView. :]

    Open ShapeView.swift and add the following at the bottom of the file:

    class CircleShapeView: ShapeView {
      override init(frame: CGRect) {
        super.init(frame: frame)
        // 1
        self.opaque = false
        // 2
        self.contentMode = UIViewContentMode.Redraw
      }
     
      required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
      }
     
      override func drawRect(rect: CGRect) {
        super.drawRect(rect)
     
        if showFill {
          fillColor.setFill()
          // 3
          let fillPath = UIBezierPath(ovalInRect: self.bounds)
          fillPath.fill()
        }
     
        if showOutline {
          outlineColor.setStroke()
          // 4
          let outlinePath = UIBezierPath(ovalInRect: CGRect(
            x: halfLineWidth,
            y: halfLineWidth,
            width: self.bounds.size.width - 2 * halfLineWidth,
            height: self.bounds.size.height - 2 * halfLineWidth))
          outlinePath.lineWidth = 2.0 * halfLineWidth
          outlinePath.stroke()
        }
      }
    }

    Explanations of the above that take each section in turn:

    1. Since a circle cannot fill the rectangular bounds of its view, you need to tell UIKit that the view is not opaque, meaning content behind it may poke through. If you miss this, then the circles will have an ugly black background.
    2. Because the view is not opaque, you should redraw the view when its bounds change.
    3. Draw a circle filled with the fillColor. In a moment, you’ll create CircleShapeViewFactory, which will ensurethat CircleView has equal width and height so the shape will be a circle and not an ellipse.
    4. Stroke the outline border of the circle and inset to account for line width.

    Now you’ll create CircleShapeView objects in a CircleShapeViewFactory.

    Open ShapeViewFactory.swift and add the following code at the bottom of the file:

    class CircleShapeViewFactory: ShapeViewFactory {
      var size: CGSize
     
      init(size: CGSize) {
        self.size = size
      }
     
      func makeShapeViewsForShapes(shapes: (Shape, Shape)) -> (ShapeView, ShapeView) {
        let circleShape1 = shapes.0 as CircleShape
        // 1
        let shapeView1 = CircleShapeView(frame: CGRect(
          x: 0,
          y: 0,
          width: circleShape1.diameter * size.width,
          height: circleShape1.diameter * size.height))
        shapeView1.shape = circleShape1
     
        let circleShape2 = shapes.1 as CircleShape
        // 2
        let shapeView2 = CircleShapeView(frame: CGRect(
          x: 0,
          y: 0,
          width: circleShape2.diameter * size.width,
          height: circleShape2.diameter * size.height))
        shapeView2.shape = circleShape2
     
        return (shapeView1, shapeView2)
      }
    }

    This is the factory that will create circles instead of squares. Section 1 and Section 2 are creating CircleShapeView instances by using the passed in shapes. Notice how your code is makes sure the circles have equal width and height so they render as perfect circles and not ellipses.

    Finally, open GameViewController.swift and replace the lines in viewDidLoad that assign the shape and view factories with the following:

    shapeViewFactory = CircleShapeViewFactory(size: gameView.sizeAvailableForShapes())
    shapeFactory = CircleShapeFactory(minProportion: 0.3, maxProportion: 0.8)

    Now build and run and you should see something like the following screenshot.

    Screenshot7
    Lookee there. You made circles!

    Notice how you were able to add a new shape without much impact on your game’s logic in GameViewController? The Abstract Factory and Servant design patterns made this possible.

    Design Pattern: Builder

    Now it’s time to examine a third design pattern: Builder.

    Suppose you want to vary the appearance of your ShapeView instances — whether they should show fill and outline colors and what colors to use. The Builder design pattern makes such object configuration easier and more flexible.

    One approach to solve this configuration problem would be to add a variety of constructors, either class convenience methods like CircleShapeView.redFilledCircleWithBlueOutline() or initializers with a variety of arguments and default values.

    Unfortunately, it’s not a scalable technique as you’d need to write a new method or initializer for every combination.

    Builder solves this problem rather elegantly because it creates a class with a single purpose — configure an already initialized object. If you set up your builder to build red circles and then later blue circles, it’ll do so without need to alter CircleShapeView.

    Create a new file ShapeViewBuilder.swift and replace its contents with the following code:

    import Foundation
    import UIKit
     
    class ShapeViewBuilder {
      // 1
      var showFill  = true
      var fillColor = UIColor.orangeColor()
     
      // 2
      var showOutline  = true
      var outlineColor = UIColor.grayColor()
     
      // 3
      init(shapeViewFactory: ShapeViewFactory) {
        self.shapeViewFactory = shapeViewFactory
      }
     
      // 4
      func buildShapeViewsForShapes(shapes: (Shape, Shape)) -> (ShapeView, ShapeView) {
        let shapeViews = shapeViewFactory.makeShapeViewsForShapes(shapes)
        configureShapeView(shapeViews.0)
        configureShapeView(shapeViews.1)
        return shapeViews
      }
     
      // 5
      private func configureShapeView(shapeView: ShapeView) {
        shapeView.showFill  = showFill
        shapeView.fillColor = fillColor
        shapeView.showOutline  = showOutline
        shapeView.outlineColor = outlineColor
      }
     
      private var shapeViewFactory: ShapeViewFactory
    }

    Here’s how your new ShapeViewBuilder works:

    1. Store configuration to set ShapeView fill properties.
    2. Store configuration to set ShapeView outline properties.
    3. Initialize the builder to hold a ShapeViewFactory to construct the views. This means the builder doesn’t need to know if it’s building SquareShapeView or CircleShapeView or even some other kind of shape view.
    4. This is the public API; it creates and initializes a pair of ShapeView when there’s a pair of Shape.
    5. Do the actual configuration of a ShapeView based on the builder’s stored configuration.

    Deploying your spiffy new ShapeViewBuilder is as easy as opening GameViewController.swift and adding the following code to the bottom of the class, just before the closing curly brace:

    private var shapeViewBuilder: ShapeViewBuilder!

    Now, populate your new property by adding the following code to viewDidLoad just above the line that invokes beginNextTurn:

    shapeViewBuilder = ShapeViewBuilder(shapeViewFactory: shapeViewFactory)
    shapeViewBuilder.fillColor = UIColor.brownColor()
    shapeViewBuilder.outlineColor = UIColor.orangeColor()

    Finally replace the line that creates shapeViews in beginNextTurn with the following:

    let shapeViews = shapeViewBuilder.buildShapeViewsForShapes(shapes)

    Build and run, and you should see something like this:

    Screenshot8

    Notice how your circles are now a pleasant brown with orange outlines — I know you must be amazed by the stunning design here, but please don’t try to hire me to be your interior decorator. ;]

    Now to reinforce the power of the Builder pattern. With GameViewController.swift still open, change your viewDidLoad to use square factories:

    shapeViewFactory = SquareShapeViewFactory(size: gameView.sizeAvailableForShapes())
    shapeFactory = SquareShapeFactory(minProportion: 0.3, maxProportion: 0.8)

    Build and run, and you should see this.

    Screenshot9

    Notice how the Builder pattern made it easy to apply a new color scheme to squares as well as to circles. Without it, you’d need color configuration code in both CircleShapeViewFactory and SquareShapeViewFactory.

    Furthermore, changing to another color scheme would involve widespread code changes. By restricting ShapeView color configuration to a single ShapeViewBuilder, you also isolate color changes to a single class.

    Design Pattern: Dependency Injection

    Every time you tap a shape, you’re taking a turn in your game, and each turn can be a match or not a match.

    Wouldn’t it be helpful if your game could track all the turns, stats and award point bonuses for hot streaks?

    Create a new file called Turn.swift, and replace its contents with the following code:

    import Foundation
     
    class Turn {
      // 1
      let shapes: [Shape]
      var matched: Bool?
     
      init(shapes: [Shape]) {
        self.shapes = shapes
      }
     
      // 2
      func turnCompletedWithTappedShape(tappedShape: Shape) {
        var maxArea = shapes.reduce(0) { $0 > $1.area ? $0 : $1.area }
        matched = tappedShape.area >= maxArea
      }
    }

    Your new Turn class does the following:

    1. Store the shapes that the player saw during the turn, and also whether the turn was a match or not.
    2. Records the completion of a turn after a player taps a shape.

    To control the sequence of turns your players play, create a new file named TurnController.swift, and replace its contents with the following code:

    import Foundation
     
    class TurnController {
      // 1
      var currentTurn: Turn?
      var pastTurns: [Turn] = [Turn]()
     
      // 2
      init(shapeFactory: ShapeFactory, shapeViewBuilder: ShapeViewBuilder) {
        self.shapeFactory = shapeFactory
        self.shapeViewBuilder = shapeViewBuilder
      }
     
      // 3
      func beginNewTurn() -> (ShapeView, ShapeView) {
        let shapes = shapeFactory.createShapes()
        let shapeViews = shapeViewBuilder.buildShapeViewsForShapes(shapes)
        currentTurn = Turn(shapes: [shapeViews.0.shape, shapeViews.1.shape])
        return shapeViews
      }
     
      // 4
      func endTurnWithTappedShape(tappedShape: Shape) -> Int {
        currentTurn!.turnCompletedWithTappedShape(tappedShape)
        pastTurns.append(currentTurn!)
     
        var scoreIncrement = currentTurn!.matched! ? 1 : -1
     
        return scoreIncrement
      }
     
      private let shapeFactory: ShapeFactory
      private var shapeViewBuilder: ShapeViewBuilder
    }

    Your TurnController works as follows:

    1. Stores both the current turn and past turns.
    2. Accepts a ShapeFactory and ShapeViewBuilder.
    3. Uses this factory and builder to create shapes and views for each new turn and records the current turn.
    4. Records the end of a turn after the player taps a shape, and returns the computed score based on whether the turn was a match or not.

    Now open GameViewController.swift, and add the following code at the bottom, just above the closing curly brace:

    private var turnController: TurnController!

    Scroll up to viewDidLoad, and just before the line invoking beginNewTurn, insert the following code:

    turnController = TurnController(shapeFactory: shapeFactory, shapeViewBuilder: shapeViewBuilder)

    Replace beginNextTurn with the following:

    private func beginNextTurn() {
      // 1
      let shapeViews = turnController.beginNewTurn()
     
      shapeViews.0.tapHandler = {
        tappedView in
        // 2
        self.gameView.score += self.turnController.endTurnWithTappedShape(tappedView.shape)
        self.beginNextTurn()
      }
     
      // 3
      shapeViews.1.tapHandler = shapeViews.0.tapHandler
     
      gameView.addShapeViews(shapeViews)
    }

    Your new code works as follows:

    1. Asks the TurnController to begin a new turn and return a tuple of ShapeView to use for the turn.
    2. Informs the turn controller that the turn is over when the player taps a ShapeView, and then it increments the score. Notice how TurnController abstracts score calculation away, further simplifying GameViewController.
    3. Since you removed explicit references to specific shapes, the second shape view can share the same tapHandler closure as the first shape view.

    An example of the Dependency Injection design pattern is that it passes in its dependencies to the TurnController initializer. The initializer parameters essentially inject the shape and shape view factory dependencies.

    Since TurnController makes no assumptions about which type of factories to use, you’re free to swap in different factories.

    Not only does this make your game more flexible, but it makes automated testing easier since it allows you to pass in special TestShapeFactory and TestShapeViewFactory classes if you desire. These could be special stubs or mocks that would make testing easier, more reliable or faster.

    Build and run and check that it looks like this:

    Screenshot10

    There are no visual differences, but TurnController has opened up your code so it can use more sophisticated turn strategies: calculating scores based on streaks of turns, alternating shape type between turns, or even adjusting the difficulty of play based on the player’s performance.

    Design Pattern: Strategy

    I’m happy because I’m eating a piece of pie while writing this tutorial. Perhaps that’s why it was imperative to add circles to the game. :]

    You should be happy because you’ve done a great job using design patterns to refactor your game code so that it’s easy to expand and maintain.

    ragecomic3

    Speaking of pie, err, Pi, how do you get those circles back in your game? Right now your GameViewController can use either circles or squares, but only one or the other. It doesn’t have to be all restrictive like that.

    Next, you’ll use the Strategy design pattern to manage which shapes your game produces.

    The Strategy design pattern allows you to design algorithm behaviors based on what your program determines at runtime. In this case, the algorithm will choose which shapes to present to the player.

    You can design many different algorithms: one that picks shapes randomly, one that picks shapes to challenge the player or help him be more successful, and so on. Strategy works by defining a family of algorithms through abstract declarations of the behavior that each strategy must implement. This makes the algorithms within the family interchangeable.

    If you guessed that you’re going to implement the Strategy as a Swift protocol, you guessed correctly!

    Create a new file named TurnStrategy.swift, and replace its contents with the following code:

    import Foundation
     
    // 1
    protocol TurnStrategy {
      func makeShapeViewsForNextTurnGivenPastTurns(pastTurns: [Turn]) -> (ShapeView, ShapeView)
    }
     
    // 2
    class BasicTurnStrategy: TurnStrategy {
      let shapeFactory: ShapeFactory
      let shapeViewBuilder: ShapeViewBuilder
     
      init(shapeFactory: ShapeFactory, shapeViewBuilder: ShapeViewBuilder) {
        self.shapeFactory = shapeFactory
        self.shapeViewBuilder = shapeViewBuilder
      }
     
      func makeShapeViewsForNextTurnGivenPastTurns(pastTurns: [Turn]) -> (ShapeView, ShapeView) {
        return shapeViewBuilder.buildShapeViewsForShapes(shapeFactory.createShapes())
      }
    }
     
    class RandomTurnStrategy: TurnStrategy {
      // 3
      let firstStrategy: TurnStrategy
      let secondStrategy: TurnStrategy
     
      init(firstStrategy: TurnStrategy, secondStrategy: TurnStrategy) {
        self.firstStrategy = firstStrategy
        self.secondStrategy = secondStrategy
      }
     
      // 4
      func makeShapeViewsForNextTurnGivenPastTurns(pastTurns: [Turn]) -> (ShapeView, ShapeView) {
        if Utils.randomBetweenLower(0.0, andUpper: 100.0) < 50.0 {
          return firstStrategy.makeShapeViewsForNextTurnGivenPastTurns(pastTurns)
        } else {
          return secondStrategy.makeShapeViewsForNextTurnGivenPastTurns(pastTurns)
        }
      }
    }

    Here’s what your new TurnStrategy does line-by-line:

    1. Declare the behavior of the algorithm. This is defined in a protocol, with one method. The method takes an array of the past turns in the game, and returns the shape views to display for the next turn.
    2. Implement a basic strategy that uses a ShapeFactory and ShapeViewBuilder. This strategy implements the existing behavior, where the shape views just come from the single factory and builder as before. Notice how you’re using Dependency Injection again here, and that means this strategy doesn’t care which factory or builder it’s using.
    3. Implement a random strategy which randomly uses one of two other strategies. You’ve used composition here so that RandomTurnStrategy can behave like two potentially different strategies. However, since it’s a Strategy, that composition is hidden from whatever code uses RandomTurnStrategy.
    4. This is the meat of the random strategy. It randomly selects either the first or second strategy with a 50 percent chance.

    Now you need to use your strategies. Open TurnController.swift, and replace its contents with the following:

    import Foundation
     
    class TurnController {
      var currentTurn: Turn?
      var pastTurns: [Turn] = [Turn]()
     
      // 1
      init(turnStrategy: TurnStrategy) {
        self.turnStrategy = turnStrategy
      }
     
      func beginNewTurn() -> (ShapeView, ShapeView) {
        // 2
        let shapeViews = turnStrategy.makeShapeViewsForNextTurnGivenPastTurns(pastTurns)
        currentTurn = Turn(shapes: [shapeViews.0.shape, shapeViews.1.shape])
        return shapeViews
      }
     
      func endTurnWithTappedShape(tappedShape: Shape) -> Int {
        currentTurn!.turnCompletedWithTappedShape(tappedShape)
        pastTurns.append(currentTurn!)
     
        var scoreIncrement = currentTurn!.matched! ? 1 : -1
     
        return scoreIncrement
      }
     
      private let turnStrategy: TurnStrategy
    }

    Here’s what’s happening, section by section:

    1. Accepts a passed strategy and stores it on the TurnController instance.
    2. Uses the strategy to generate the ShapeView objects so the player can begin a new turn.

    Note: This will cause a syntax error in GameViewController.swift. Don’t worry, it’s only temporary. You’re going to fix the error in the very next step.

    Your last step to use the Strategy design pattern is to adapt your GameViewController to use your TurnStrategy.

    Open GameViewController.swift and replace its contents with the following:

    import UIKit
     
    class GameViewController: UIViewController {
     
      override func viewDidLoad() {
        super.viewDidLoad()
     
        // 1
        let squareShapeViewFactory = SquareShapeViewFactory(size: gameView.sizeAvailableForShapes())
        let squareShapeFactory = SquareShapeFactory(minProportion: 0.3, maxProportion: 0.8)
        let squareShapeViewBuilder = shapeViewBuilderForFactory(squareShapeViewFactory)
        let squareTurnStrategy = BasicTurnStrategy(shapeFactory: squareShapeFactory, shapeViewBuilder: squareShapeViewBuilder)
     
        // 2
        let circleShapeViewFactory = CircleShapeViewFactory(size: gameView.sizeAvailableForShapes())
        let circleShapeFactory = CircleShapeFactory(minProportion: 0.3, maxProportion: 0.8)
        let circleShapeViewBuilder = shapeViewBuilderForFactory(circleShapeViewFactory)
        let circleTurnStrategy = BasicTurnStrategy(shapeFactory: circleShapeFactory, shapeViewBuilder: circleShapeViewBuilder)
     
        // 3
        let randomTurnStrategy = RandomTurnStrategy(firstStrategy: squareTurnStrategy, secondStrategy: circleTurnStrategy)
     
        // 4
        turnController = TurnController(turnStrategy: randomTurnStrategy)
     
        beginNextTurn()
      }
     
      override func prefersStatusBarHidden() -> Bool {
        return true
      }
     
      private func shapeViewBuilderForFactory(shapeViewFactory: ShapeViewFactory) -> ShapeViewBuilder {
        let shapeViewBuilder = ShapeViewBuilder(shapeViewFactory: shapeViewFactory)
        shapeViewBuilder.fillColor = UIColor.brownColor()
        shapeViewBuilder.outlineColor = UIColor.orangeColor()
        return shapeViewBuilder
      }
     
      private func beginNextTurn() {
        let shapeViews = turnController.beginNewTurn()
     
        shapeViews.0.tapHandler = {
          tappedView in
          self.gameView.score += self.turnController.endTurnWithTappedShape(tappedView.shape)
          self.beginNextTurn()
        }
        shapeViews.1.tapHandler = shapeViews.0.tapHandler
     
        gameView.addShapeViews(shapeViews)
      }
     
      private var gameView: GameView { return view as GameView }
      private var turnController: TurnController!
    }

    Your revised GameViewController uses TurnStrategy as follows:

    1. Create a strategy to create squares.
    2. Create a strategy to create circles.
    3. Create a strategy to randomly select either your square or circle strategy.
    4. Create your turn controller to use the random strategy.

    Build and run, then go ahead and play five or six turns. You should see something similar to the following screenshots.

    Screenshot111213_Animatedv2

    Notice how your game randomly alternates between square shapes and circle shapes. At this point, you could easily add a third shape like triangle or parallelogram and your GameViewController could use it simply by switching up the strategy.

    Design Patterns: Chain of Responsibility, Command and Iterator

    Think about the example at the beginning of this tutorial:

    var collection = ...
     
    // The for loop condition uses the Iterator design pattern
    for item in collection {
      println("Item is: \(item)")
    }

    What is it that makes the for item in collection loop work? The answer is Swift’s SequenceType.

    By using the Iterator pattern in a for ... in loop, you can iterate over any type that conforms to the SequenceType protocol.

    The built-in collection types Array and Dictionary already conform to SequenceType, so you generally don’t need to think about SequenceType unless you code your own collections. Still, it’s nice to know. :]

    Another design pattern that you’ll often see used in conjunction with Iterator is the Command design pattern, which captures the notion of invoking a specific behavior on a target when asked.

    For this tutorial, you’ll use Command to determine if a Turn was a match, and compute your game’s score from that.

    Create a new file named Scorer.swift, and replace its contents with the following code:

    import Foundation
     
    // 1
    protocol Scorer {
      func computeScoreIncrement<S: SequenceType where Turn == S.Generator.Element>(pastTurnsReversed: S) -> Int
    }
     
    // 2
    class MatchScorer: Scorer {
      func computeScoreIncrement<S : SequenceType where Turn == S.Generator.Element>(pastTurnsReversed: S) -> Int {
        var scoreIncrement: Int?
        // 3
        for turn in pastTurnsReversed {
          if scoreIncrement == nil {
          	// 4
            scoreIncrement = turn.matched! ? 1 : -1
            break
          }
        }
     
        return scoreIncrement ?? 0
      }
    }

    Taking each section in turn:

    1. Define your Command type, and declare its behavior to accept a collection of past turns that you can iterate over using the Iterator design pattern.
    2. Declare a concrete implementation of Scorer that will score turns based on whether they matched or not.
    3. Use the Iterator design pattern to iterate over past turns.
    4. Compute the score as +1 for a matched turn and -1 for a non-matched turn.

    Now open TurnController.swift and add the following line near the end, just before the closing brace:

    private let scorer: Scorer

    Then add the following line to the end of the initializer init(turnStrategy:):

    self.scorer = MatchScorer()

    Finally, replace the line in endTurnWithTappedShape that declares and sets scoreIncrement with the following:

    var scoreIncrement = scorer.computeScoreIncrement(pastTurns.reverse())

    Take note of how how you reverse pastTurns before passing it to the scorer because the scorer expects turns in reverse order (newest first), whereas pastTurns stores oldest-first (In other words, it appends newer turns to the end of the array).

    Build and run your code. Did you notice something strange? I bet your scoring didn’t change for some reason.

    You need to make your scoring change by using the Chain of Responsibility design pattern.

    The Chain of Responsibility design pattern captures the notion of dispatching multiple commands across a set of data. For this exercise, you’ll dispatch different Scorer commands to compute your player’s score in multiple additive ways.

    For example, not only will you award +1 or -1 for matches or mismatches, but you’ll also award bonus points for streaks of consecutive matches. Chain of Responsibility allows you add a second Scorer implementation in a manner that doesn’t interrupt your existing scorer.

    Open Scorer.swift and add the following line to the top of MatchScorer

    var nextScorer: Scorer? = nil

    Then add the following line to the end of the Scorer protocol:

    var nextScorer: Scorer? { get set }

    Now both MatchScorer and any other Scorer implementations declare that they implement the Chain of Responsibility pattern through their nextScorer property.

    Replace the return statement in computeScoreIncrement with the following:

    return (scoreIncrement ?? 0) + (nextScorer?.computeScoreIncrement(pastTurnsReversed) ?? 0)

    Now you can add another Scorer to the chain after MatchScorer, and its score gets automatically added to the score computed by MatchScorer.

    Note: The ?? operator is Swift’s nil coalescing operator. It unwraps an optional to its value if non-nil, else returns the other value if the optional is nil. Effectively, a ?? b is the same as a != nil ? a! : b. It’s a nice shorthand and I encourage you to use it in your code.

    To demonstrate this, open Scorer.swift and add the following code to the end of the file:

    class StreakScorer: Scorer {
      var nextScorer: Scorer? = nil
     
      func computeScoreIncrement<S : SequenceType where Turn == S.Generator.Element>(pastTurnsReversed: S) -> Int {
        // 1
        var streakLength = 0
        for turn in pastTurnsReversed {
          if turn.matched! {
            // 2
            ++streakLength
          } else {
            // 3
            break
          }
        }
     
        // 4
        let streakBonus = streakLength >= 5 ? 10 : 0
        return streakBonus + (nextScorer?.computeScoreIncrement(pastTurnsReversed) ?? 0)
      }
    }

    Your nifty new StreakScorer works as follows:

    1. Track streak length as the number of consecutive turns with successful matches.
    2. If a turn is a match, the streak continues.
    3. If a turn is not a match, the streak is broken.
    4. Compute the streak bonus: 10 points for a streak of five or more consecutive matches!

    To complete the Chain of Responsibility open TurnController.swift and add the following line to the end of the initializer init(turnStrategy:):

    self.scorer.nextScorer = StreakScorer()

    Excellent, you’re using Chain of Responsibility.

    Build and run. After five successful matches in the first five turns you should see something like the following screenshot.

    ScreenshotStreakAnimated

    Notice how the score hits 15 after only 5 turns since 15 = 5 points for successful 5 matches + 10 points streak bonus.

    Where To Go From Here?

    Here is the final completed project for this tutorial.

    You’ve taken a fun game, Tap the Larger Shape and used design patterns to add even more shapes and enhance their styling. You’ve also used design patterns to add more elaborate scoring.

    Most remarkably, even though the final project has many more features, its code is actually simpler and more maintainable than what you started with.

    Why not use these design patterns to extend your game even further? Some ideas follow.

    Add more shapes like triangle, parallelogram, star, etc
    Hint: Think back to how you added circles, and follow a similar sequence of steps to add new shapes. If you come up with some really cool shapes, please post screenshots of them in the comments at the bottom of this tutorial!

    Add an animation whenever the score changes
    Hint: Use the didSet property observer on GameView.score.

    Add controls so that players can choose which types of shapes the game uses
    Hint: Add three UIButton or a UISegmentedControl with three choices (Square, Circle, Mixed) in GameView, which should forward any target actions from the controls on to an Observer (Swift closure). GameViewController can use these closures to adjust which TurnStrategy it uses.

    Persist shape settings to preferences that you can restore
    Hint: Store the player’s choice of shape type in NSUserDefaults. Try to use the Facade design pattern (Facade details) to hide your choice of persistence mechanism for this preference from the rest of your code.

    Allow players to select the color scheme for the game
    Hint: Use NSUserDefaults to persist the player’s choice. Create a ShapeViewBuilder that can accept the persisted choice and adjust the app’s UI accordingly. Could you use NSNotificationCenter to inform all interested views that the color scheme changed so that they can immediately update themselves?

    Have your game play a happy sound when a match occurs and a sad sound when a match fails
    Hint: Extend the Observer pattern used between GameView and GameViewController.

    Use Dependency Injection to pass in the Scorer to TurnController
    Hint: Remove the hard-coded dependency on MatchScorer and StreakScorer from the initializer.

    Thank you for working through this tutorial! Please join the discussion below and share your questions, ideas and cool ways you kicked the game up a few notches.

    Intermediate Design Patterns in Swift is a post from: Ray Wenderlich

    The post Intermediate Design Patterns in Swift appeared first on Ray Wenderlich.

    Viewing all 4373 articles
    Browse latest View live


    <script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>