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

The Successful App Launch with Jeremy Olson – Podcast S02 E01

$
0
0
Learn how to have a successful app launch with Jeremy Olson!

Learn how to have a successful app launch with Jeremy Olson!

Welcome to season 2 of the raywenderlich.com podcast! There are a lot of exciting changes in this season, check out this post to learn more.

In this episode, we talk with Jeremy Olson, Apple Design Award winner and co-author of iOS 7 by Tutorials, about how to have a successful app launch.

[Subscribe in iTunes] [RSS Feed]

Links and References

Contact Us

Where To Go From Here?

We hope you enjoyed this podcast, and the changes we made for season 2.

Remember – we are now moving to a weekly format, so 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!

The Successful App Launch with Jeremy Olson – Podcast S02 E01 is a post from: Ray Wenderlich

The post The Successful App Launch with Jeremy Olson – Podcast S02 E01 appeared first on Ray Wenderlich.


Reminder: Free Live Tech Talk (Xcode 6 Tips and Tricks) Tomorrow (Tuesday)!

$
0
0
Free live tech talk (Facebook Pop Animation Library) tomorrow!

Free live tech talk (iOS 8 App Extensions) tomorrow!

This is a reminder that we are having a free live tech talk on Xcode 6 Tips and Tricks tomorrow (Tuesday Oct 14), and you’re all invited! Here are the details:

  • When: Tuesday, Oct 14 at 2:00 PM EST – 3:00 PM EST
  • What: Xcode 6 Tips and Tricks Tech Talk/Demo followed by live Q&A (come w/ questions!)
  • Who: Chris Lowe (iOS 8 by Tutorials author)
  • 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 (Xcode 6 Tips and Tricks) Tomorrow (Tuesday)! is a post from: Ray Wenderlich

The post Reminder: Free Live Tech Talk (Xcode 6 Tips and Tricks) Tomorrow (Tuesday)! appeared first on Ray Wenderlich.

Video Tutorial: iOS Animation with Swift Part 9: Shape and Mask Animations

How to Create Your Own Slide-Out Navigation Panel in Swift

$
0
0
Facebook Slide

Slide to the right!

Note from Ray: This is a Swift update to a popular Objective-C tutorial on our site, released as part of the iOS 8 Feast. Update by James Frost, Original post by Tutorial Team member Tammy Coron. Enjoy!

This tutorial will show you how to build a slide-out navigation panel similar to the ones available in the Facebook and Path iOS apps.

The slide-out navigation panel design pattern lets developers add permanent navigation to their apps without taking up valuable screen real estate. The user can choose to reveal the navigation at any time, while still seeing their current context.

These days, there are many pre-built solutions out there you can use, such as John-Lluch’s excellent SWRevealViewController or Mutual Mobile’s MMDrawerController. If you’re looking for the quickest and easiest way, using library might be a good way to go.

However, in this tutorial you’ll see that it’s really not as complicated as you might think. You’ll take a less-is-more approach and skip all of the complicated code that’s not really required, so that you can apply the slide-out navigation technique to your own applications with relative ease.

Getting Started

You’re going to build slide-out navigation into a cute kitten and puppy photo browser. To get started, download the starter project for this tutorial. It’s a zip file, so save it to a convenient location and then extract it to get the project.

Next open the project in Xcode and take a look at how it’s organized. The Resources folder contains all of the kitten and puppy images that’ll be displayed by the app. Notice too that are three main view controllers. When it comes time to adapt this tutorial to your own projects, here’s what you should keep in mind:

  • ContainerViewController: This is where the magic happens! This contains the views of the left, center, and right view controllers and handles things like animations and swiping. In this project, it’s created and added to the window in applicationDidFinishLaunching: in AppDelegate.swift
  • CenterViewController: The center panel. This can be replaced with your own view controller (make sure you copy the button actions).
  • SidePanelViewController: Used for the left and right side panels. This could be replaced with your own view controller.

The views for the center, left, and right view controllers are all defined within Main.storyboard, so feel free to take a quick look at that to get an idea of how the app will look.

Now that you’re familiar with the structure of the project, it’s time to start at square one: the center panel.

Finding Your Center

In this section, you are going to place the CenterViewController inside the ContainerViewController, as a child view controller.

Note: This section uses a concept called View Controller Containment introduced in iOS 5. If you are new to this concept, check out Chapter 22 in iOS 5 by Tutorials, “UIViewController Containment.”

Open ContainerViewController.swift. Notice at the bottom of the file that there is a small extension for UIStoryboard. This adds a few class methods which make it a bit more concise to load specific view controllers from the app’s storyboard. You’ll make use of these methods soon.

Add a couple of properties for the CenterViewController and for a UINavigationController, above ContainerViewController‘s init method:

var centerNavigationController: UINavigationController!
var centerViewController: CenterViewController!

Note: These are implicitly-unwrapped optionals (as denoted by the !). They have to be optional because their values won’t be initialized until after init has been called, but they can be automatically unwrapped because once they’re created you know they will always have values.

Find viewDidLoad and add the following block of code to it, beneath the call to super:

centerViewController = UIStoryboard.centerViewController()
centerViewController.delegate = self
 
// wrap the centerViewController in a navigation controller, so we can push views to it
// and display bar button items in the navigation bar
centerNavigationController = UINavigationController(rootViewController: centerViewController)
view.addSubview(centerNavigationController.view)
addChildViewController(centerNavigationController)
 
centerNavigationController.didMoveToParentViewController(self)

The code above creates a new CenterViewController and assigns it to the centerViewController property that you just created. It also creates a UINavigationController to contain the CenterViewController. It then adds the navigation controller’s view to ContainerViewController‘s view and sets up the parent-child relationship using addSubview, addChildViewContoller and didMoveToParentViewController.

This code also sets the current view controller as the center view controllers’s delegate. This will be used by the center view controller to tell its container when to show and hide the left and right side panels.

You need to modify the interface of this class so that it will adhere to the protocol requirements of CenterViewControllerDelegate. Do this by updating the class declaration for ContainerViewController, near the top of the file:

class ContainerViewController: UIViewController, CenterViewControllerDelegate {

Now is a good time to check your progress. Build and run the project. If all went well, you should see something similar to the screen below:

Slide Out Navigation in Swift main screen

Yes, those buttons at the top will eventually bring you kitties and puppies. What better reason could there be for creating sliding navigation panels? But to get your cuteness fix, you’ve got to start sliding. First, to the left!

Kittens to the Left of Me…

You’ve created your center panel, but adding the left view controller requires a different set of steps. There’s quite a bit of set up to get through here, so bear with it. Think of the kittens!

To expand the left menu, the user will tap on the Kitties button in the navigation bar. So head on over to CenterViewController.swift.

In the interests of keeping this tutorial focused on the important stuff, the IBActions and IBOutlets have been pre-connected for you in the storyboard. However, to implement your DIY slide-out navigation, you need to understand how the buttons are configured.

Notice that there are already two IBAction methods, one for each of the buttons. Find kittiesTapped and add the following implementation to it:

if let d = delegate {
  d.toggleLeftPanel?()
}

As previously mentioned, the method is already hooked up to the Kitties button.

This uses optional binding to check that delegate has a value, and then calls the toggleLeftPanel method if the delegate has implemented it.

You can see the definition of the delegate protocol at the top of CenterViewController.swift. As you’ll see, there are optional methods toggleLeftPanel and toggleRightPanel. If you remember, when you set up the center view controller instance earlier, you set its delegate as the container view controller. Time to go and implement toggleLeftPanel.

Note: For more information on delegate methods and how to implement them, please refer to Apple’s Developer Documentation.

Return to ContainerViewController.swift. First add an enum to the top of the file, below the import statements:

enum SlideOutState {
  case BothCollapsed
  case LeftPanelExpanded
  case RightPanelExpanded
}

This will let you keep track of the current state of the side panels, so you can tell whether neither panel is visible, or one of the left or right panels are visible.

Now, below your existing centerViewController property, add two more properties:

var currentState: SlideOutState = .BothCollapsed
var leftViewController: SidePanelViewController?

These will hold the current state, and the left side panel view controller itself:

The current state is initialized to be .BothCollapsed – that is, neither of the side panels are visible when the app first loads. The leftViewController property is an optional, because you’ll be adding and removing the view controller at various times, so it might not always have a value.

Now add an implementation for the toggleLeftPanel delegate method:

let notAlreadyExpanded = (currentState != .LeftPanelExpanded)
 
if notAlreadyExpanded {
  addLeftPanelViewController()
}
 
animateLeftPanel(shouldExpand: notAlreadyExpanded)

First, this method checks whether the left side panel is already expanded or not. If it’s not already visible, then the panel is added and animated to its ‘open’ position. If the panel is already visible, then it will be animated to its ‘closed’ position.

What does it mean to ‘add’ the left panel? Locate addLeftPanelViewController, and add the following code inside it:

if (leftViewController == nil) {
  leftViewController = UIStoryboard.leftViewController()
  leftViewController!.animals = Animal.allCats()
 
  addChildSidePanelController(leftViewController!)
}

The code above first checks to see if the leftViewController property is nil. If it is, then the code creates a new SidePanelViewController, and assigns it a list of animals to display – in this case, cats!

Next, add the implementation for addChildSidePanelController below addLeftPanelViewController:

func addChildSidePanelController(sidePanelController: SidePanelViewController) {
  view.insertSubview(sidePanelController.view, atIndex: 0)
 
  addChildViewController(sidePanelController)
  sidePanelController.didMoveToParentViewController(self)
}

This method inserts the child view into the container view controller. This is much the same as adding the center view controller earlier. It simply inserts its view (in this case it’s inserted at z-index 0, which means that it will be below the center view controller) and adds it as a child view controller.

It’s almost time to try the project out again, but there’s one more thing to do: add some animation! It won’t take long!

showmenow

And sliiiiiiide!

First, add a constant below your other properties in ContainerViewController.swift:

let centerPanelExpandedOffset: CGFloat = 60

This value is the width, in points, of the center view controller that will be left visible once it has animated offscreen. 60 points should do it.

Locate the method stub for animateLeftPanel and add the following block of code to it:

if (shouldExpand) {
  currentState = .LeftPanelExpanded
 
  animateCenterPanelXPosition(targetPosition: CGRectGetWidth(centerNavigationController.view.frame) - centerPanelExpandedOffset)
} else {
  animateCenterPanelXPosition(targetPosition: 0) { finished in
    self.currentState = .BothCollapsed
 
    self.leftViewController!.view.removeFromSuperview()
    self.leftViewController = nil;
  }
}

This method simply checks whether it’s been told to expand or collapse the side panel. If it should expand, then it sets the current state to indicate that the left panel is expanded, and then animates the center panel so it’s open. Otherwise, it animates the center panel closed and then removes its view and sets the current state to indicate that it’s closed.

Finally, add animateCenterPanelXPosition underneath that:

func animateCenterPanelXPosition(#targetPosition: CGFloat, completion: ((Bool) -> Void)! = nil) {
  UIView.animateWithDuration(0.5, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0, options: .CurveEaseInOut, animations: {
    self.centerNavigationController.view.frame.origin.x = targetPosition
  }, completion: completion)
}

This is where the actual animation happens. The center view controller’s view is animated to the specified position, with a nice spring animation. The method also takes an optional completion closure, which it passes on to the UIView animation. You can try tweaking the duration and spring damping parameters if you want to change the appearance of the animation.

OK… It’s taken a little while to get everything in place, but now is a great time to build and run the project. So do it!

When you’ve run the project, try tapping on the Kitties button in the navigation bar. The center view controller should slide over – whoosh! – and reveal the Kitties menu underneath. D’aww, look how cute they all are.

Slide Out Navigation in Swift - Kitties

But too much cuteness can be a dangerous thing! Tap the Kitties button again to hide them!

Me and my shadow

When the left panel is open, notice how it’s right up against the center view controller. It would be nice if there were a bit more of a distinction between them. How about adding a shadow?

Add the following method below your animation methods:

func showShadowForCenterViewController(shouldShowShadow: Bool) {
  if (shouldShowShadow) {
    centerNavigationController.view.layer.shadowOpacity = 0.8
  } else {
    centerNavigationController.view.layer.shadowOpacity = 0.0
  }
}

This adjusts the opacity of the navigation controller’s shadow to make it visible or hidden. You can implement a didSet observer to add or remove the shadow whenever the currentState property changes.

Scroll to the top of ContainerViewController.swift and change the currentState declaration to:

var currentState: SlideOutState = .BothCollapsed {
  didSet {
    let shouldShowShadow = currentState != .BothCollapsed
    showShadowForCenterViewController(shouldShowShadow)
  }
}

The didSet closure will be called whenever the property’s value changes. If either of the panels are expanded, then the shadow will be displayed.

Build and run the project again. This time when you tap the kitties button, check out the sweet new shadow! Looks better, huh?

Slide Out Navigation in Swift - Kitties with shadows

Up next, adding the same functionality but for the right side, which means… puppies!

Puppies to the Right…

To add the right panel view controller, simply repeat the steps for adding the left view controller.

In ContainerViewController.swift, add the following property below the leftViewController property:

var rightViewController: SidePanelViewController?

Now locate toggleRightPanel, and add the following:

let notAlreadyExpanded = (currentState != .RightPanelExpanded)
 
if notAlreadyExpanded {
  addRightPanelViewController()
}
 
animateRightPanel(shouldExpand: notAlreadyExpanded)

Then add implementations for the corresponding addRightPanelViewController and animateRightPanelViewController methods below their left view controller counterparts:

func addRightPanelViewController() {
  if (rightViewController == nil) {
    rightViewController = UIStoryboard.rightViewController()
    rightViewController!.animals = Animal.allDogs()
 
    addChildSidePanelController(rightViewController!)
  }
}
 
func animateRightPanel(#shouldExpand: Bool) {
  if (shouldExpand) {
    currentState = .RightPanelExpanded
 
    animateCenterPanelXPosition(targetPosition: -CGRectGetWidth(centerNavigationController.view.frame) + centerPanelExpandedOffset)
  } else {
    animateCenterPanelXPosition(targetPosition: 0) { _ in
      self.currentState = .BothCollapsed
 
      self.rightViewController!.view.removeFromSuperview()
      self.rightViewController = nil;
    }
  }
}

The code above is almost an exact duplicate of the code for the left panel, except of course for the differences in method and property names and the direction. If you have any questions about it, review the explanation from the previous section.

Just as before, the IBActions and IBOutlets have been connected in the storyboard for you. Similar to the Kitties button, the Puppies button is hooked up to an IBAction method named puppiesTapped. This button controls the sliding of the center panel to reveal the right-side panel.

Finally, switch to CenterViewController.swift and add the following snippet to puppiesTapped:

if let d = delegate {
  d.toggleRightPanel?()
}

Again, this is the same as kittiesTapped, except it’s toggling the right panel instead of the left.

Time to see some puppies!

Build and run the program again to make sure everything is working. Tap on the Puppies button. Your screen should look like this:

Slide Out Navigation in Swift - Puppies

Looking good, right? But remember, you don’t want to expose yourself to the cuteness of puppies for too long, so tap that button again to hide them away.

You can now view both kitties and puppies, but it would be great to be able to view a bigger picture of each one, wouldn’t it? MORE CUTENESS :]

Pick An Animal, Any Animal

The kitties and puppies are listed within the left and right panels. These are both instances of SidePanelViewController, which essentially just contain table views.

Head over to SidePanelViewController.swift to handle taps on the rows. Take a look at the SidePanelViewControllerDelegate definition at the top of the file. A side panel’s delegate can be notified via this method whenever an animal is tapped. Let’s use it!

Still in SidePanelViewController.swift, first add an optional delegate property at the top of the class, underneath the table view IBOutlet:

var delegate: SidePanelViewControllerDelegate?

Then fill in the implementation for tableView(_:didSelectRowAtIndexPath:):

func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
  let selectedAnimal = animals[indexPath.row]
  delegate?.animalSelected(selectedAnimal)
}

If there is a delegate set, this will tell it that an animal has been selected. But there is no delegate yet! It would make sense for CenterViewController to be the side panel’s delegate, as it can then display the selected animal photo and title.

Open up CenterViewController.swift to implement the delegate protocol. Change the class declaration to the following:

class CenterViewController: UIViewController, SidePanelViewControllerDelegate {

And then add the implementation for animalSelected:

func animalSelected(animal: Animal) {
  imageView.image = animal.image
  titleLabel.text = animal.title
  creatorLabel.text = animal.creator
 
  if let d = delegate {
    d.collapseSidePanels!()
  }
}

This method simply populates the image view and labels in the center view controller with the animal’s image, title, and creator. Then, if the center view controller has a delegate of its own, you can tell it to collapse the side panel away so you can focus on the selected item.

collapseSidePanels hasn’t been implemented yet, so switch over to ContainerViewController.swift to finish things up.

Add the method below toggleRightPanel:

func collapseSidePanels() {
  switch (currentState) {
    case .RightPanelExpanded:
      toggleRightPanel()
    case .LeftPanelExpanded:
      toggleLeftPanel()
    default:
    	break
  }
}

The switch statement in this method simply checks the current state of the side panels, and collapses whichever one is open (if any!).

Finally, update addChildSidePanelViewController to the following implementation:

func addChildSidePanelController(sidePanelController: SidePanelViewController) {
  sidePanelController.delegate = centerViewController
 
  view.insertSubview(sidePanelController.view, atIndex: 0)
 
  addChildViewController(sidePanelController)
  sidePanelController.didMoveToParentViewController(self)
}

In addition to what it was doing before, the method will now set the center view controller as the side panels’ delegate.

That should do it! Build and run the project again. View kitties or puppies, and tap on one of the cute little critters. The side panel should collapse itself again and you should see the details of the animal you chose.

Slide Out Navigation in Swift - Puppy Details

Move Your Hands Back and Forth

The navigation bar buttons are great, but most apps also allow you to “swipe” to open the side panels. Adding gestures to your app is surprisingly simple. Don’t be intimated; you’ll do fine!

grooveinthehandsc

Open ContainerViewController.swift and locate viewDidLoad. Add the following to the end:

let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: "handlePanGesture:")
centerNavigationController.view.addGestureRecognizer(panGestureRecognizer)

The above code defines a UIPanGestureRecognizer and assigns handlePanGesture() to it to handle any detected pan gestures. (You will write the code for that method soon.)

By default, a pan gesture recognizer detects a single touch with a single finger, so it doesn’t need any extra configuration. All that’s required is to add the newly created gesture recognizer to centerNavigationController.view.

Note: Refer to our Using UIGestureRecognizer with Swift Tutorial for more information about gesture recognizers in iOS.

Next make this class a UIGestureRecognizerDelegate by changing the class declaration at the top:

class ContainerViewController: UIViewController, CenterViewControllerDelegate, UIGestureRecognizerDelegate {

Didn’t I tell you that’d be simple? There’s only one move remaining in your slide-out routine.

Now Move That View!

The gesture recognizer calls handlePanGesture:code> when it detects a gesture. So your last task for this tutorial is to implement that method.

Locate the stub for handlePanGesture: and add the following block of code to it (it’s a big one!):

let gestureIsDraggingFromLeftToRight = (recognizer.velocityInView(view).x > 0)
 
switch(recognizer.state) {
  case .Began:
    if (currentState == .BothCollapsed) {
      if (gestureIsDraggingFromLeftToRight) {
        addLeftPanelViewController()
      } else {
        addRightPanelViewController()
      }
 
      showShadowForCenterViewController(true)
    }
  case .Changed:
    recognizer.view!.center.x = recognizer.view!.center.x + recognizer.translationInView(view).x
    recognizer.setTranslation(CGPointZero, inView: view)
  case .Ended:
    if (leftViewController != nil) {
      // animate the side panel open or closed based on whether the view has moved more or less than halfway
      let hasMovedGreaterThanHalfway = recognizer.view!.center.x > view.bounds.size.width
      animateLeftPanel(shouldExpand: hasMovedGreaterThanHalfway)
    } else if (rightViewController != nil) {
      let hasMovedGreaterThanHalfway = recognizer.view!.center.x < 0
      animateRightPanel(shouldExpand: hasMovedGreaterThanHalfway)
    }
  default:
  	break
}

The pan gesture recognizer detects pans in any direction, but you’re only interested in horizontal movement. First, you set up the gestureIsDraggingFromLeftToRight Boolean to check for this.

There are three states that need to be tracked: UIGestureRecognizerState.Began, UIGestureRecognizerState.Changed, and UIGestureRecognizerState.Ended:

  • Began: If the user starts panning, and neither panel is visible then show the correct panel based on the pan direction.
  • Changed: If the user is already panning, translate the center view controller’s view by the amount that the user has panned
  • Ended: When the pan ends, check whether the left or right view controller is visible. Depending on which one is visible and how far the pan has gone, perform the animation.

You can move the center view around, and show and hide the left and right views using a combination of these three states, as well as the location and velocity / direction of the pan gesture.

For example, if the gesture direction is right, then show the left panel. If the direction is left, then show the right panel.

Build and run the program again. At this point, you should be able to slide the center panel left and right, revealing the panels underneath. If everything is working… you’re good to go!

Where to Go from Here?

Congratulations! If you made it all the way through, you’re a slide-out navigation panel ninja!

feel-like-a-ninja

I hope you enjoyed this tutorial. Feel free to download the completed project file. I’m sure you’ll enjoy being stuck in the middle of kitties and puppies!

As I mentioned earlier, if you prefer a pre-built library over the DIY solution, be sure to check out MMDrawerController or SWRevealViewController. For an in-depth look (and pretty pictures), check out iOS developer and designer Ken Yarmosh’s post New iOS Design Pattern: Slide-Out Navigation. He does a great job of explaining the benefits of using this design pattern and showing common uses in the wild.

Leave a comment in the forums below to share your slide-out moves and grooves!

How to Create Your Own Slide-Out Navigation Panel in Swift is a post from: Ray Wenderlich

The post How to Create Your Own Slide-Out Navigation Panel in Swift appeared first on Ray Wenderlich.

Video Tutorial: iOS Animation with Swift Part 10: Gradient Animations

Core Data by Tutorials Now Available!

$
0
0

Core Data by Tutorials now available!

Note from Ray: Happy Wednesday – it’s book release day during the iOS 8 Feast!

Good news – the third and final book in the Swift by Tutorials Bundle is now available: Core Data by Tutorials!

Core Data by Tutorials will teach you the fundamentals of using Core Data with Swift, by means of hands-on tutorials. It starts with the basics, and quickly moves to more advanced topics like versioning and migration, syncing with iCloud, performance, multithreading, and more.

Written by some of the foremost experts on Core Data, you’re in for a treat with this book. Get ready to level-up your Core Data skills – the easy way!

In addition, Matthijs Hollemans has updated the fourth and final part of the iOS Apprentice to iOS 8 and Swift. Keep reading to find out more about each update!

About Core Data by Tutorials

Core Data by Tutorials is for intermediate to advanced developers, who already know the basics of iOS and Swift development but want to learn Core Data.

4 members of the Tutorial Team on this site have teamed up to write this book: Aaron Douglas, Saul Mora, Matthew Morey, and Pietro Rea. All four of these guys have battle-hardened Core Data experience to share with you.

Core Data by Tutorials is 10 chapters and 256 pages. Let’s take a quick look at what’s inside:

  • Chapter 1, Your First Core Data App: You’ll click File\New Project and write a Core Data app from scratch! This chapter covers the basics of setting up your data model and then adding and fetching records.
  • Chapter 2, NSManagedObject Subclasses: NSManagedObject is the base data storage class of your Core Data object graphs. This chapter will teach you how you customize your own managed object subclasses to store and validate data.
  • Chapter 3, The Core Data Stack: Under the hood, Core Data is made up of many parts working together. In this chapter, you’ll learn about how these parts fit together, and move away from the starter Xcode template to build your own customizable system.
  • Chapter 4, Intermediate Fetching: Your apps will fetch data all the time, and Core Data offers many options for getting the data to you efficiently. This chapter covers more advanced fetch requests, predicates, sorting and asynchronous fetching.
  • Chapter 5, NSFetchedResultsController: Table views are at the core of many iOS apps, and Apple wants to make Core Data play nicely with them! In this chapter, you’ll learn how NSFetchedResultsController can save you time and code when your table views are backed by data from Core Data.
  • Chapter 6, Versioning and Migration: As you update and enhance your app, its data model will almost certainly need to change. In this chapter, you’ll learn how to create multiple versions of your data model and then migrate your users forward so they can keep their existing data as they upgrade.
  • Chapter 7, Syncing with iCloud: Move beyond storing data locally on a single device, to cloud storage and synchronizing across all the user’s devices. This chapter covers how to extend an existing Core Data app to use iCloud.
  • Chapter 8, Unit Tests: Testing is an important part of the development process, and you shouldn’t leave Core Data out of those tests! In this chapter, you’ll learn how to set up a separate test environment for Core Data and see examples of how to test your models.
  • Chapter 9, Measuring and Boosting Performance: No one ever complained that an app was too fast, so it’s important to be vigilant about tracking performance. In this chapter, you’ll learn how to measure your app’s performance with various Xcode tools and then pick up some tips for dealing with slow spots in your code.
  • Chapter 10, Multiple Managed Object Contexts: In this final chapter, you’ll expand the usual Core Data stack to include multiple managed object contexts. You’ll learn how this can improve perceived performance and help make your app architecture less monolithic and more compartmentalized.

The iOS Apprentice Third Edition Part 4: StoreSearch

iOS Apprentice Third Edition Part 4 Now Available!

iOS Apprentice Third Edition Part 4 Now Available!

As you may know, Matthijs Hollemans has been updating his popular iOS Apprentice series to iOS 8 and Swift as well.

Today, we are happy to announce that the fourth and final part is now fully updated!

Again, this is a free update to existing PDF customers. If you bought the iOS Apprentice when it first came out, you have seen it update from iOS 5 -> 6 -> 7 -> 8, and even an entirely new language!

Pretty good value for the money, eh? :]

How To Get Your Copy

If you are an existing PDF customer for Core Data by Tutorials or the iOS Apprentices, you can download it now on your My Loot page.

Otherwise, you can pick up a copy here:

We hope you enjoy these books – along with the rest of the books released during the iOS 8 Feast. These are the last books to be released during the feast – stay tuned for the grand prize giveaway next week to end with a bang! :]

And by the way, don’t forget to sign up for RWDevCon, and grab your early bird discount while you still can. See you there!

Core Data by Tutorials Now Available! is a post from: Ray Wenderlich

The post Core Data by Tutorials Now Available! appeared first on Ray Wenderlich.

Your First Core Data App Using Swift

$
0
0
Learn how to make your first Core Data app with Swift!

Learn how to make your first Core Data app with Swift!

Note from Ray: This is an abbreviated version of a chapter from Core Data by Tutorials released as part of the iOS 8 Feast to give you a sneak peek of what’s inside the book. We hope you enjoy!

In this tutorial, you’ll write your very first Core Data app using Swift. You’ll see how easy it is to get started with all the resources provided in Xcode, from the starter code templates to the data model editor. By the end of the tutorial you’ll know how to:

  • model data you want to store in Core Data using Xcode’s model editor;
  • add new records to Core Data;
  • fetch a set of records from Core Data;
  • display the fetched results to the user in a table view.

You’ll also get a sense of what Core Data is doing behind the scenes, and how you can interact with the various moving pieces there. We’re getting ahead of ourselves though – it’s time to build an app!

Getting Started

Open Xcode and create a new iPhone project based on the Single View Application template. Call the app HitList and make sure Use Core Data is checked:

image1

Checking the Use Core Data box will cause Xcode to generate boilerplate code for what’s known as a Core Data stack in AppDelegate.swift.

The Core Data stack consists of a set of objects that facilitate saving and retrieving information from Core Data. There’s an object to manage the Core Data state as a whole, an object representing the data model, and so on.

Note: Not all Xcode templates have the option to start with Core Data. In Xcode 6, only the Master-Detail Application and the Single View Application templates have the Use Core Data checkbox.

The idea for this sample app is simple. There will be a table view with a list of names for your very own “hit list”. You’ll be able to add names to this list and eventually, you’ll use Core Data to make sure the data is stored between sessions. We don’t condone violence in this tutorial so you can think of this app as a “favorites list” to keep track of your friends too, of course! ;]

Click on Main.storyboard to open it in Interface Builder. Select its only view controller and change its size class to Regular Height and Compact Width to match an iPhone in portrait mode:

image2

Next, embed the view controller in a navigation controller. From Xcode’s Editor menu, select Embed In…\ Navigation Controller.

image3

Back in Interface Builder, drag a Table View from the object library into the view controller so that it covers the entire view.

Then, drag a Bar Button Item and place it on the view controller’s newly added navigation bar. Finally, double-click the bar button item to change its text to Add. Your canvas should now look like the following screenshot:

image4

Every time you tap Add on the top-right, an alert containing a text field will appear on the screen. From there you’ll be able to type someone’s name into the text field. Dismissing the alert will save the name and refresh the table view with all the names you’ve saved up to that point.

Before you can do that, you need to make the view controller the table view’s data source. Ctrl-drag from the table view to the yellow view controller icon above the navigation bar, as shown below, and click on dataSource:

image5

In case you were wondering, you don’t need to set up the table view’s delegate since tapping on the cells won’t trigger any action. It doesn’t get simpler than this!

Open the Assistant Editor by hitting Command-Option-Enter or by selecting the middle button on the Editor toolset on the Xcode bar. Ctrl-drag from the table view onto ViewController.swift, inside the class definition to insert an outlet:

image6

Name the new IBOutlet property tableView, resulting in the following line:

@IBOutlet weak var tableView: UITableView!

Ctrl-drag from the Add bar button item onto ViewController.swift, but this time, create an action instead of an outlet and name the method addName:

@IBAction func addName(sender: AnyObject) {
 
}

You can now refer to the table view and the bar button item’s action in code. Next, set up the model for the table view. Add the following property to ViewController.swift:

//Insert below the tableView IBOutlet
var names = [String]()

names is a mutable Array to hold the strings for the table view to display.

Replace the implementation of viewDidLoad with the following:

override func viewDidLoad() {
  super.viewDidLoad()
  title = "\"The List\""
  tableView.registerClass(UITableViewCell.self,
    forCellReuseIdentifier: "Cell")
}

This will set a title and register the UITableViewCell class with the table view. You do this so that when you dequeue a cell, the table view will return a cell of the correct type.

Still in ViewController.swift, declare that ViewController will conform to the UITableViewDataSource protocol by editing the class declaration:

//Add UITableViewDataSource to class declaration
class ViewController: UIViewController, UITableViewDataSource {

Immediately, Xcode will complain about ViewController not conforming to the protocol.

Below viewDidLoad, implement the following data source methods to fix the error:

// MARK: UITableViewDataSource
func tableView(tableView: UITableView,
    numberOfRowsInSection section: Int) -> Int {
    return names.count
}
 
func tableView(tableView: UITableView,
  cellForRowAtIndexPath
  indexPath: NSIndexPath) -> UITableViewCell {
 
    let cell =
        tableView.dequeueReusableCellWithIdentifier("Cell")
        as UITableViewCell
 
    cell.textLabel!.text = names[indexPath.row]
 
  return cell
}

If you’ve ever worked with UITableView, this code should look very familiar. The first method says that the table view will have as many rows as the names array has strings.

The second method, tableView(_:cellForRowAtIndexPath:), dequeues table view cells and populates them with the corresponding string in the names array.

Don’t run the app just yet. First, you need a way to input names so the table view can display them.

Implement the addName IBAction method you Ctrl-dragged into your code earlier:

//Implement the addName IBAction
@IBAction func addName(sender: AnyObject) {
 
  var alert = UIAlertController(title: "New name",
      message: "Add a new name",
      preferredStyle: .Alert)
 
  let saveAction = UIAlertAction(title: "Save",
   style: .Default) { (action: UIAlertAction!) -> Void in
 
    let textField = alert.textFields![0] as UITextField
    self.names.append(textField.text)
    self.tableView.reloadData()
  }
 
  let cancelAction = UIAlertAction(title: "Cancel",
    style: .Default) { (action: UIAlertAction!) -> Void in
  }
 
  alert.addTextFieldWithConfigurationHandler {
    (textField: UITextField!) -> Void in
  }
 
  alert.addAction(saveAction)
  alert.addAction(cancelAction)
 
  presentViewController(alert,
      animated: true,
      completion: nil)
}

Every time you tap the Add bar button item, this method presents an UIAlertController with a text field and two buttons, Save and Cancel.

Save takes whatever text is currently in the text field, inserts it into the name array and reloads the table view. Since the names array is the model backing the table view, whatever you typed into the text field will appear in the table view.

Finally it’s time to build and run your app for the first time. Tap the Add bar button item. The alert controller will look like this:

image7

Add four or five names to the list. You should wind up with something like this:

image8

Your table view will display the data and your array will store the names, but the big thing missing here is persistence. The array is in memory but if you force quit the app or reboot your device, your hit list will be wiped out.

Core Data provides persistence, meaning it can store data in a more durable state so that it can outlive an app re-launch or a device reboot.

You haven’t added any Core Data yet, so nothing should persist after you navigate away from the app. Let’s test this out. Press the Home button if you’re using a physical device or the equivalent (Shift+⌘+H) if you’re on the Simulator. This will take you back to the familiar app grid on the home screen:

image9

From the home screen, tap the HitList icon to bring the app back to the foreground. The names are still on the screen. What happened?

When you tap the Home button, the app that’s currently in the foreground goes to the background. When this happens, the operating system flash-freezes everything currently in memory, including the strings in the names array. Similarly, when it’s time to wake up and return to the foreground, the operating system restores what used to be in memory as if you’d never left.

Apple introduced these advances in multitasking back in iOS 4. They create a seamless experience for iOS users but add a wrinkle to the definition of persistence for iOS developers. Are the names really persisted?

No, not really. If you had completely killed the app in the fast app switcher or turned off your phone, those names would be gone. You can verify this, as well. With the app in the foreground, double tap the Home button to enter the fast app switcher, like so:

image10

From here, flick the HitList app snapshot upwards to terminate the app. There should be no trace of HitList in living memory (no pun intended). Verify that the names are gone by returning to the home screen and tapping on the HitList icon to trigger a fresh launch.

This difference between flash-freezing and persistence may be obvious if you’ve been working with iOS for some time and are familiar with the way multitasking works. In a user’s mind, however, there is no difference. The user doesn’t care if the names are “still there” because the app went into the background and came back, or because the app saved and reloaded them.

All that matters is that the names are still there when she comes back!

So the real test of persistence, the one you will use in this tutorial, is whether your data is still there after a fresh app launch.

Modeling Your Data

Now that you know how to check for persistence, let’s get started with Core Data. Your goal for the HitList app is simple: to persist the names you enter so they’re available for viewing after a fresh app launch.

Up to this point, you’ve been using plain old Swift strings to store the names in memory. In this section, you’ll replace these strings with Core Data objects.

The first step is to create a managed object model, which spells out the way Core Data represents data on disk. By default, Core Data uses an SQLite database as the persistent store (more on this later), so you can think of the data model as the database schema.

Note: You’ll come across the word “managed” quite a bit in this tutorial. If you see “managed” in the name of a class, such as in NSManagedObjectContext, chances are you are dealing with a Core Data class. “Managed” refers to Core Data’s management of the life cycle of Core Data objects.

However, don’t assume that all Core Data classes contain the word “managed”—actually, most don’t. For a comprehensive list of Core Data classes, check out the Objective-C umbrella header CoreData/CoreData.h.

Since you elected to use Core Data when you created the HitList project, Xcode automatically created a data model file for you and named it HitList.xcdatamodeld.

image11

Click on HitList.xcdatamodeld to open it. As you can see, Xcode has a powerful data model editor that looks like this:

image12

The data model editor has a lot of features. For now, let’s focus on creating a single Core Data entity.

Click on Add Entity on the lower-left to create a new entity. Double-click on the new entity and change its name to Person, like so:

image13

You may be wondering why the model editor uses the term “Entity.” Weren’t you simply defining a new class? As you’ll see shortly, Core Data comes with its own vocabulary. Here’s a quick rundown of some of the terms you’ll commonly encounter:

  • An entity is a class definition in Core Data. The classic example is an Employee or a Company. In a relational database, an entity corresponds to a table.
  • An attribute is a piece of information attached to a particular entity. For example, an Employee entity could have attributes for the employee’s name, position and salary. In a database, an attribute corresponds to a particular field in a table.
  • A relationship is a link between multiple entities. In Core Data, relationships between two entities are called to-one relationships, while those between one and many entities are called to-many relationships. For example, a Manager can have a to-many relationship with a set of employees, whereas an individual Employee will have a to-one relationship with his manager.

Note: As you’ve probably noticed, entities sound a lot like a classes. Likewise, attributes/relationships sound a lot like properties. What’s the difference? You can think of a Core Data entity as a class “definition” and the managed object as an instance of that class.

Now that you know what an attribute is, go back to the model editor and add an attribute to Person. Select Person on the left-hand side and click the plus sign (+) under Attributes.

Set the new attribute’s name to, well, name and change its type to String:

image14

In Core Data, an attribute can be of one of several data types — one of them is the string type.

Saving to Core Data

Import the Core Data module at the top of ViewController.swift:

//Add below "import UIKit"
import CoreData

You may have had to link frameworks manually in your project’s Build Phases if you’ve worked with Objective-C frameworks. In Swift, a simple import statement is all you need to start using Core Data APIs in your code.

Next, replace the table view’s model with the following:

//Change [String] to [NSManagedObject]
var people = [NSManagedObject]()

You’ll be storing Person entities rather than just names, so you rename the Array that serves as the table view’s data model to people. It now holds instances of NSManagedObject rather than simple Swift strings.

NSManagedObject represents a single object stored in Core Data—you must use it to create, edit, save and delete from your Core Data persistent store. As you’ll see shortly, NSManagedObject is a shape-shifter. It can take the form of any entity in your data model, appropriating whatever attributes and relationships you defined.

Since you’re changing the table view’s model, you must also replace both data source methods you implemented earlier with the following to reflect these changes:

//Replace both UITableViewDataSource methods
func tableView(tableView: UITableView,
    numberOfRowsInSection section: Int) -> Int {
    return people.count
}
 
func tableView(tableView: UITableView,
  cellForRowAtIndexPath
  indexPath: NSIndexPath) -> UITableViewCell {
 
  let cell =
      tableView.dequeueReusableCellWithIdentifier("Cell")
      as UITableViewCell
 
  let person = people[indexPath.row]
  cell.textLabel!.text = person.valueForKey("name") as String?
 
  return cell
}

The most significant change to these methods occurs in cellForRowAtIndexPath. Instead of matching cells with the corresponding string in the model array, you now match cells with the corresponding NSManagedObject.

Note how you grab the name attribute from the NSManagedObject. It happens here:

cell.textLabel.text = person.valueForKey("name") as String

Why do you have to do this? As it turns out, NSManagedObject doesn’t know about the name attribute you defined in your data model, so there’s no way of accessing it directly with a property. The only way Core Data provides to read the value is key-value coding, commonly referred to as KVC.

Note: If you’re new to iOS development, you may not be familiar with key-value coding or KVC.

KVC is a mechanism in Cocoa and Cocoa Touch for accessing an object’s properties indirectly using strings to identify properties. In this case, KVC makes NSMangedObject behave more or less like a dictionary.

Key-value coding is available to all classes that descend from NSObject, including NSManagedObject. You wouldn’t be able to access properties using KVC on a Swift object that doesn’t descend from NSObject.

Next, replace the save action in the addName @IBAction method with the following:

let saveAction = UIAlertAction(title: "Save",
 style: .Default) { (action: UIAlertAction!) -> Void in
 
  let textField = alert.textFields![0] as UITextField
  self.saveName(textField.text)
  self.tableView.reloadData()
}

This takes the text in the text field and passes it over to a new method called saveName. Add saveName to ViewController.swift, as shown below:

func saveName(name: String) {
  //1
  let appDelegate =
  UIApplication.sharedApplication().delegate as AppDelegate
 
  let managedContext = appDelegate.managedObjectContext!
 
  //2
  let entity =  NSEntityDescription.entityForName("Person",
    inManagedObjectContext:
    managedContext)
 
  let person = NSManagedObject(entity: entity!,
    insertIntoManagedObjectContext:managedContext)
 
  //3
  person.setValue(name, forKey: "name")
 
  //4
  var error: NSError?
  if !managedContext.save(&error) {
      println("Could not save \(error), \(error?.userInfo)")
  }  
  //5
  people.append(person)
}

This is where Core Data kicks in! Here’s what the code does:

  1. Before you can save or retrieve anything from your Core Data store, you first need to get your hands on an NSManagedObjectContext. You can think of a managed object context as an in-memory “scratchpad” for working with managed objects.

    Think of saving a new managed object to Core Data as a two-step process: first, you insert a new managed object into a managed object context; then, after you’re happy with your shiny new managed object, you “commit” the changes in your managed object context to save it to disk.

    Xcode has already generated a managed object context as part of the new project’s template – remember, this only happens if you check the Use Core Data checkbox at the beginning. This default managed object context lives as a property of the application delegate. To access it, you first get a reference to the app delegate.

  2. You create a new managed object and insert it into the managed object context. You can do this in one step with NSManagedObject’s designated initializer: init(entity:insertIntoManagedObjectContext:).

    You may be wondering what an NSEntityDescription is all about. Recall that earlier, I called NSManagedObject a “shape-shifter” class because it can represent any entity. An entity description is the piece that links the entity definition from your data model with an instance of NSManagedObject at runtime.

  3. With an NSManagedObject in hand, you set the name attribute using key-value coding. You have to spell the KVC key (“name” in this case) exactly as it appears on your data model, otherwise your app will crash at runtime.
  4. You commit your changes to person and save to disk by calling save on the managed object context. Note that save takes one parameter, which is a pointer to an NSError; if there is ever an error with the save operation, you can inspect the error and alert the user if necessary.
  5. Congratulations! Your new managed object is now safely ensconced in your Core Data persistent store. Insert the new managed object into the people array so that it shows up in the table view when it reloads.

That’s a little more complicated than an array of strings, but not too bad. Some of the code here—getting the managed object context and entity¬—could be done just once in your own init or viewDidLoad and then reused later. For simplicity, you’re doing it all at once in one method.

Build and run the app, and add a few names to the table view:

image15

If the names are actually stored in Core Data, the HitList app should pass the persistence test. Double-tap the Home button to bring up the fast app switcher. Terminate the HitList app by flicking it upwards.

From Springboard, tap the HitList app to trigger a fresh launch. Wait, what happened? The table view is empty:

image16

You saved to Core Data, but after a fresh app launch, the people array is empty! The data is actually sitting there waiting, but you haven’t fetched it yet.

Fetching from Core Data

To get data from your persistent store and into the managed object context, you have to fetch it. Add the following method to ViewController.swift:

override func viewWillAppear(animated: Bool) {
  super.viewWillAppear(animated)
 
  //1
  let appDelegate =
  UIApplication.sharedApplication().delegate as AppDelegate
 
  let managedContext = appDelegate.managedObjectContext!
 
  //2
  let fetchRequest = NSFetchRequest(entityName:"Person")
 
  //3
  var error: NSError?
 
  let fetchedResults =
    managedContext.executeFetchRequest(fetchRequest,
    error: &error) as [NSManagedObject]?
 
  if let results = fetchedResults {
    people = results
  } else {
    println("Could not fetch \(error), \(error!.userInfo)")
  }
}

Step by step, this is what the code does:

  1. As mentioned in the previous section, before you can do anything with Core Data, you need a managed object context. Fetching is no different! You pull up the application delegate and grab a reference to its managed object context.
  2. As the name suggests, NSFetchRequest is the class responsible for fetching from Core Data. Fetch requests are both powerful and flexible. You can use requests to fetch a set of objects that meet particular criteria (e.g., “give me all employees that live in Wisconsin and have been with the company at least three years”), individual values (e.g., “give me the longest name in the database”) and more.


    Fetch requests have several qualifiers that refine the set of results they return. For now, you should know that NSEntityDescription is one of these qualifiers (one that is required!).

    Setting a fetch request’s entity property, or alternatively initializing it with init(entityName:), fetches all objects of a particular entity. This is what you do here to fetch all Person entities.

  3. You hand the fetch request over to the managed object context to do the heavy lifting.
    executeFetchRequest(_:error:) returns an optional array of managed objects that meets the criteria specified by the fetch request.

Note: If there are no objects that match the fetch request’s criteria, the method returns an optional value containing an empty array.

If an error occurred during the fetch, the method returns an optional value that contains nil. If this happens, you can inspect the NSError and respond appropriately.

Build and run the application once again. Immediately, you should see the list of names you added earlier:

image17

Great! They’re back from the dead. Add a few more names to the list and restart the app to verify that saving and fetching are working properly. Short of deleting the app, resetting the Simulator or throwing your phone off a tall building, the names will appear in the table view no matter what.

image18

Where To Go From Here?

In this tutorial you experienced several fundamental Core Data concepts: data models, entities, attributes, managed objects, managed object contexts and fetch requests. Here is the completed HitList project, fully integrated with Core Data.

There were a few rough edges in the HitList app: you had to get the managed object context from the app delegate each time, and you used KVC to access the attributes rather than a more natural object-style person.name. As you can see, Core Data is a large and extensive topic. There’s a lot more to learn!

If you’d like to learn more about creating Core Data applications using Swift, check out our book Core Data by Tutorials where you can go deeper into more advanced Core Data topics such as iCloud/Core Data integration, versioning and migration.

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

Your First Core Data App Using Swift is a post from: Ray Wenderlich

The post Your First Core Data App Using Swift appeared first on Ray Wenderlich.

Smart App Banners Tutorial

$
0
0
Learn how to add Smart App Banners linking to your app on your web site!

Learn how to add Smart App Banners linking to your app on your web site!

Note from Ray: This is a brand new tutorial released as part of the iOS 8 Feast. Enjoy!

According to the latest statistics, the Apple App Store boasts over 1.2 million apps.

Let that sink in for a moment. Though there are millions of potential users out there for your apps, it’s harder and harder to get your work noticed.

Of course, there’s an array of marketing strategies you can use to help elevate your app’s status, downloads and ultimately generate more revenue. Unfortunately, most require you to spend money to make money — something a lot of indie developers may not want or cannot afford to do.

There is a free option, though. Since the launch of iOS 6 in 2012, Apple’s allowed developers to add advertising banners, so-called Smart App Banners, to promote your app directly on a website.

For example, try browsing to math-ninja-app.com on your iOS device. You’ll see a Smart App Banner for the Math Ninja App by Razeware, as shown in the screenshot to the upper right.

In this short and sweet Smart App Banners tutorial, you’ll learn how to display a Smart App Banner on a website, by editing the HTML and using a cool WordPress plugin.

That face you make when somebody says, "Free Marketing."

Getting Started

Smart App Banners have limited scope and visibility. They only show on the Safari browser on iOS devices. Since the intent is to encourage the user to download or open the app, they display when a user visits a website or subpage that’s usually a landing page for the app.

Smart App Banners are, well…smart, so they only display on devices that support the promoted app. For example, if your app is only compatible with iOS 7 and above, a user on an iOS 6 device will never see the banner.

Likewise, a banner for an iPad-only app will not display on an iPhone or iPod. Finally, if an app isn’t available in the user’s country, the Smart App Banner will not display.

It detects whether the user already has the featured app. If not, the Smart App Banner invites the user to download or purchase the app, and tapping View brings the user to your App Store page.

mathninja

If the device already has the application, the Smart App Banner recognizes this and loads a slightly different ad with a link to open the app, rather than downloading and/or purchasing it.

mathninja2

Users can easily dismiss a Smart App Banner by tapping the X button on the left. Once dismissed, it doesn’t show itself again for that user on that website, even if the website is reloaded.

The only way to get it to show again is if the user clears some metadata on that iOS device, as described below.

Re-Showing Hidden Banners

Note: This section is optional. You only need to know this if you dismiss a smart app banner and want to know how to get it to show up again. Feel free to skip to the next section if you want to speed ahead to implementing a banner!

On iOS 6, Smart App Banners can reappear only if Safari’s cookies and data are erased by the user in the Settings App. (Open Settings, find Safari and select Delete cookies and data.)

On iOS 7.0, it’s in a similar location, but under Website Data. (Open Settings, find Safari, select Advanced, Website Data and Remove all Website Data).

Alternatively, you can tap the Edit button in the Website Data screen and then tap the minus button next to each website where you want the Smart App Banners.

websitedata

On iOS 7.1, the only way to have those Smart App Banners reappear, once dismissed, is to reset all settings. (Open Settings, find General, then go into Reset and Reset All Settings.)

Of course, this resets your iOS device to factory settings, which is a pretty radical solution. So the onus is on you to be strategic about where your banner displays; you don’t want to annoy users by peppering them with ads because they’ll just dismiss the banner and never see your app again.

How to Make Them Appear?

Since Smart App Banners are highly specialized marketing agents, you have to make some small modifications to the website where you want to place them.

One best practice is to only employ Smart App Banners on websites dedicated to your application(s). For example on math-ninja-app.com, or on subpages of websites that are all about applications, such as razeware.com/battle-map-2/.

Another important detail to note is that since only one Smart App Banner can display at a time, you must choose — and choose wisely — the perfect app to promote.

App ID

How does the Smart App Banner know what to display? You feed it an App ID, your application’s unique identifier within the Apple mobile ecosystem. There are two common ways to find an App ID.

From the iTunes.apple.com URL

If you view your application’s page on iTunes.apple.com, the URL contains your application’s App ID, as seen below, in the highlighted section of the browser’s address bar.

MathNinja3

From iTunes Connect

Log in to your account on iTunes Connect, click Manage your apps and then click on the application you plan to promote. From there, you can find your application’s App ID next to the label Apple ID.

MathNinjaAppID

Save your App ID number somewhere handy, as you’ll need it to work through the sections below and create your Smart App Banner.

Showing a Smart App Banner in Plain HTML

Adding a banner to your site’s HTML is extremely easy — it requires you to add a single line of code to the head. You can use this method on static pages, as well as those encoded by a CMS, provided you can access and edit each page’s source code.

<meta name="apple-itunes-app" content="app-id=myAppStoreID, affiliate-data=myAffiliateData, app-argument=myURL">

The most important part of this meta tag is the name attribute, which must always be apple-itunes-app. This identifies the type of meta tag, which in turn tells Safari to display your Smart App Banner.

The content attribute contains the following parameters/arguments:

  • app-argument=myAppStoreID (required): replace ‘myAppStoreID’ with your unique App ID
  • affiliate-data=myAffiliateData (optional): If you are an iTunes affiliate, replace ‘ myAffiliateData’ with your iTunes affiliate string
  • app-argument=myURL (optional): Specifies a context-sensitive URL that passes back to the application, so it can open and load in accordance with the current context. More on that later.

Once you have all the pieces necessary for this meta tag, insert it directly into website’s main page, usually named index.html, index.php, or something similar. Here’s an example of how looks on the Math Ninja website.

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Math Ninja iPhone/iPod Touch Game | Making Addition, Subtraction, Multiplication, and Division Fun!</title>
<meta name="apple-itunes-app" content="app-id=370144476"/>
<link rel="stylesheet" type="text/css" href="reset.css"/>
<link rel="stylesheet" type="text/css" href="style.css"/>
</head>

And this is how that renders in Safari:

mathninja

If you’re not sure about tinkering with your website’s HTML code, then consult with your webmaster or your favorite web professional.

Showing a Smart App Banner in WordPress

For websites developed on WordPress, you start by installing a free WordPress plugin. This makes it much easier to specify the App ID and display different banners on different subpages — all without touching the source code.

Easy Peasy

The aptly named Smart App Banners plugin by Justin Saad is an elegant solution.

Before installing the plugin, you need to ensure the version of WordPress installed on your website is compatible with the plugin. Technically, you should backup your website before installing a new plugin, but it’s rare that people report issues with this tool.

Check the requirements on the plugin’s landing page or dialog within WordPress. As of this writing, it’s compatible with version 2.9 to 3.8.3.

Installing the Plugin

To install the plugin, log in as an administrator to your website’s WordPress dashboard and navigate to the Plugins section.

razeware_wordpress

From the Plugins menu, click Add New, and within that page type Smart App Banners in the Search field.

razeware_wordpress2

Click Search Plugins to see the results, which will look similar to this — though plugins are constantly added, so your results could look different.

razeware_wordpress3

From those search results, the recommended plugin is likely the first one in the list, if not, just look for it and make sure the author is Justin Saad. In the search results list, click the Install Now link directly underneath the plugin name.

In the next screenshot, you can also see what the WordPress requirements look like, so you can tell if the plugin will work on your site.

If you don’t have a compatible version of WordPress installed — try updating to a newer build. Otherwise, the plugin could behave in unexpected ways. (It’s also wise to keep WordPress updated for the sake of security.)

razeware_wordpress4

The plugin comes with extra features, such as widgets to display “Download on the App Store” and “Download for Android” badges and shortcodes you can copy and paste into any page or HTML widget. This tutorial does not cover these, but they’re easy to set up and you can find out more directly from the plugin’s webpage.

The Smart App Banners plugin allows two different ways to specify the App ID: a global site banner and a subpage-specific banner.

Global Site Smart App Banner

In order to display a Smart App Banner across your entire WordPress site, navigate to the plugin’s settings page and specify the App ID in the appropriate field. Make sure that Show banner on all pages? is checked. Click Save Changes.

fullsite

This is what a Smart App Banner using this methodology looks like on the Wild Fables website:

wildfables

Every page on this site displays the banner, provided the user hasn’t dismissed it.

Subpage-specific Smart App Banner

But what if you only want to show the banner on a specific subpage? There’s a fix for that.

In order to specify a page-specific Smart App Banner, load the page or post in admin side of WordPress and specify the App ID as shown below.

BattleMap2

When users browse to that page on a mobile device using Safari, they will see the Smart App Banner for that mobile application. When they visit another page on that website, they’ll see no banner, unless you set an App ID for that page.

Here is a Smart App Banner displayed on the Battle Map 2 subpage of the Razeware website using this methodology, as seen in Safari on a device running iOS 6:

battle2

Using a Contextual URL with Smart App Banners

As you saw earlier, the content attribute of the meta tag can contain the app-argument parameter, and its value passes into your app when the user taps Open.

For example, if you add app-argument=http://mywebsite.com/reviews?123, the following code in your app’s AppDelegate could take the user directly to the review with ID 123 in your app:

- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication
         annotation:(id)annotation {
    if ([[url path] isEqualToString:@"/reviews"]) {
    	ReviewViewController *viewController = [[ReviewViewController alloc] init];
    	viewController.reviewID = [url query];
        [self.navigationController pushViewController:viewController animated:NO];
    }
    return YES;
}

This is convenient for your users to continue doing in your app what they started doing on your website, seamlessly. For example, if you had an app that allows you to purchase items, perhaps you want to start the user on a particular item.

Final Notes

Test the implementation of your Smart App Banner by loading the website or subpage where you placed it in Safari on a compatible iOS device. Also check to see if it self-modifies when you have installed the application.

Bear in mind that Smart App Banners display the language set on your iOS device the last time you connected to your iTunes/App Store account in the Settings App.

In order to test Smart App Banners in another language, you need to modify your device’s language in the Settings App, and also log out and reconnect to your iTunes/App Store account on that same device.

Where to Go From Here?

That’s it for this Smart App Banners tutorial!

Now you can start using your own Smart App Banners and enjoy a free, simple way to promote your app. If you’d like to know more, be sure to check out the Safari Web Content Guide.

We’d love to hear from you about the different marketing and contextual strategies you’re using to make the most of Smart App Banners, so be sure to leave your comments below.

Smart App Banners Tutorial is a post from: Ray Wenderlich

The post Smart App Banners Tutorial appeared first on Ray Wenderlich.


Video Tutorial: Introduction to Unity Part 13: Particle Systems

Xcode 6 Tips and Tricks Tech Talk Video

$
0
0

Each month, one of the members of the team gives a Tech Talk, and by popular request we’ve started to stream these live.

Today in our September Tech Talk, Chris Lowe (co-author of iOS 8 by Tutorials) gave an excellent talk and Q&A on Xcode 6 Tips and Tricks.

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 Chris 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!

Stay tuned for next month’s tech talk – we’ll put a signup link on the sidebar once it’s announced. Hope to see some of you there! :]

Xcode 6 Tips and Tricks Tech Talk Video is a post from: Ray Wenderlich

The post Xcode 6 Tips and Tricks Tech Talk Video appeared first on Ray Wenderlich.

Lightweight Migrations in Core Data Tutorial

$
0
0
Learn how to make your first Core Data app with Swift!

Learn how to make your first Core Data app with Swift!

Note from Ray: This is an abbreviated version of a chapter from Core Data by Tutorials released as part of the iOS 8 Feast to give you a sneak peek of what’s inside the book. We hope you enjoy!

When you create a Core Data app, you design an initial data model for your app. However, after you ship your app inevitably you’ll want to make changes to your data model. What do you do then – you don’t want to break the app for existing users!

You can’t predict the future, but with Core Data, you can migrate toward the future with every new release of your app. The migration process will update data created with a previous version of the data model to match the current data model.

This tutorial gives you an introduction to Core Data migrations by covering the most common and simple type of migration – a lightweight migration.

You’ll start with a simple app with only a single entity in its data model, and use a lightweight migrations to automatically update a user’s data model.

Let the journey begin!

Note: This tutorial assumes some basic knowledge of Core Data and Swift.

When to Migrate

When is a migration necessary? The easiest answer to this common question is “when you need to make changes to the data model.”

However, there are some cases in which you can avoid a migration. If an app is using Core Data merely as an offline cache, then when you update the app, you can simply delete and rebuild the data store. This is only possible if the source of truth for your user’s data isn’t in the data store. In all other cases, you’ll need to safeguard your user’s data.

That said, any time it’s impossible to implement a design change or feature request without changing the data model, you’ll need to create a new version of the data model and provide a migration path.

The Migration Process

When you initialize a Core Data stack, one of the steps involved is adding a store to the persistent store coordinator. When you encounter this step, Core Data does a few things prior to adding the store to the coordinator.

First, Core Data analyzes the store’s model version. Next, it compares this version to the coordinator’s configured data model. If the store’s model version and the coordinator’s model version don’t match, then Core Data will perform a migration, when enabled.

Note: If migrations aren’t enabled, and the store is incompatible with the model, Core Data will simply not attach the store to the coordinator and specify an error with an appropriate reason code.

To start the migration process, Core Data needs the original data model and the destination model. It uses these two versions to load or create a mapping model for the migration, which it uses to convert data in the original store to data that it can store in the new store. Once Core Data determines the mapping model, the migration process can start in earnest.

Migrations happen in three steps:

  1. First, Core Data copies over all the objects from one data store to the next.
  2. Next, Core Data connects and relates all the objects according to the relationship mapping.
  3. Enforce any data validations in the destination model. Core Data disables destination model validations during the data copy.

You might ask, “If something goes wrong, what happens to the original source data store?” With nearly all types of Core Data migrations, nothing happens to the original store unless the migration completes without error. Only when a migration is successful, will Core Data remove the original data store.

Types of Migrations

In my own experience using Core Data, I’ve found there are a few more migration variants than the simple distinction between lightweight and heavyweight. Below, I’ve provided the more subtle variants of migration names, but these names are not official categories by any means. I’ll start with the least complex form of migration and end with the most complex form.

Lightweight migrations

A lightweight migration is Apple’s term for the migration with the least amount of work involved on your part. Simply enable a couple of flags when setting up a Core Data stack, and the migration happens automatically. There are some limitations on how much you can change the data model, but because of the small amount of work required to enable this option, it is the ideal setting.

Manual migrations

Manual migrations involve a little more work on your part. You need to specify how to map the old set of data onto the new set, but you get the benefit of a more explicit mapping model file to configure. Setting up a mapping model in Xcode is much like setting up a data model, with similar GUI tools and some automation.

Custom manual migrations

This is level 3 of the migration complexity index. You still use a mapping model, but add to that custom code with the ability to also specify custom transformation logic on data. In this case, custom entity transformation logic involves creating an NSEntityMigrationPolicy subclass and performing custom transformations there.

Fully manual migrations

Fully manual migrations are for those times when even specifying custom transformation logic isn’t enough to fully migrate data from one model version to another. In this case, custom version detection logic and custom handling of the migration process are necessary. In this chapter, you’ll use set up a fully manual migration to update data across non-sequential versions, such as jumping from version 1 to 4.

In this tutorial, you will focus on lightweight migrations because they are the easiest and most common type of migrations. Let’s get started!

Getting Started

First, download this starter project for this tutorial and open it in the latest public version of Xcode (6.0.1 at the time of writing this tutorial).

Build and run the app in the iPhone simulator. You’ll see an empty list of notes:

Starter project

Tap the plus (+) button in the top-right corner to add a new note. Add a title (there is default text in the note body to make the process faster) and tap Create to save the new note to the data store. Repeat this a few times so that you have some sample data to migrate.

Back in Xcode, open the UnCloudNotesDatamodel.xcdatamodeld file to show the entity modeling tool in Xcode. The data model is simple—just one entity, a Note, with a few attributes.

Modeling tool in Xcode

You’re going to add a new feature to the app: the ability to attach a photo to a note. The data model doesn’t have any place to persist this kind of information, so you’ll need to add a place in the data model to hold onto the photo. But you already added a few test notes in the app—how can you change the model without breaking the existing notes? It’s time for your first migration!

A Lightweight Migration

With the entity modeler open, open the Editor menu and select Add Model Version…. Call the new version UnCloudNotesDataModel v2 and select UnCloudNotesDataModel in the “Based on Model” field. Xcode will now create a copy of the data model.

Note: You can give this file any name you want. The sequential v2, v3, v4, et cetera naming helps you tell the versions apart easily.

This step will create a second version of the data model, but you still need to tell Xcode to use the new version as the current model. In the File Inspector pane on the right, find the option toward the bottom called Model Version. Change that selection to match the name of the new data model, UnCloudNotesDataModel v2:

Once you’ve made that change, notice in the project navigator that the little green check mark icon has moved from the previous data model to the v2 data model:

003_Migration

Core Data will load the ticked version when setting up the stack. The older version is there to support migration—it’s hard to migrate to a new model without knowing the old one!

Make sure you have the v2 data model selected and add an image attribute to the Note entity. Set the attribute’s name to image and the attribute’s type to Transformable.

Since this attribute is going to contain the actual binary bits of the image, you’ll use a custom NSValueTransformer to convert from binary bits to a UIImage and back again. Just such a transformer has been provided for you as ImageTransformer. In the Value Transformer Name field in the Data Model Inspector on the right of the screen, enter UnCloudNotes.ImageTransformer.

004_Transformer

The new model is now ready for some code! Open Note.swift and add a property to match the new attribute:

@NSManaged var image: UIImage?

Build and run, and you’ll see your notes have disappeared! In the Xcode console, you’ll see some error text related to the CoreDataStack object:

context: 
modelName: UnCloudNotesDataModelmodel: [Note: ]
coordinator: 
storeURL: file:///Users/YOURNAME/Library/Developer/CoreSimulator/Devices/A24A4E68-D616-4F63-8946-652164EE5E53/data/Containers/Data/Application/9921B2DD-D0FD-4330-90F9-A2F44CC9899A/Library/Application%20Support/UnCloudNotes.sqlite
store: nil

The store file is still around (storeURL in the log above), but since it’s incompatible with the new v2 model, Core Data couldn’t attach it to the persistent store, so store is still nil.

Core Data can automatically update your store if all you’ve done is add a new property like this. These are called lightweight migrations.

Enabling Lightweight Migrations

To enable lightweight migrations, you need to set two flags on initialization. The stack in this app lives in an object imaginatively titled CoreDataStack, which you’ll modify to do this.

Open CoreDataStack.swift and add a property to the class:

var options: NSDictionary?

Right now, you’re setting up the persistent store with no options for default behavior. You’ll use the options dictionary to set the necessary flags.

Next, update the initializer to match the following:

init(modelName: String, storeName: String,
 options: NSDictionary? = nil) {
  self.modelName = modelName
  self.storeName = storeName
  self.options = options
}

In setting the default value of options to nil, the old method signature remains valid and you have the additional choice of passing in the options dictionary.

Find the coordinator computed property and change the initialization of the persistent store as follows:

store = coordinator.addPersistentStoreWithType(
  NSSQLiteStoreType,
  configuration: nil,
  URL: storeURL,
  options: self.options,
  error: nil)

There’s just a small change here to pass in the extra options when creating the stack.

Open NotesListViewController.swift and change the CoreDataStack lazy initialization statement to use the lightweight migration options:

lazy var stack : CoreDataStack = CoreDataStack(
  modelName:"UnCloudNotesDataModel",
  storeName:"UnCloudNotes",
  options:[NSMigratePersistentStoresAutomaticallyOption: true,
           NSInferMappingModelAutomaticallyOption: true])

The NSMigratePersistentStoresAutomaticallyOption is what tells Core Data (the NSPersistentStoreCoordinator, actually) to start a migration if the persistent store model isn’t compatible with the current data model. Core Data will handle all the details, from finding the source model to creating the destination store file, and all the steps in between.

The NSInferMappingModelAutomaticallyOption is the other half of what makes a lightweight migration possible. Every migration requires a mapping model. Here’s an analogy: If you’re traveling from a known place on Earth to somewhere unknown, you’ll want a map to tell you where to go. The mapping model is that guide.

It just so happens that Core Data can infer a mapping model in many cases. That is, Core Data can automatically look at the differences in two data models and create a mapping model between them. For entities and attributes that are identical between model versions, this is a straightforward data pass through mapping. For other changes, just follow a few simple rules for Core Data to create a mapping model. In the new model, changes must fit an obvious migration pattern, such as:

  1. Deleting entities, attributes or relationships;
  2. Renaming entities, attributes or relationships using the renamingIdentifier;
  3. Adding a new, optional attribute;
  4. Adding a new, required attribute with a default value;
  5. Changing an optional attribute to non-optional and specifying a default value;
  6. Changing a non-optional attribute to optional;
  7. Changing the entity hierarchy;
  8. Adding a new parent entity and moving attributes up or down the hierarchy;
  9. Changing a relationship from to-one to to-many;
  10. Changing a relationship from non-ordered to-many to ordered to-many (and vice versa).
Note: Check out Apple’s documentation for more information on how Core Data infers a lightweight migration mapping.

As you can see from this list, Core Data can detect, and more importantly, automatically react to, a wide variety of common changes between data models. As a rule of thumb, all migrations, if necessary, should start as lightweight migrations and only move to more complex mappings when the need arises.

As for the migration from UnCloudNotes to UnCloudNotes v2, the image property has a default value of nil since it’s an optional property. This means Core Data can easily migrate the old data store to a new one, since this change follows item 3 in the list of lightweight migration patterns.

Build and run, and your old notes have returned! Core Data has migrated the data store automatically using an inferred mapping model.

The non-nil value for the store: entry in the logs is a nice confirmation that the migration actually happened and that there’s now an NSPersistentStore object representing the store.

005_Output

Congratulations—you’ve completed your first data migration!

Image attachments

Now that data is migrated, you need to update the UI to allow image attachments to new notes. Luckily, most of this work has been done for you, so you can quickly get to the interesting part. :]

Open Main.storyboard and go to the Create Note scene. Just underneath, you’ll see a Create Note With Images scene that includes the interface to attach an image.

The Create Note scene is attached to a navigation controller with a root view controller relationship. Control-drag from the navigation controller to the Create Note With Images scene and select the root view controller relationship segue. This will disconnect the old Create Note scene and connect the new, image-powered one instead:

006_Storyboard

Open AttachPhotoViewController.swift and add the following method to the class:

func imagePickerController(picker: UIImagePickerController,
 didFinishPickingMediaWithInfo info: NSDictionary) {
  if let note = note {
    note.image = info[UIImagePickerControllerOriginalImage] as? UIImage
  }
  self.navigationController?.popViewControllerAnimated(true)
}

This will populate the new image property of the note once the user selects something from the standard image picker.

Open CreateNoteViewController.swift and replace viewDidAppear with the following:

override func viewDidAppear(animated: Bool) {
  super.viewDidAppear(animated)
  if let image = _note?.image {
    attachedPhoto.image = image
    view.endEditing(true)
  } else {
    titleField.becomeFirstResponder()
  }
}

This implementation will display the new image if the user has added one.

Next, open NotesListViewController.swift and update tableView(_:cellForRowAtIndexPath) with the following:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
  let note = notes.fetchedObjects![indexPath.row] as Note
  var identifier = "NoteCell"
  if note.image != nil {
    identifier = "NoteCellImage"
  }
  var cell = tableView.dequeueReusableCellWithIdentifier(identifier, forIndexPath: indexPath) as NoteTableViewCell;
  cell.note = notes.fetchedObjects![indexPath.row] as? Note
  return cell
}

This will set the correct cell identifier based on whether an image is present in the note. If there is an image, you also need to populate the image view in the cell. Open NoteTableViewCell.swift and add the following lines after the code that sets the creation date label’s text in updateNoteInfo():

if let image = note?.image {
  noteImage.image = image
}

Build and run, and choose to add a new note:

007_New_Note

Tap the Attach Image button to add an image to the note. Choose an image and you’ll see it in your new note:

008_Attach_Image

The app uses a standard UIImagePickerController to add photos as attachments to notes. Hooray - you now have successfully modified your data model!

Note: To add your own images to the Simulator’s photo album, drag an image file onto the open Simulator window. Thankfully, the iOS 8 Simulator now comes with a library of photos ready for your use. :]

If you’re using a device, go to AttachPhotoViewController.swift and set the sourceType attribute on the image picker controller to .Camera to take photos with the device camera. The existing code uses the photo album, since there is no camera in the Simulator.

Where To Go From Here?

Here is the final example project from the above tutorial.

If you'd like to learn about more advanced migrations, like manual/heavyweight migrations, check out our book Core Data by Tutorials. The full chapter in the book takes this further, creating several more migrations to demonstrate mapping models, attribute/relationship mapping, custom migration policies, migrating non-sequential versions, and more!

I hope you enjoyed this tutorial, and if you have any questions or comments, please join the discussion thread below!

Lightweight Migrations in Core Data Tutorial is a post from: Ray Wenderlich

The post Lightweight Migrations in Core Data Tutorial appeared first on Ray Wenderlich.

The iOS Apprentice Updated for Xcode 6.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 for Xcode 6.1!

Xcode 6.1 has a few small changes to Swift – mostly minor syntax things – but we wanted to make sure that all the instructions work without any issues.

Xcode 6.1 is supposed to go live on the App Store today (in theory), except for some reason it’s still showing 6.0.1 at the time of writing this post.

But it should be out anytime, so when it comes out the updated iOS Apprentice will be there for you! :]

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.1).
  • If you haven’t picked up a copy of the iOS Apprentice yet, grab your copy now.

We’re hard at work updating the rest of our Swift books for Xcode 6.1 – stay tuned.

Matthijs and I hope you enjoy this update!

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

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

Multiple Managed Object Contexts in Core Data Tutorial

$
0
0
Learn how to work with multiple Managed Object Contexts in Core Data with Swift!

Learn how to work with multiple Managed Object Contexts in Core Data with Swift!

Note from Ray: This is an abbreviated version of a chapter from Core Data by Tutorials released as part of the iOS 8 Feast to give you a sneak peek of what’s inside the book. We hope you enjoy!

A managed object context is an in-memory scratchpad that you use to work with your managed objects in Core Data.

Most apps need but a single managed object context. A single managed object context with a main queue, the default behavior, is simple to manage and understand. Apps with multiple managed object contexts are harder to debug. For that reason, you should avoid them, if possible.

That being said, certain situations do warrant the use of more than one managed object context. For example, long-running tasks such as exporting data will block the main thread of apps that use only a single main-queue managed object context, causing the UI to stutter.

In other situations, such as when temporarily editing user data, it’s helpful to treat a managed object context as a set of changes that the app can just throw away if it no longer needs them. Using child contexts makes this possible.

In this Core Data tutorial in Swift, you’ll learn about multiple managed object contexts by taking a journaling app for surfers and improving it in several ways by adding multiple contexts.

Note: This is an advanced tutorial, and assumes prior knowledge of Swift, Core Data, and iOS app development in general. If common Core Data phrases such as managed object subclass and persistent store coordinator don’t ring any bells, or if you’re unsure what a Core Data stack is supposed to do, you may want to read some of other Core Data tutorials first.

Getting Started

This tutorial’s starter project is a simple journal app for surfers. After each surf session, a surfer can use the app to create a new journal entry that records marine parameters, such as swell height or period, and rate the session from 1 to 5.

Dude, if you’re not fond of hanging ten and getting barreled, no worries, brah. Just replace the surfing terminology with your favorite hobby of choice!

Introducing Surf Journal

Open the SurfJournal starter project, then build and run the app.

On startup, the application lists all previous surf session journal entries. Tapping on a row in the list brings up the detail view of a surf session with the ability to make edits.

screenshot02 screenshot01

As you can see, the sample app works and has data. Tapping the Export button on the top-left exports the data to a comma-separated values (CSV) file. Tapping the plus (+) button on the top-right adds a new journal entry. Tapping a row in the list opens the entry in edit mode, letting you make changes or view the details of a surf session.

Although the sample project appears simple, it actually does a lot and will serve as a good base to add multi-context support. First, make sure you have a good understanding of the various classes in the project.

Open the project navigator and take a look at the full list of files in the starter project:

screenshot03

Before jumping into the code, let’s briefly go over what each class does for you out of the box.

  • AppDelegate: On first launch, the app delegate creates the Core Data stack and sets the coreDataStack property on the primary view controller JournalListViewController.
  • CoreDataStack: This object contains the cadre of Core Data objects known as the “stack”: the context, the model, the persistent store and the persistent store coordinator. The stack installs a database that already has data in it on first launch. No need to worry about this just yet; you’ll see how it works shortly.
  • JournalListViewController: The sample project is a one-page table-based application. This file represents that table. If you’re curious about its UI elements, head over to Main.storyboard. There’s a table embedded in a navigation controller and a single prototype cell of type SurfEntryTableViewCell.
  • JournalEntryViewController: This class handles creating and editing surf journal entries. You can see its UI in Main.storyboard.
  • JournalEntry: This class represents a surf journal entry. It is an NSManagedObject subclass with six properties for attributes: date, height, location, period, rating and wind. It also includes the CSV export function csv. If you’re curious about this class’s entity definition, head over to SurfJournalModel.xcdatamodel.

screenshot04

When you first launched the app, it already had a significant amount of data. While it is common to import seed data from a JSON file, this sample project comes with a seeded Core Data database. Let’s see how it works.

The Core Data Stack

Open CoreDataStack.swift and find the following code in init:

// 1
let seededDatabaseURL = bundle.URLForResource("SurfJournalDatabase", withExtension: "sqlite")
 
// 2
var fileManagerError:NSError? = nil
let didCopyDatabase = NSFileManager.defaultManager().copyItemAtURL(seededDatabaseURL!, toURL: storeURL, error: &fileManagerError)
 
// 3
if didCopyDatabase {

Let’s go through the code step by step:

  1. The app bundle comes with a pre-populated Core Data database named SurfJournalDatabase.sqlite. To make use of this database, first you have to find it and create a URL reference to it using URLForResource(_:withExtension:).
  2. copyItemAtURL(_:toURL:error:) attempts to copy the seeded database file to the app’s documents directory. If the database file already exists in the documents directory, the copy operation fails. This behavior allows the seeding operation to happen only once, on first launch.
  3. On subsequent app launches, the database will already exist and the copy will fail. When the copy operation fails, the variable didCopyDatabase will be false and the code in the if-statement will never execute.

Assume that the app is launching for the first time and therefore didCopyDatabase is true. Let’s see how the rest of the seeding operation works:

// 4
fileManagerError = nil
let seededSHMURL = bundle.URLForResource("SurfJournalDatabase", withExtension: "sqlite-shm")
let shmURL = documentsURL.URLByAppendingPathComponent("SurfJournalDatabase.sqlite-shm")
 
let didCopySHM = NSFileManager.defaultManager().copyItemAtURL(seededSHMURL!, toURL: shmURL, error: &fileManagerError)
if !didCopySHM {
  println("Error seeding Core Data: \(fileManagerError)")
  abort()
}
 
// 5
fileManagerError = nil
let walURL = documentsURL.URLByAppendingPathComponent("SurfJournalDatabase.sqlite-wal")
let seededWALURL = bundle.URLForResource("SurfJournalDatabase", withExtension: "sqlite-wal")
 
let didCopyWAL = NSFileManager.defaultManager().copyItemAtURL(seededWALURL!, toURL: walURL, error: &fileManagerError)
if !didCopyWAL {
  println("Error seeding Core Data: \(fileManagerError)")
  abort()
}

To support concurrent reads and writes, SQLite, the persistent store in use by this sample app, utilizes SHM (shared memory file) and WAL (write-ahead logging) files. You don’t need to know how these extra files work, but you do need to be aware that they exist and that you need to copy them over when seeding the database. If you fail to copy over these files, the app will work, but it will be missing data.

  1. Once the initializer has successfully copied the primary SurfJournalDatabase.sqlite, it copies over the support file SurfJournalDatabase.sqlite-shm.
  2. Finally, the initializer copies over the other support file, SurfJournalDatabase.sqlite-wal.

The only reason SurfJournalDatabase.sqlite, SurfJournalDatabase.sqlite-shm or SurfJournalDatabase.sqlite-wal would fail to copy over on first launch is if something really bad happened, such as disk corruption from cosmic radiation. In that case the device, including any apps, would likely also fail. If the app won’t work, there’s no point in continuing, so the initializer calls abort().

Note: We developers often frown upon using abort(), as it confuses users by causing the app to quit suddenly and without explanation. But this is one example where abort() is acceptable, since the app needs Core Data to work.

If an app requires Core Data to be useful and Core Data isn’t working, there’s no point in letting the app continue on, only to fail sometime later in a non-deterministic way. Calling abort() at least generates a stack trace, which can be helpful when trying to fix the problem.

If your app has support for remote logging or crash reporting, you should log any relevant information that might be helpful for debugging before calling abort().

Once the initializer has copied over the pre-populated database and support files, the final step is to add the seeded database store to the persistent store coordinator.

// 6
var error: NSError? = nil
let options = [NSInferMappingModelAutomaticallyOption:true,   NSMigratePersistentStoresAutomaticallyOption:true]
store = psc.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: options, error: &error)
 
// 7
if store == nil {
  println("Error adding persistent store: \(error)")
  abort()
}
  1. NSPersistentStoreCoordinator hands you an NSPersistentStore object as a side effect of attaching a persistent store type. You simply have to specify the store type (NSSQLiteStoreType in this case), the URL location of the store file and some configuration options.
  2. Finally, the initializer checks if the store was successfully created. If it wasn’t, the app won’t work, so there’s no point in continuing; the initializer calls abort.

Now that you know something about beginning with a seeded database, let’s start learning about multiple managed object contexts by adding a second context with a private queue to the Surf Journal app.

Doing Work in the Background

If you haven’t done so already, tap the Export button at the top-left and then immediately try to scroll the list of surf session journal entries. Notice anything? The export operation will take several seconds and it will prevent the UI from responding to touch events, such as scrolling.

The UI is blocked during the export operation because both the export operation and UI are using the main queue to perform their work. This is the default behavior.

How can you fix this? The traditional way would be to use Grand Central Dispatch to run the export operation on a background queue. However, Core Data managed object contexts are not thread-safe. That means you can’t just dispatch to a background queue and use the same Core Data stack.

The solution is easy: just add another context for the export operation that uses a private queue rather than the main queue, so the export operation can do its work in the background. This will keep the main queue free for the UI to use.

But before you jump in and fix the problem, you need to understand how the export operation works.

Exporting Data

Start by viewing how the app creates the CSV strings for the Core Data entity. Open JournalEntry.swift and find csv():

func csv() -> String {
  let coalescedHeight = height ?? ""
  let coalescedPeriod = period ?? ""
  let coalescedWind = wind ?? ""
  let coalescedLocation = location ?? ""
  var coalescedRating:String
  if let rating = rating?.intValue {
    coalescedRating = String(rating)
  } else {
    coalescedRating = ""
  }
 
  return "\(stringForDate()),\(coalescedHeight)," +
    "\(coalescedPeriod),\(coalescedWind)," +
    "\(coalescedLocation),\(coalescedRating)\n"
}

As you can see, this JournalEntry function returns a comma-separated string of the entity’s attributes. Because the JournalEntry attributes are allowed to be nil, the function uses the nil coalescing operator (??) so that it exports an empty string instead of an unhelpful debug message that the attribute is nil.

Note: The nil coalescing operator (??) unwraps an optional if it contains a value; otherwise it returns a default value. For example, the following:

let coalescedHeight = height != nil ? height! : ""

Can be shortened by using the nil coalescing operator:

let coalescedHeight = height ?? ""

Now that you know how the app creates the CSV strings for an individual journal entry, take a look at how the app saves the CSV file to disk. Switch to JournalListViewController.swift and find the following code in exportCSVFile:

// 1
var fetchRequestError: NSError? = nil
let results = coreDataStack.context.executeFetchRequest( self.surfJournalFetchRequest(), error: &fetchRequestError)
if results == nil {
  println("ERROR: \(fetchRequestError)")
}
 
// 2
let exportFilePath = NSTemporaryDirectory() + "export.csv"
let exportFileURL = NSURL(fileURLWithPath: exportFilePath)
NSFileManager.defaultManager().createFileAtPath( exportFilePath, contents: NSData(), attributes: nil)

Let’s go through the CSV export code step by step:

  1. First, the code retrieves all JournalEntry entities by executing a fetch request. The fetch request is the same one used by the fetched results controller and therefore the code uses surfJournalFetchRequest to create it, avoiding duplication.
  2. The code creates the URL for the exported CSV file by appending the file name (“export.csv”) to the output of NSTemporaryDirectory. The path returned by NSTemporaryDirectory is a unique directory for temporary file storage. This a good place for files that can easily be generated again and don’t need to be backed up by iTunes or to iCloud. After creating the export URL, the code calls createFileAtPath(_:contents:attributes:) to create the empty file to store the exported data. If a file already exists at the specified file path, then the code removes it first.

Once the app has the empty file, it can write the CSV data to disk:

// 3
var fileHandleError: NSError? = nil
let fileHandle = NSFileHandle.fileHandleForWritingToURL(exportFileURL, error: &fileHandleError)
if fileHandle == nil {
  println("ERROR: \(fileHandleError)")
}
 
// 4
for object in results {
  let journalEntry = object as JournalEntry
 
  fileHandle.seekToEndOfFile()
  let csvData = journalEntry.csv().dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
  fileHandle.writeData(csvData!)
}
 
// 5
fileHandle.closeFile()
  1. First, the app needs to create a file handler for writing, which is simply an object that handles the low-level disk operations necessary for writing data. To create a file handler for writing, the code calls fileHandleForWritingToURL(_:error:).
  2. Using a for-in statement, the code iterates over all JournalEntry entities. During each iteration, the code creates a UTF8-encoded string using csv and dataUsingEncoding(_:allowLossyConversion:). It then writes the UTF8 string to disk using writeData.
  3. Finally, the code closes the export file-writing file handler, since it’s no longer needed.
    Once the app has written all the data to disk, it shows an alert dialog with the exported file path:

Once the app has written all the data to disk, it shows an alert dialog with the exported file path:

screenshot05

Note: This alert view with the export path is fine for learning purposes, but for a real app, you’ll need to provide the user with a way to retrieve the exported CSV file. Attaching the export file to an email is a popular method.

To open the exported CSV file, use Excel, Numbers or your favorite text editor to navigate to and open the file specified in the alert dialog. If you open the file in Numbers you will see the following:

screenshot06

Now that you’ve seen how the app currently exports data, it’s time to make some improvements.

Exporting on a Private Queue

You want the UI to continue to work while the export is happening. To fix the UI problem, you’ll perform the export operation on a private background queue instead of on the main queue.

Open JournalListViewController.swift and find the following code in exportCSVFile:

var fetchRequestError: NSError? = nil
let results = coreDataStack.context.executeFetchRequest(self.surfJournalFetchRequest(), error: &fetchRequestError)
if results == nil {
  println("ERROR: \(fetchRequestError)")
}

As you saw earlier, this code retrieves all of the journal entries by calling executeFetchRequest on the managed object context.

Now replace it with the following:

// 1
let privateContext = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
privateContext.persistentStoreCoordinator = coreDataStack.context.persistentStoreCoordinator
 
// 2
privateContext.performBlock { () -> Void in
 
  // 3
  var fetchRequestError:NSError? = nil
  let results = privateContext.executeFetchRequest(self.surfJournalFetchRequest(), error: &fetchRequestError)
  if results == nil {
    println("ERROR: \(fetchRequestError)")
  }

Let’s go through the new code, which utilizes a new managed object context, step by step:

  1. First, you create a new managed object context called privateContext with a concurrency type of PrivateQueueConcurrencyType, which specifies that the context will be associated with a private dispatch queue. Once you’ve created the new context, you assign it the same persistent store coordinator as the main managed object context.
  2. Next, you call performBlock. This function asynchronously performs the given block on the context’s queue. In this case, the queue is private.
  3. Just as before, you retrieve all JournalEntry entities by executing a fetch request. But this time, you use the private context to execute the fetch request.

Next, find the following code in the same function:

self.navigationItem.leftBarButtonItem = self.exportBarButtonItem()
println("Export Path: \(exportFilePath)")
self.showExportFinishedAlertView(exportFilePath)

Now replace it with the following:

  // 4
  dispatch_async(dispatch_get_main_queue(), { () -> Void in
    self.navigationItem.leftBarButtonItem = self.exportBarButtonItem()
    println("Export Path: \(exportFilePath)")
    self.showExportFinishedAlertView(exportFilePath)
  })
 
} // 5 closing brace for performBlock()
  1. You should always perform all operations related to the UI, such as showing an alert view when the export operation is finished, on the main queue; otherwise unpredictable things will happen. You use the dispatch_async and dispatch_get_main_queue to show the final alert view message on the main queue.
  2. Finally, the block you opened earlier in step 2 via the performBlock call now needs to be closed with a closing curly brace.

Note: There are three concurrency types a managed object context can use:

ConfinementConcurrencyType specifies that the context will use the thread confinement pattern and that the developer will be responsible for managing all thread access. You should consider this type deprecated and never use it, as the next two types will cover all use cases.

PrivateQueueConcurrencyType specifies that the context will be associated with a private dispatch queue instead of the main queue. This is the type of queue you just used to move the export operation off of the main queue so that it no longer interferes with the UI.

MainQueueConcurrencyType, the default type, specifies that the context will be associated with the main queue. This type is what the main context (coreDataStack.context) uses. Any UI operation, such as creating the fetched results controller for the table view, must use a context of this type.

Now that you’ve moved the export operation to a new context with a private queue, it’s time to build and run and see if it works! Give it a go.

You should see exactly what you saw before:

screenshot07

Tap the Export button in the top-left and then immediately try to scroll the list of surf session journal entries. Notice anything different this time? The export operation still takes several seconds to complete, but now the table view continues to scroll during this time. The export operation is no longer blocking the UI.

Cowabunga, dude! Gnarly job making the UI more responsive.

You’ve just witnessed how creating a new managed object context with a private queue can improve a user’s experience with your app.

Where To Go From Here?

Here is the SurfJournal final project for this tutorial.

If you followed this tutorial all the way through, you’ve turned an app with a single managed object context into an app with multiple contexts. You improved UI responsiveness by performing the export operation on a managed object context with a private queue.

If you want to learn more about multiple managed object contexts, check out the full chapter in Core Data by Tutorials, where I go a bit further and cover parent and child contexts.

In the meantime, if you have any questions or comments, please join the forum discussion below!

Multiple Managed Object Contexts in Core Data Tutorial is a post from: Ray Wenderlich

The post Multiple Managed Object Contexts in Core Data Tutorial appeared first on Ray Wenderlich.

Core Data with Saul Mora – Podcast S02 E02

$
0
0
A deep dive into Core Data with Saul Mora!

A deep dive into Core Data with Saul Mora!

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

Remember that among the many changes in this season, we are now moving to a weekly (and shorter) format – so episode 2 is out already.

In this episode, we talk with Saul Mora, NSBrief host and co-author of Core Data by Tutorials, and take a deep dive into Core Data.

[Subscribe in iTunes] [RSS Feed]

Links and References

Contact Us

Where To Go From Here?

We hope you enjoyed this podcast, and the changes we made for season 2.

Remember – we’re now on a weekly format, so 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!

Core Data with Saul Mora – Podcast S02 E02 is a post from: Ray Wenderlich

The post Core Data with Saul Mora – Podcast S02 E02 appeared first on Ray Wenderlich.

Video Tutorial: iOS Animation with Swift Part 11: Stroke Animation


Create a Game Like Cut the Rope Using Sprite Kit and Swift

$
0
0
CutTheVerlet

Ever feed a pineapple to a crocodile? In this tutorial, you’ll find out how!

Update note: This Sprite Kit tutorial was updated for iOS 8 and Swift by Nick Lockwood. Original post by Tutorial Team member Tammy Coron.

Prior to iOS 7, if you wanted to make a game, you either had to know a bit of arcane OpenGL magic, or rely on a third party library to do the heavy lifting for you. Once you had your graphics engine in place, you’d often need to add additional libraries for physics, sound effects, etc. This could result in additional dependencies as well as additional language requirements (such as C++).

With the introduction of Sprite Kit in iOS 7, Apple changed all of this. Developers have access to an integrated 2D graphics and physics engine, all exposed via a friendly Cocoa API. Now, developers can focus on making a game, instead of trying to assemble an engine from raw materials.

In this tutorial, you will use Sprite Kit to make a game similar to Cut the Rope, the award-winning, physics-based puzzle game. You’ll learn how to:

  • Add sprites to scenes
  • Create animation sequences
  • Add music and sound effects
  • Work with Sprite Kit’s physics engine!

By the end of this tutorial, you’ll be well on your way to using Sprite Kit to create your own game projects from scratch.

This is not an entry-level tutorial; if classes such as SKNode or SKAction are entirely new to you, then check out our Sprite Kit Tutorial for Beginners before continuing. That tutorial will get you quickly up to speed so you can start feeding pineapples to crocodiles.

Wait. What?

Read on.

Note: Make sure you’re using the latest version of Xcode 6.1 before continuing! Due to several incompatible changes in Swift, you’ll get compiler errors if you use Xcode 6.0!

On Your Marks… Get Set…

In this tutorial, you’ll be creating a game called Cut the Verlet. This game is modelled after Cut the Rope which tasks you to cut a rope holding a candy so it will drop into the mouth of a cute (but hungry, and impatient) creature. This game was first demonstrated in a previous tutorial using Objective-C and Cocos2D, but in this tutorial, you’ll be using Sprite Kit and Swift.

Modeling Particle Trajectories

So what is a Verlet? Verlet is not actually a what but a who – Loup Verlet is a French physicist responsible for inventing Verlet integration, a mathematical method for modelling particle trajectories in motion, and also a great tool for simulating other physical interactions, such as ropes and solid structures. The original Cocos2D version of this tutorial used a Verlet integrator, but for the Sprite Kit version you’ll be using the built-in physics engine instead of a Verlet integrator (we’re keeping the name though).

If you’re interested in finding out more about modelling ropes using Verlet integrators, Gustavo Ambrozio (the author of the Cocos2D version of this tutorial) provides an excellent overview of verlets and how they are applied to the game. It’s not required reading for this tutorial, however.

To get started, first download the starter project for this tutorial. Extract the project to a convenient location on your hard drive and then open it in Xcode for a quick look at how it’s structured.

The project files are split into six folders, as shown below:

Folders

  • Classes contains the primary code files, including the main view controller, the scene and the rope node. You will be adding to these classes throughout this tutorial.
  • Supporting Files contains the project’s main storyboard and info.plist. You won’t need to touch these.
  • Resources/Sounds contains the project’s sound effects and music files.
  • Resources/Particles contains the files you need to add particles to the scene.
  • Resources/Data contains data files that define the level.
  • Images.xcassets contains all of the image assets for this project (this is technically a folder, although Xcode displays it differently).

For this tutorial, you’ll be working only with the files located in the Classes folder.

It’s time to begin!

Constant Vigilance

A constant is a property whose value never changes once set. In Swift, you’re encouraged to use constant whenever possible by using the let keyword to declare your local and class properties. But we’re not talking about those kind of constants here, we’re talking about global constants.

Global constants help to make your code more readable and maintainable by avoiding repetition of hard-coded strings or magic numbers throughout your codebase. In this project, you’ll define some global constants for things like sprite image names, sound files, the z-order or zPosition of your sprites and the category defined for each sprite (which is important for collision detection).

Open Constants.swift and add the following code below the //MARK: constants line:

let BackgroundImage = "Background"
let GroundImage = "Ground"
let WaterImage = "Water"
let RopeTextureImage = "RopeTexture"
let RopeHolderImage = "RopeHolder"
let CrocMouthClosedImage = "CrocMouthClosed"
let CrocMouthOpenImage = "CrocMouthOpen"
let CrocMaskImage = "CrocMask"
let PrizeImage = "Pineapple"
let PrizeMaskImage = "PineappleMask"
 
let BackgroundMusicSound = "CheeZeeJungle.caf"
let SliceSound = "Slice.caf"
let SplashSound = "Splash.caf"
let NomNomSound = "NomNom.caf"
 
let RopeDataFile = "RopeData.plist"

The code above declares a group of String constants using the let keyword to indicate that their values cannot be changed later. Because these constants are declared outside of any class, they are globally available anywhere in the program.

Beneath those, add the following:

struct Layer {
  static let Background: CGFloat = 0
  static let Crocodile: CGFloat = 1
  static let Rope: CGFloat = 1
  static let Prize: CGFloat = 2
  static let Foreground: CGFloat = 3
}
 
struct Category {
  static let Crocodile: UInt32 = 1
  static let RopeHolder: UInt32 = 2
  static let Rope: UInt32 = 4
  static let Prize: UInt32 = 8
}

This code declares two structs, Layer and Category, each containing a bunch of static CGFloat and UInt32 properties respectively. You’ll use these to specify the zPosition and collision category of a sprite when you add it to the scene (more about this later).

Note: The Objective-C versions of this tutorial used C enums for the sprite layer and category constants, and that made a lot of sense because in C, enums are just a neat way of declaring a bunch of numeric values. But Swift enums are quite a different beast: In Swift, enum values are unique types in their own right, and to use them as a number requires them to be converted using toRaw(), which makes them unwieldy to use for the purpose intended here. Structs containing static properties are a better way to create groups of numeric constants in Swift

Finally, under //MARK: game configuration, add the following:

let PrizeIsDynamicsOnStart = true
let CanCutMultipleRopesAtOnce = false

In addition to avoiding “magic” values, constants also allow you to easily make certain parts of the game configurable. It’s not always obvious which gameplay decisions will make a game more fun, but it’s usually too late to go back and recode everything later if you realize you made the wrong call. Constants give you a simple way to flip a switch to swap between different approaches and see which works best in practice.

This last pair of constants will be used to tweak the gameplay later.

Note: In Objective-C, it’s common practice to use compiler macros to selectively compile code. This is a good way to make functionality configurable at compile time without imposing any performance overhead. Swift doesn’t support macros yet though (and may never), so you’ll have to use ordinary if statements to enable and disable code at runtime.

Now that you’ve got your constants in place, you can begin adding nodes to your scene, starting with the background and foreground scenery.

Setting the Scene

The starter project provides stub versions of the GameScene and RopeNode classes. You’ll be fleshing out those stubbed methods with the code to get the game up and running. The first step is to initialize the SKScene and add the background and foreground scenery.

Open GameScene.swift and add the following to setUpScenery():

let background = SKSpriteNode(imageNamed: BackgroundImage)
background.anchorPoint = CGPointMake(0, 1)
background.position = CGPointMake(0, size.height)
background.zPosition = Layer.Background
background.size = CGSize(width: self.view!.bounds.size.width, height:self.view!.bounds.size.height)
addChild(background)
 
let water = SKSpriteNode(imageNamed: WaterImage)
water.anchorPoint = CGPointMake(0, 0)
water.position = CGPointMake(0, size.height - background.size.height)
water.zPosition = Layer.Foreground
water.size = CGSize(width: self.view!.bounds.size.width, height: self.view!.bounds.size.height * 0.2139)
 
addChild(water)

The setUpScenery() method is called from didMoveToView(). In this method, you create a couple of SKSpriteNodes and initialize them using SKSpriteNode(imageNamed:). Because you now have to deal with multiple screen sizes for @2x resolutions (iPhone 5/5s and iPhone 6), the size of these background images needs to be made explicit (not inferred) and made relative to the window screen. There will be a little bit of scaling because of this, but this is OK for a background image.

You’ve changed the anchorPoint of the background from the default value of (0.5, 0.5) to (0, 1). This means that it is positioned relative to the top-left corner of the sprite image, instead of its center, which is a bit easier to work with when positioning relative to the scene’s coordinate space. For the water, you’ve set the anchorPoint to (0, 0), which makes it easier to align with the bottom of the background image.

The anchorPoint property uses the unit coordinate system, where (0,0) represents the bottom-left corner of the sprite image, and (1,1) represents the top-right corner. Because it’s always measured from 0 to 1, these coordinates are independent of the image dimensions or aspect ratio.

Note: For more information about the unit coordinate system, review Working with Sprites in Apple’s Sprite Kit Programming Guide.

You also set the sprites’ positions within the scene and zPositions, which controls the layer order.

Recall that in Constants.swift, you specified some values for use with the sprite’s zPosition. You use two of them in the code above: Layer.Background and Layer.Foreground. SKSpriteNode inherits the zPosition property from SKNode. These values ensure that the background will always be drawn behind all the other sprites in the scene, and the foreground will always be drawn in front, regardless of the order in which you add the sprites.

Build and run your project. If you did everything right, you should see the following screen:

Screen1

It’s a lonely jungle out there. Time to bring out the croc!

In a While, Crocodile

Just like the background scenery, the crocodile is represented by an SKSpriteNode. There are a couple of important differences though: Firstly, you’ll need to retain a reference to the crocodile so you can refer back to it later in your game logic, and secondly, you’ll need to set up a physics body for the crocodile sprite in order to detect and handle collisions.

Still in GameScene.swift, add the following properties to the top of the class:

private var crocodile: SKSpriteNode!
private var prize: SKSpriteNode!

These properties will store references to the main actors in the scene: the crocodile and the prize (pineapple). You’ve defined them as private, because they won’t be accessed outside of the scene itself, and it’s always good practice to keep your class data private unless there’s a good reason why it needs to be directly visible to other classes.

The type for these properties has been defined as SKSpriteNode!. The “!” means that these are implicitly unwrapped optionals, which tells Swift that they don’t need to be initialized right away, but that we confident that they won’t be nil when we try to access them (and we better be confident – the app will crash if we get it wrong!).

Note: Since these values won’t change after they are initialized, ideally we’d want these to be defined as constants using the let keyword, but due to the design of the SKScene class, we won’t be setting these values until the didMoveToView(view:) method is called (after the scene has been initialized), which isn’t permitted for constants.

Locate the setUpCrocodile() method inside of GameScene.swift and add the following block of code:

crocodile = SKSpriteNode(imageNamed: CrocMouthClosedImage)
crocodile.position = CGPointMake(size.width * 0.75, size.height * 0.312)
crocodile.zPosition = Layer.Crocodile
 
crocodile.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: CrocMaskImage), size: crocodile.size)
crocodile.physicsBody?.categoryBitMask = Category.Crocodile
crocodile.physicsBody?.collisionBitMask = 0
crocodile.physicsBody?.contactTestBitMask = Category.Prize
crocodile.physicsBody?.dynamic = false
 
addChild(crocodile)
 
animateCrocodile()

This code uses two of the constants you set up earlier: CrocMouthClosedImage and Layer.Crocodile. It also sets the position of the crocodile node relative to the scene bounds.

Just as before, you set the zPosition to place the crocodile node on top of the background. By default, Sprite Kit will layer nodes based on the order in which they’re added to their parent, but you can control the ordering yourself by providing a different zPosition.

Unlike the background scenery, the croc has an SKPhysicsBody, which means it can interact physically with other objects in the world. This will be useful later for detecting when the pineapple lands in its mouth. You don’t want the croc to get knocked over, or fall off the bottom of the screen though, so you’ve set dynamic = false which prevents it from being affected by physical forces.

The categoryBitMask, collisionBitMask and contactTestBitMask values will be used later for detecting collisions. The category bitmask defines a collision group for the sprite, and the contact bitmask defines which other groups this sprite can collide with. The collision bitmask is used for modelling realistic collisions (where objects bounce off of one another), but we don’t actually want to do that for the crocodile, so we disable it by setting the value to zero.

You may have noticed that the the physics body for the crocodile is being initialized using an SKTexture object. Prior to iOS 8, to specify a collision region for a non-rectangular sprite, you would have needed to use a CGPath to approximate the shape of your sprite image. This was a fiddly, manual process. In iOS 8, Sprite Kit added the option to specify the collision shape using a texture image. Sprite Kit automatically uses this image to generate a collision detection polygon that closely matches the desired shape.

You could simply re-use CrocMouthOpenImage for the collision texture, but in this case, by using a separate mask image you can finely tune the collidable area to improve the gameplay. The CrocMaskImage texture just includes the crocodile’s head and mouth, because a croc can’t eat a pineapple with its tail!

Note: A neat trick when debugging your game is to temporarily set your sprites to use the physics body collision texture as the sprite texture. This will let you see immediately if collisions aren’t working correctly (which might happen if you’ve changed the anchor point to something other than (0.5, 0.5), so that the sprite image is no longer aligned with the physics body).

Now it’s time to animate the crocodile. Find the animateCrocodile() method and add the following code:

let frames = [
  SKTexture(imageNamed: CrocMouthClosedImage),
  SKTexture(imageNamed: CrocMouthOpenImage),
]
 
let duration = 2.0 + drand48() * 2.0
 
let move = SKAction.animateWithTextures(frames, timePerFrame:0.25)
let wait = SKAction.waitForDuration(duration)
let rest = SKAction.setTexture(frames[0])
let sequence = SKAction.sequence([wait, move, wait, rest])
 
crocodile.runAction(SKAction.repeatActionForever(sequence))

This code creates an array of SKTexture frames which you then animate using SKActions. In this case the array only contains two frames, but you could easily extend this principle for more complex animations.

The SKAction.sequence() constructor creates a sequence of actions from an array. In this case, the texture animation is combined in sequence with a randomly-chosen delay period between 2 and 4 seconds.

The sequence action is wrapped in a repeatActionForever() action, so that it will repeat indefinitely for the duration of the level. It is then run on the crocodile node using the node’s runAction(action:) method.

That’s it! Prepare yourself to see a hungry-looking crocodile hopefully opening and closing its jaws.

Build and run the project to see this fierce reptile in action!

Screen2

That’s pretty scary, right? As the player, it’s your job to keep this guy happy with pineapples, which (as everyone knows) are a crocodile’s favorite food!

You’ve got scenery and you’ve got a croc, now we need a pineapple.

Eyes on the Prize

Open up the GameScene.swift file again, and locate the setUpPrize() method. Add the following:

prize = SKSpriteNode(imageNamed: PrizeImage)
prize.position = CGPointMake(size.width * 0.5, size.height * 0.7)
prize.zPosition = Layer.Prize
 
prize.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: PrizeImage), size: prize.size)
prize.physicsBody?.categoryBitMask = Category.Prize
prize.physicsBody?.collisionBitMask = 0
prize.physicsBody?.contactTestBitMask = Category.Rope
prize.physicsBody?.dynamic = PrizeIsDynamicsOnStart
 
addChild(prize)

Like the crocodile, the pineapple sprite uses a physics body. But unlike the crocodile, we want the pineapple to fall and bounce around realistically. Instead of merely setting dynamic = true though (which would be redundant anyway, since that’s the default), it’s set to the constant PrizeIsDynamicsOnStart that you set earlier. What’s that all about?

Don’t worry! All will be revealed later!

Let’s Get Physical

Sprite Kit makes use of iOS’ built-in physics engine (which, our spies tell us, is really the popular open-source Box 2D physics engine running behind the scenes). If you’re familiar with Cocos-2D, you may already have used Box 2D for implementing 2D game physics. The big difference when using Box 2D physics in Sprite Kit is that Apple has fully encapsulated the library in a Cocoa wrapper, so you won’t need to use C++ to interact with it.

To get started, locate the setUpPhysics() method inside of GameScene.swift and add the following three lines:

physicsWorld.contactDelegate = self
physicsWorld.gravity = CGVectorMake(0.0,-9.8)
physicsWorld.speed = 1.0

This sets up the physics world’s contact delegate, gravity and speed. The gravity and speed values actually match the defaults for their respective properties. The former specifies the gravitational acceleration applied to physics bodies in the world, while the latter specifies the speed at which the simulation executes.

Since they’re the default values, you don’t really need to specify them here, but it’s good to know they exist in case you want to tweak your physics. Both of these properties can be found in the SKPhysicsWorld Class Reference.

You’ll see a compiler error on the first line because you’ve specified self as the the physics delegate, but GameScene doesn’t conform to the SKPhysicsContactDelegate protocol. Fix that by adding that protocol to the class definition, like this:

class GameScene: SKScene, SKPhysicsContactDelegate {

Build and run the app again. You should see the pineapple sail past the crocodile and fall into the water (behind the water, technically). That’s progress, but clearly not what we’re aiming for. You need to find a way to suspend the pineapple from the trees. It’s time to add the ropes.

Learn the Ropes

Adding a rope is not quite as straightforward as an ordinary sprite. The physics bodies used in Sprite Kit are designed to model rigid objects, but ropes are not rigid, they bend!

For this reason, you’ll implement each rope as an array of segments with flexible joints. In reality, they are more like chains than ropes, but it’s our game and we’ll call them what we like!

Positioning the rope segments manually would be extremely tedious and repetitive, and since performing repetitive tasks is what you learned to program computers for (!) you’re going to get the computer to do that work for you instead.

Each rope has three significant attributes:

  • anchorPoint – a CGPoint indicating where the end of the rope connects to the tree
  • length – an Int representing the number of segments in the rope
  • name – a String used to identify which rope a given segment belong to (more on this later)

In this tutorial, the game has only one level. But in a real game you would want to be able to easily create new level layouts without writing a lot of code. A good way to do this is to specify your level data independently of your game logic, by storing it in a data file, perhaps using a property list or JSON.

For this reason it is convenient if the data can be modelled and manipulated independently of the the actual sprite nodes that make up the ropes on screen. Does that idea sound familiar at all? Right! It’s the MVC pattern!

Sprite Kit, like UIKit, follows the MVC pattern when it comes to creating game interfaces. The SKScene is your controller and the SKNodes are views. What you need now is a model to represent the rope data.

Since we’ll be loading our rope data from a file, the natural structure for representing the rope data is an NSArray of NSDictionary objects, which can be easily read from a property list using the NSArray(contentsOfFile:) initializer.

It’s not generally good practice to store complex data in your app as plain old arrays or dictionaries, but since this data will only exist briefly while you are setting up the rope sprites, it’s not really worth creating a bespoke class or struct to store it.

In GameScene.swift, locate setUpRopes() and add the following block of code:

// load rope data
let dataFile = NSBundle.mainBundle().pathForResource(RopeDataFile, ofType: nil)
let ropes = NSArray(contentsOfFile: dataFile!)
 
// add ropes
for i in 0..<ropes.count {
 
  // create rope
  let ropeData = ropes[i] as NSDictionary
  let length = Int(ropeData["length"] as NSNumber) * Int(UIScreen.mainScreen().scale)
  let relAnchorPoint = CGPointFromString(ropeData["relAnchorPoint"] as String)
  let anchorPoint = CGPoint(x: relAnchorPoint.x * self.view!.bounds.size.width,
                            y: relAnchorPoint.y * self.view!.bounds.size.height))
  let rope = RopeNode(length: length, anchorPoint: anchorPoint, name: "\(i)")
 
  // add to scene
  rope.addToScene(self)
 
  // connect the other end of the rope to the prize
  rope.attachToPrize(prize)
}

First, the code above loads the rope data from a property list. Take a look at the RopeData.plist file (inside Resources/Data, and you should see that the file contains an array of dictionaries, each containing a relAnchorPoint and length (expand the nodes in the property list editor to see the sub-structure):

RopeData

The for loop iterates over the indexes in the array. The reason for iterating over the indexes instead of just the array objects is that we need the index value in order to generate a unique name string for each rope. This will be important later.

For each rope dictionary, the relAnchorPoint and length are retrieved and used to initialize a new RopeNode object. Length is specified in the plist measured in @1x, so you need to multiply by the actual screen scale. You do this because a “fixed” length would either be too loose (for lower resolutions) or too tight (for higher resolutions such as the 6 Plus). Similarly, relAnchorPoint is converted to a position on the screen relative the the screen’s bounds. This is to ensure that our points fall nicely on the trees for all device sizes. Finally, you attach the RopeNode to the scene with addToScene(), and then attach to the prize using attachToPrize().

If you try to run this code, nothing new will happen because the RopeNode class is just a stub. Let’s go and fix that now.

In a Class of its Own

Open RopeNode.swift. RopeNode is a custom class that inherits from SKNode. It doesn’t have any visual appearance of its own (which is why it doesn’t inherit from SKSpriteNode), but instead acts as container for a collection of SKSpriteNodes representing the rope segments.

Add the following properties to the class definition:

private let length: Int
private let anchorPoint: CGPoint
private var ropeSegments: [SKNode] = []

You’ll see some errors appearing because the length and anchorPoint properties haven’t been initialized. You’ve declared them as non-optional, but not assigned a value. Fix this by replacing the implementation of the init(length:anchorPoint:name:) method with the following:

self.length = length
self.anchorPoint = anchorPoint
 
super.init()
 
self.name = name

Pretty straightforward, but for some reason there are still errors. There is a second initializer method, init(coder:) – you aren’t calling that anywhere, so what is it for?

Because SKNode implements the NSCoding protocol, it inherits the required init(coder:) method, and that means you have to initialize your non-optional properties there as well, because even though you aren’t using it, Swift won’t allow any possibility of a class being incorrectly initialized.

So you’d better update the init(coder:) method too:

length = aDecoder.decodeIntegerForKey("length")
anchorPoint = aDecoder.decodeCGPointForKey("anchorPoint")
 
super.init(coder: aDecoder)

And while you’re at it, may as well add the encodeWithCoder() method as well, because it’s poor form to leave a job half finished!

override func encodeWithCoder(aCoder: NSCoder) {
 
  aCoder.encodeInteger(length, forKey: "length")
  aCoder.encodeCGPoint(anchorPoint, forKey: "anchorPoint")
 
  super.encodeWithCoder(aCoder)
}

You won’t be using NSCoding to serialize the scene in this tutorial, but if you want to add the ability to save and load the game in future, these methods might well prove useful.

Next, you need to implement the addToScene() method. This is where the real magic happens! This is a complex method, so you’ll write it in stages. First, find addToScene() and add the following:

// add rope to scene
zPosition = Layer.Rope
scene.addChild(self)

This adds the rope to the scene, and sets its z-offset, but not much else. Next, add this block of code to the method:

// create rope holder
let ropeHolder = SKSpriteNode(imageNamed: RopeHolderImage)
ropeHolder.position = anchorPoint
ropeHolder.zPosition = Layer.Rope
 
ropeSegments.append(ropeHolder)
addChild(ropeHolder)
 
ropeHolder.physicsBody = SKPhysicsBody(circleOfRadius: ropeHolder.size.width / 2)
ropeHolder.physicsBody?.dynamic = false
ropeHolder.physicsBody?.categoryBitMask = Category.RopeHolder
ropeHolder.physicsBody?.collisionBitMask = 0
ropeHolder.physicsBody?.contactTestBitMask = Category.Prize

This creates the rope holder, which is basically a nail for the rope to hang from. Like the crocodile, this is a static body (as specified by the dynamic = false) which means that it won’t be affected by gravity, and won’t get moved around by the forces applied by the other nodes.

The rope holder is circular, so although you could define its collision shape using an image texture, it’s a bit more efficient just to use the SKPhysicsBody(circleOfRadius:) constructor instead. The position of the rope holder matches the anchorPoint that you specified when creating the RopeModel.

Next, you’ll create the rope itself. Add the following code:

// add each of the rope parts
for i in 0..<length {
 
  let ropeSegment = SKSpriteNode(imageNamed: RopeTextureImage)
  let offset = ropeSegment.size.height * CGFloat(i + 1)
  ropeSegment.position = CGPointMake(anchorPoint.x, anchorPoint.y - offset)
  ropeSegment.name = name
 
  ropeSegments.append(ropeSegment)
  addChild(ropeSegment)
 
  ropeSegment.physicsBody = SKPhysicsBody(rectangleOfSize: ropeSegment.size)
  ropeSegment.physicsBody?.categoryBitMask = Category.Rope
  ropeSegment.physicsBody?.collisionBitMask = Category.RopeHolder
  ropeSegment.physicsBody?.contactTestBitMask = Category.Prize
}

This loop creates an array of rope segments, equal in number to the length you specified when creating the RopeModel. Each segment is a sprite, with its own physics body. The segments are rectangular, so, as with the rope holder, you can make Sprite Kit work a little less hard by using SKPhysicsBody(rectangleOfSize:) to specify the physics body shape, instead of using the rope texture image.

Unlike the rope holder, the rope nodes are dynamic, so they can move around and are affected by gravity.

Try building and running the app now.

Uh oh! That probably wasn’t quite what we were expecting – the rope segments all fell off the screen like finely chopped spaghetti. The problem is that you haven’t joined them together yet.

To fix that, you need to add this final chunk of code to addToScene():

// set up joints between rope parts
for i in 1...length {
 
  let nodeA = ropeSegments[i - 1]
  let nodeB = ropeSegments[i]
  let joint = SKPhysicsJointPin.jointWithBodyA(nodeA.physicsBody, bodyB: nodeB.physicsBody,
		anchor: CGPointMake(CGRectGetMidX(nodeA.frame), CGRectGetMinY(nodeA.frame)))
 
  scene.physicsWorld.addJoint(joint)
}

This code sets up physical joints between the segments, connecting them together. The type of joint you’ve used is an SKPhysicsJointPin, which inherits from the SKPhysicsJoint base class. A pin joint behaves as if you had hammered a pin through the two nodes, allowing them pivot, but not move closer or further apart from one another.

Note: Later, when you play the finished game, you’ll notice that there’s actually a bit of springiness to these joints, and the ropes behave more like strong elastic than a chain of solid links. The way that the physics are implemented in Sprite Kit allows for a bit of give in the calculations to prevent rounding errors from building up and causing everything to break, but this does lead to a slightly rubbery feel to things sometimes.

OK, so now if you build and run again, your ropes should hang realistically from the trees.

Screen3

The final step is to attach the ropes to the pineapple. You already added the call to call attachToPrize() – now you just need to write that method. Open up RopeNode.swift again, and scroll down to attachToPrize(). Add the following code:

// align last segment of rope with prize
let lastNode = ropeSegments.last!
lastNode.position = CGPointMake(prize.position.x, prize.position.y + prize.size.height * 0.1)
 
// set up connecting joint
let joint = SKPhysicsJointPin.jointWithBodyA(lastNode.physicsBody,
	bodyB: prize.physicsBody, anchor: lastNode.position)
 
prize.scene?.physicsWorld.addJoint(joint)

The code first gets the last segment of the rope and positions it slightly above the center of the prize. We want to attach it here so the prize hangs down realistically. If it was dead-center, the prize would be evenly weighted, and might spin on its axis.

Finally, the code creates another pin joint to attach the rope segment to the prize.

Because you’ve only moved the last segment of the rope into position, you might think it would create a gap between the last two segments. Not so, however. The beauty of having a realistic physics engine is that won’t allow the laws of physics to be violated – because the segments of the rope are all joined together, moving one now moves them all.

Build and run the project. If all your joints and nodes are set up properly, you should see a screen similar to the one below:

Screen4

It looks good. But the pineapple and ropes sure do bounce around a lot when the game first starts, right?

The problem is, you’re starting the pineapple off in an essentially arbitrary position, and letting the physics engine drop it into place. There’s a way to fix that so that the level doesn’t start quite so… energetically.

You may recall that when you created the pineapple sprite, you set its dynamic property to the constant PrizeIsDynamicsOnStart, which is currently set to true. The reason for that is that you weren’t sure where the pineapple would end up once the physics had resolved itself, so the position you placed the pineapple initially was just approximate.

But now that the joints are all in place, you can find out where the pineapple is destined to end up, and position it there to begin with. Run the app again, and once the pineapple has settled down and stopped bouncing, in Xcode, while the game is still running, find the update() stub function in GameScene.swift and add a breakpoint by clicking in the left-hand margin (see picture below):

Breakpoint

The game should break almost instantly at this line. Now, in the debug console, type po prize.position, and you should see the value logged out as something like (x=178.95286560058594, y=395.62783813476563).

Now locate setUpPrize() and find this line:

prize.position = CGPointMake(size.width * 0.5, size.height * 0.7)

Change it to match whatever values you saw in the console. For example:

prize.position = CGPointMake(178.95286560058594, 395.62783813476563)

You can remove your breakpoint now.

In Constants.swift, change the value of PrizeIsDynamicsOnStart to false, and run the game again.

This looks much better! The ropes still bounce around a bit, but the pineapple is already sitting in the right position instead of bouncing into place when the game begins.

Making the Cut

The game can’t be called Cut the Verlet if your Verlets, uh, ropes have no fear of being cut, right?

In this section, you’re going to learn how to work with the touch methods that will allow your player to cut those ropes.

If you’ve worked with a UIView before, you may have come across iOS’s touch handling methods. If not, they are well explained here.

Although SKScene does not inherit from UIView, it does inherit from UIResponder, which makes the same touch handling methods available. For now, you’ll only need touchesMoved.

Locate touchesMoved(_:withEvent:) and add the following code:

for touch in touches {
 
  let startPoint = touch.locationInNode(self)
  let endPoint = touch.previousLocationInNode(self)
 
  // check if rope cut
  scene?.physicsWorld.enumerateBodiesAlongRayStart(startPoint, end: endPoint, usingBlock: { (body, point, normal, stop) -> Void in
 
    self.checkIfRopeCutWithBody(body)
  })
 
  // produce some nice particles
  let emitter = SKEmitterNode(fileNamed: "Particle.sks")
  emitter.position = startPoint
  emitter.zPosition = Layer.Rope
  addChild(emitter)
}

This code works as follows: For each touch (we support multitouch slicing in this game) it gets the current and previous positions of the touch. Next, it loops through all of the bodes in the scene that lie between those two points, using the very handy enumerateBodiesAlongRayStart(_:end:usingBlock:) method of SKScene. For each body encountered it calls checkIfRopeCutWithBody(), which you’ll write in a minute.

Finally, the code creates an SKEmitterNode by loading it from the Particle.sks file, and adds it to the scene at the position of the user’s touch. This results in a nice green smoke trail wherever you drag your finger. This is pure eye-candy, but it does make the game look 100x better!

Particle emitters are not within the scope of this tutorial, but now that you know they exist… you’ve got something else to do later!

Scroll down to the checkIfRopeCutWithBody() method, and add this block of code to the method body:

let node = body.node!
 
// if it has a name it must be a rope node
if let name = node.name {
 
  //enable prize dynamics
  prize.physicsBody?.dynamic = true            
 
  // cut the rope
  node.removeFromParent()
 
  // fade out all nodes matching name
  self.enumerateChildNodesWithName(name, usingBlock: { (node, stop) in
 
  let fadeAway = SKAction.fadeOutWithDuration(0.25)
  let removeNode = SKAction.removeFromParent()
  let sequence = SKAction.sequence([fadeAway, removeNode])
 
  node.runAction(sequence)
  })
}

The code above first checks if the node connected to the physics body has a name. Remember that there are other nodes in the scene besides rope segments, and you certainly don’t want to accidentally slice up the crocodile or the pineapple with a careless swing! But you only named the rope node segments, so if the node has a name then we can be certain that it’s part of a rope.

Once you know that the node you’ve swiped is a rope, the first thing you do is to enable the dynamic property of the prize so that it can react properly after the rope is cut. (Depending on the value of the PrizeIsDynamicsOnStart constant, the prize may already be dynamic, but if not this will set it moving.)

Next, you remove the node from the scene. Removing a node also removes its physicsBody, and destroys any joints connected to it. The rope has now officially been cut!

Finally, you enumerate through all nodes in the scene whose name matches the name of the node that was swiped, using the scene’s enumerateChildNodesWithName(_:usingBlock:). The only nodes whose name should match are the other segments in the same rope, so you are basically just looping over the nodes in whichever rope was sliced.

For each node, you create an SKAction sequence that first fades out the node, then removes it from the scene. The effect is that immediately after being sliced, the rope will fade away gracefully. I think this looks a bit nicer than leaving the ends flapping, but if you disagree, you can remove this enumeration block to leave the severed ends on screen. You could even add another gameplay constant to make that option configurable!

Build and run the project. You should be able to swipe and cut all three ropes and see the prize fall. By the way, aren’t those particles awesome?!

Screen5

When Two Nodes Collide

You’re almost done! You’ve got a rope you can cut, but nothing happens once the pineapple falls. Even if it lands dead-center on the croc, it just falls through her, because the croc and prize’s collision masks are both set to zero.

If you changed the collision masks, the pineapple would bounce off, but that isn’t what you want either. You don’t want to realistically model the collision, you want to intercept it and handle it yourself. That’s where the SKPhysicsContactDelegate comes in.

You may recall that when you wrote the setUpPhysics() method, you specified that GameScene would act as the contactDelegate for the physicsWorld. You also added collision categories and bitmasks to the prize and croc so that the physics engine would be able to detect when they intersect each other. That was excellent foresight on your part!

Now all you need to do is implement didBeginContact() of the SKPhysicsContactDelegate, which will be triggered whenever an intersection is detected between two appropriately masked bodies. A stub for that method has been added for you – scroll down to find it, and add the following code:

if (contact.bodyA.node == crocodile && contact.bodyB.node == prize) ||
    (contact.bodyA.node == prize && contact.bodyB.node == crocodile) {
 
    // fade the pineapple away
    let shrink = SKAction.scaleTo(0, duration: 0.08)
    let removeNode = SKAction.removeFromParent()
    let sequence = SKAction.sequence([shrink, removeNode])
    prize.runAction(sequence)
}

This code checks if the two colliding bodies belong to the crocodile and prize respectively (you don’t know which order the nodes will be listed in, so you check for both combinations). If the test passes, you trigger a simple animation sequence that shrinks the prize down to nothing and then removes it from the scene.

Chew on This!

The pineapple vanishing when it lands on the croc may not be the most compelling way to inform the player that their pet has been fed. Users will expect to see the crocodile munch down that pineapple!

You can fulfil that expectation with another animation. Inside the if statement where you just triggered the pineapple shrink animation, add the following extra line:

runNomNomAnimationWithDelay(0.15)

Now locate runNomNomAnimationWithDelay() and add this code:

crocodile.removeAllActions()
 
let openMouth = SKAction.setTexture(SKTexture(imageNamed: CrocMouthOpenImage))
let wait = SKAction.waitForDuration(delay)
let closeMouth = SKAction.setTexture(SKTexture(imageNamed: CrocMouthClosedImage))
let sequence = SKAction.sequence([openMouth, wait, closeMouth])
 
crocodile.runAction(sequence)
 
animateCrocodile()

The code above removes any animation currently running on the crocodile node using removeAllActions(). It then creates a new animation sequence that opens and closes the crocodile’s mouth and runs this sequence on the crocodile. It then calls animateCrocodile() to resume the idle opening and closing of the crocodile’s jaws.

This new animation will be triggered when the prize lands in the croc’s mouth. The 0.15 second delay is so that it triggers slightly after the pineapple has disappeared, giving the impression that the crocodile is chewing it.

While you’re at it, add the following method just before the touchesMoved(_:withEvent:) method you filled in earlier:

override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
  runNomNomAnimationWithDelay(1)
}

This will trigger the same chewing animation every time the user cuts a rope. The animation gives the illusion that the crocodile is opening its mouth in hope something yummy will fall into it.

Build and run.

Second Serving

The happy croc will now chew up the pineapple if it lands in her mouth. But once that’s happened, the game just hangs there. The hungry croc won’t be satisfied by just one pineapple, so you need a way to reset the game so you can keep on feeding her!

In GameScene.swift, find switchToNewGameWithTransition(), and add the following block of code:

let delay = SKAction.waitForDuration(1)
let transition = SKAction.runBlock({
  let scene = GameScene(size: self.size)
  self.view?.presentScene(scene, transition: transition)
})
 
runAction(SKAction.sequence([delay, transition]))

The code above uses SKView’s presentScene(scene:, transition:) method to present the next scene.

In this case, the scene you are transitioning to is a new instance of the same GameScene class. You also pass in a transition effect using the SKTransition class. The transition is specified as an argument to the method so that you can use different transition effects depending on the outcome of the game.

Scroll back to didBeginContact(), and inside the if statement, after the prize fade and nomnom animations, add the following:

// transition to next level
switchToNewGameWithTransition(SKTransition.doorwayWithDuration(1.0))

This calls the switchToNewGameWithTransition() method we added earlier, using the SKTransition.doorwayWithDuration(duration:) constructor to create a doorway transition. This shows the next level with an effect like a door opening. Pretty neat, huh?

Screen6

That’s all well and good, but if the pineapple doesn’t land in the croc’s mouth, you’re still stuck. You need a way to detect that the prize has fallen into the water, and that all hope of the poor crocodile being fed is lost.

Heads: You Win, Tails: You Lose

You might be thinking that you need to add another physics body to the water so you can detect if the prize hits it, but that wouldn’t really help if the pineapple were to fly off the side of the screen. A simpler, better approach is just to detect when the pineapple has moved below the bottom of the screen edge, and then end the game.

SKScene provides an update() method that is called once every frame. Find that method, and add the following logic:

if prize.position.y <= 0 {
  let transitions = [
    SKTransition.doorsOpenHorizontalWithDuration(1.0),
    SKTransition.doorsOpenVerticalWithDuration(1.0),
    SKTransition.doorsCloseHorizontalWithDuration(1.0),
    SKTransition.doorsCloseVerticalWithDuration(1.0),
    SKTransition.flipHorizontalWithDuration(1.0),
    SKTransition.flipVerticalWithDuration(1.0),
    SKTransition.moveInWithDirection(.Left, duration:1.0),
    SKTransition.pushWithDirection(.Right, duration:1.0),
    SKTransition.revealWithDirection(.Down, duration:1.0),
    SKTransition.crossFadeWithDuration(1.0),
    SKTransition.fadeWithColor(UIColor.darkGrayColor(), duration:1.0),
    SKTransition.fadeWithDuration(1.0),
  ]
 
  // transition to next level
  let randomIndex = arc4random_uniform(UInt32(transitions.count))
  switchToNewGameWithTransition(transitions[Int(randomIndex)])
}

The if statement logic here is quite simple – it just checks if the prize’s y coordinate is less than zero (the bottom of the screen). If so, it calls switchToNewGameWithTransition() to start the level again.

Rather than always using the same transition effect, the code selects a random transition by using arc4random_uniform() to index into an array of all of the available transitions (except doorwayWithDuration, the transition we used for the success scenario), so you should see a different transition after each game-over.

Now build and run the project.

You should see the scene transition back to the starting conditions whenever the player scores a point or loses the prize.

The Sound of Music

While the game is technically complete, it lacks a certain pizazz. A silent game may quickly bore your users. It’s time to make it sing!

We’ve selected a nice jungle song from incompetech.com and some sound effects from freesound.org.

Sprite Kit will handle the sound effects for you, but to play the background music you’re going to use an AVAudioPlayer. The reason for this is that because this game will play music in the background, we want the music to continue playing seamlessly between level transitions, and an SKAction would be destroyed when the scene it’s running in gets replaced.

Note: AVAudioPlayer isn’t directly related to Sprite Kit, so this tutorial won’t cover it in detail. To learn more about AVAudioPlayer, check out our Audio Tutorial for iOS.

In a real game, with more complex audio requirements, you would probably create a singleton music manager class that could handled all of your music sequencing requirements. In this case however, you can get away with simply storing the AVAudioPlayer in a global variable, that way it will persist and continue playing even when you transition between different scene instances.

To create a global variable, you declare it outside of any class or struct. Add the following code inside GameScene.swift, immediately after the import statements, but before the GameScene class definition:

private var backgroundMusicPlayer: AVAudioPlayer!
Note: You may be thinking “Hang on a sec, aren’t global variables, like, really bad?!”, and yes, in general you’d be right. But if you look closely you’ll notice that the variable is marked as private, which restricts its scope to the file in which it was declared. Private global variables in Swift work like static variables in Objective-C implementation files. They persist for the duration of the app, but they don’t encourage the same sort of spaghetti code that can occur when using public or internal-scoped globals.

Locate the setUpAudio() method and add the following code:

if (backgroundMusicPlayer == nil) {
  let backgroundMusicURL = NSBundle.mainBundle().URLForResource(BackgroundMusicSound, withExtension: nil)
  backgroundMusicPlayer = AVAudioPlayer(contentsOfURL: backgroundMusicURL, error:nil)
  backgroundMusicPlayer.numberOfLoops = -1
}

The code above checks if the global backgroundMusicPlayer instance has been set yet. If not, it initializes a new AVAudioPlayer with the BackgroundMusicSound constant that you added to Constants.swift earlier (which is converted to an NSURL), and assigns it to the property. The numberOfLoops vale is set to -1, which indicates that the song should loop indefinitely.

You could simply recreate the player each time a scene is loaded instead of performing this nil check, but AVAudioPlayer retains itself while playing, so creating a new player each time the level loads without stopping the old one would result in a “wall of sound”, with many copies of the background music playing simultaneously.

Next, add this code:

if (!backgroundMusicPlayer.playing) {
  backgroundMusicPlayer.play()
}

This starts the background music playing when the scene is first loaded (it will then play indefinitely until the app exits or another method calls stop() on the player). You could just call play() without first checking if the player is playing, but this way the music won’t skip or restart if it is already playing when the level begins.

While you’re here, you may as well set up all the sound effects that you will be using later. Unlike the music, you don’t want to play the sound effects right away. Instead, you’ll create some reusable SKActions that can be used to play the sounds later.

Go back up to the top of the GameScene class definition, and add the following properties:

private var sliceSoundAction: SKAction!
private var splashSoundAction: SKAction!
private var nomNomSoundAction: SKAction!

Now go back to setUpAudio() and add the following lines:

sliceSoundAction = SKAction.playSoundFileNamed(SliceSound, waitForCompletion: false)
splashSoundAction = SKAction.playSoundFileNamed(SplashSound, waitForCompletion: false)
nomNomSoundAction = SKAction.playSoundFileNamed(NomNomSound, waitForCompletion: false)

This code initializes the sound actions using SKAction’s playSoundFileNamed(_:waitForCompletion:) method. Now it’s time to actually add the sound effects.

Scroll up to update() and add the following line of code inside the if statement, just above where the array of transitions are declared:

runAction(splashSoundAction)

That will play the sound of a splash when the pineapple lands in the water. Next, find didBeginContact(contact:) and add the following line of code just below the runNomNomAnimationWithDelay(0.08) line:

runAction(nomNomSoundAction)

That will play a chomping sound when the croc catches her prize. Finally, locate touchesBegan(_:withEvent:) and add the following line of code just below the runNomNomAnimationWithDelay(1) line:

runAction(sliceSoundAction)

That will play a swiping sounds whenever the player touches the screen.

Build and run the project.

The discerning player may notice a slight sound bug: If you miss the croc, the splashing sound plays multiple times. This is due to level complete logic being triggered repeatedly before the game transitions to the next scene. To correct this, add a new state property to the top of the class:

private var levelOver = false

Now modify update() and didBeginContact() by adding the following code at the top of each of them:

if levelOver {
  return
}

Finally, inside the if statements of both methods, add some code to set the levelOver state to true:

levelOver = true

Now, as soon as the game detects that the levelOver flag has been set (either because the pineapple hit the ground, or the croc got her meal), it will stop checking for the game win/lose scenarios, and won’t keep repeatedly trying to play those sound effects. Build and run. There are no awkward sound collisions anymore, and you’ll soon have one very stuffed crocodile!

FeedingTime

To The Max!

After playing a few rounds, the game seems a bit on the easy side. You’ll pretty quickly get to the point where you can feed the croc with a single well-timed slice through the three ropes. Suppose you want to make the game a bit harder – how might you do that?

The game is trickier if you slice a couple of ropes first and then have to time the last slice while the rope is swinging. It would be neat to re-engineer the game so that only one rope can be sliced at a time? Good thing you added that CanCutMultipleRopesAtOnce constant, right? ;-)

In GameScene.swift, add one last property at the top of the GameScene class definition:

private var ropeCut = false

Now locate the checkIfRopeCutWithBody(body:) method, and add the following if statement at the top of the method:

if ropeCut && !CanCutMultipleRopesAtOnce {
  return
}

At the bottom of the if let statement below, just before the closing bracket, add this line:

ropeCut = true

Finally, find touchesBegan(_:withEvent:), and add this to reset the ropeCut flag whenever the user tocuehs the screen:

ropeCut = false

Build and run the game again. You should see now that it is only possible to slice one rope each time you swipe. To cut another, you have to lift your finger and then swipe again.

I think the game is a bit more fun this way, but if you disagree, there’s no need to modify the code again, just flip the value of the CanCutMultipleRopesAtOnce configuration constant to true.

Where Do We Go From Here?

I hope you enjoyed working through this tutorial as much as I’ve enjoyed writing it. To compare notes, download the completed sample project here.

But, don’t let the fun stop here! Try adding new levels, different ropes, and maybe even a HUD with a score display and timer. Why not!? It’s only code!

If you’d like to learn more about Sprite Kit, be sure to check out our book, iOS Games by Tutorials.

If you have any questions or comments, feel free to join in the discussion below!

Create a Game Like Cut the Rope Using Sprite Kit and Swift is a post from: Ray Wenderlich

The post Create a Game Like Cut the Rope Using Sprite Kit and Swift appeared first on Ray Wenderlich.

Four Things I Learned Making My First Swift App

$
0
0
Unleash your inner poet!

Unleash your inner poet!

Note from Ray: At our company (Razeware), in addition to making written and video tutorials, we release our own apps too – we believe this helps make our material even better.

In this post, one of our newest full-timers will discuss the first app he developed at Razeware, with the goal of getting some practical experience for an upcoming video tutorial series on App Extensions. Enjoy!

My big app project over the summer was Instant Poetry 2, a Swift and iOS 8 complete rewrite of an app Ray wrote a long time ago when he was an indie iOS developer.

This was a huge learning experience for me – not only picking up the intricacies of Swift and iOS 8, but also thinking how best to teach this material in future books and tutorials.

So in the grand tradition of listicles, here are Four Things I Learned Making My First Swift App.

4) Swift Is In Flux

There were huge changes to the language over the summer. I started working on the app around beta 3, and each Xcode release brought syntax changes and Cocoa method signature tweaks.

Insert Rage Face Here!

If you plan to work on an app in Swift, you need to budget time to keep pace with the language.

I think it’s worth it though – it’s important to stay up to date with the latest and greatest, and a good learning experience. Apple has also been good about listening to feedback and bug reports about Swift, so you even have a chance to shape the future of the language.

3) Swift Exposes the Uglier Bits of Cocoa

Are you expecting a nice Swift array of SKProduct objects? No, Cocoa returns an implicitly unwrapped optional array of AnyObject.

Do you think you can pass a nice Swift array of type [NSObject: AnyObject] to that method? No, Cocoa really wants an NSDictionary or things will silently fail.

You can just feel the tension between what Swift wants to do vs the tradeoffs it has to make to fit Cocoa. Looking at Cocoa though a Swift lens isn’t always pretty!

obj-c-swift-cats

The bad news is we’re in a transition. Part of what Apple does in each release is clean up the Swift-Cocoa interface.

The good news is that Apple is very good at transitions. Think about the transitions from PowerPC to Intel, Classic Mac OS to OS X, etc. Some day in the future, Cocoa will “just work” and natively fit in with Swift.

2) Swift Plays Nicely with Objective-C

Really, this is a corollary to the previous points – the reason you notice some Swift oddities is because Swift needs to work with the Objective-C runtime and Objective-C APIs.

obj-c-and-swift-sunset

On the practical side, using Objective-C third-party libraries and extensions (like Facebook Pop) in my Swift app was simple. I simply imported the headers in my bridging header, and it just worked.

If you have a favorite library that’s written in Objective-C or an existing app where you want to try adding in one or two Swift classes, you shouldn’t have any issues.

1) Swift is Enormously Fun

I’ve been enjoying my time with Swift.

The language is expressive. Things like optional chaining and nil coalescing make for shorter code. I’m most surprised at how much I enjoy enums – they really are a win-win that make your code more readable with the added benefit of type checking and exhaustive case checking.

happyrage

As a fan of both Objective-C and Ruby, I feel like Swift is a great mix of those two languages. If you know Objective-C and Cocoa, you’ll have no problem reading Swift code; if you haven’t already, start a simple app in Swift and give it a try!

Bonus Item: Extensions Will Change the World!

Well, the Apple world at least. In iOS 8, Apple introduced app extensions, which allows developers to extend their apps into custom sharing options, notifications, keyboards, and photos.

In Instant Poetry 2, I used a Photo Extension to allow users to add poetry to their images, right within the Photo app. This wouldn’t have been possible before iOS 8!

iOS 8 Photo Extension

It’s great that apps are no longer limited to their own sandbox. It looks like this new open Apple is moving toward apps being able to do more things, from more places.

Even if the upcoming Apple Watch is just an extension of the iPhone’s screen, I can’t wait to see what we’ll be able to do with Watch Kit.

Maybe my next Swift app will be something for the Apple Watch! :]

Where to Go From Here?

I expect the rough edges of Swift will be sanded down in the short term. Before you know it, there will be Swift apps everywhere and Swift projects will outnumber Objective-C ones when you browse GitHub.

But in the here and now of trying to ship apps, it can be a real challenge. I expect that moving a project from Swift 1.0 to Swift 2.0 will be a good amount of work, although not as much as moving from Objective-C to Swift.

But that’s why we love technology, isn’t it? Learning, staying up to date, and working on the latest and greatest in languages and APIs is what keeps me excited.

swift-poem

If you want to check out Instant Poetry 2, you can download it for free on the App Store! I’d love to hear any comments or suggestions you have.

Have you shipped your first Swift app yet? If so, I’d love to hear your experience too. Please join the forum discussion below!

Four Things I Learned Making My First Swift App is a post from: Ray Wenderlich

The post Four Things I Learned Making My First Swift App appeared first on Ray Wenderlich.

Video Tutorial: iOS Animation with Swift Part 12: Custom Transitions

iOS 8 Feast Giveaway Winners!

$
0
0

iOS-8-Feast-Thumb

This past month has been absolutely crazy.

Every Monday-Friday, we released at least one new tutorial, and every Wednesday we released a new Swift book.

In total, we had over 40 posts and 5 books released in just 1 month! This is our biggest month ever on the site, and I’m really proud of the entire team for putting this together.

But all good things must come to an end. And in the case of the iOS 8 Feast, we like to end things with a bang.

So today, we are pleased to announce the winners of our iOS 8 Feast giveaway! We have over $12,000 in value of prizes to give away – one grand prize winner, and 100 second prize winners.

Keep reading to find out who the lucky winners are, how to claim your prize if you are a lucky winner, and how to get a second chance in case you aren’t! :]

Full Prize List

Here’s the full list of prizes. The grand prize winner gets them all (is your mouth watering yet?):

iOS8_Feast_Giveaway_2

Coding Tools

  1. AppCode 3 Personal License ($99 value): An intelligent IDE that helps iOS/OSX developers create outstanding apps with ease and pleasure. Now with basic Swift support!
  2. Tower Git ($60 value): The most powerful Git client for your Mac.
  3. Spark Inspector ($50 value): Monitor, understand, and experiment with your app structure at a glance with Spark Inspector. You have to see it to believe it!
  4. Base 2 ($30 value): A Mac OS X application for creating, designing, editing, and browsing SQLite 3 database files.
  5. Paw 2 ($20 value): A handy app to test HTTP calls and RESTful APIs. It lets you send HTTP requests (like cURL), and generates NSURLConnection or AFNetworking code.
  6. Dash ($20 value): Instant offline access to documentation sets, and extremely handy snippet manager.
  7. Charles ($50 value): A HTTP proxy that enables a developer to view all of the HTTP traffic between their machine and the internet.

Mockup Tools

  1. Briefs ($199 value): The essential app design and mockup tool for a professional design workflow, for Mac OS X.
  2. AppCooker ($20 value): Design apps like a chef – right on your iPad!

Design Tools

  1. Paint Code 2 ($100 value): PaintCode is a vector drawing app that generates code in real time. Now fully up-to-date with Swift!
  2. IconBeast ($75 value): A set of elegant 3,000 iOS tab bar and toolbar icons for iPhone and iPad!
  3. xScope 4 ($50 value): Ten tools in one that will help any designer or developer do their job faster and produce more accurate results. Ideal for measuring, aligning, and inspecting on-screen graphics and layouts.
  4. Pixelmator ($30 value): An inspiring, easy-to-use, beautifully designed image editor built to help you create stunning new images and edit your existing photos.
  5. iOS Hat ($20 value): Turn Photoshop layers into Objective-C or Swift!
  6. CrazyTalk Animator 2 Pipeline ($300 value): CrazyTalk Animator is built from the ground up as a revolutionary 2D animation software to generate character animations for your games or apps.

Game Tools

  1. Spine Essential ($75 value): Spine is dedicated to 2D animation, providing an efficient workflow both for creating amazing animation and for integrating it into your games.
  2. Particle Designer 2.0 Indie License ($75 value): Create amazing particle systems for your games with a visual editor. Now 100% redesigned!
  3. Glyph Designer ($40 value): Design beautiful fonts for your iOS games.
  4. Texture Packer ($39 value): The sprite sheet creator that turns chaos into order!
  5. PhysicsEditor ($19 value): Edit your physics shapes with ease!

Productivity Tools

  1. 1Password for Mac ($50 value): The most popular password manager for the Mac!
  2. Reflector ($13 value): An AirPlay receiver that allows you to wirelessly display your iPad or iPhone on your Mac. Great for making app videos!
  3. Soulver ($12 value): A handy app to help you play around with numbers, more conveniently than a traditional calculator.

iOS Controls

  1. ShinobiCharts Standard ($395 value): Bring your app’s data to life with these professional chart components.
  2. ShinobiGrids Standard ($395 value): Powerful data grids you can add into your iOS apps.
  3. ShinobiEssentials ($195 value): A kit of popular UI controls you can add to your apps like carousels, overlay panels, progress indicators, and more.

Conference Tickets

  1. RWDevCon ($599 value): A free ticket to our official raywenderlich.com conference: RWDevCon! Meet up with the team, learn, and be inspired!
  2. 360iDev ($800 value): A free ticket to 360iDev in 2014 – also includes the pre-conference workshop!
  3. CocoaConf ($800 value): A free ticket to any CocoaConf event in 2013 or 2014 – plus the pre-conference workshop!

PDF Books and Starter Kits

  1. Swift by Tutorials ($54 value): Learn Apple’s brand new programming language, Swift, the quick and easy way: via hands-on tutorials!
  2. iOS 8 by Tutorials ($54 value): Learn about the new APIs in iOS 8 such as Adaptive UI, App Extensions, and Cloud Kit!
  3. Core Data by Tutorials ($54 value): Take control of your data in iOS apps using Core Data, Apple’s powerful object graph and persistence framework.
  4. The iOS Apprentice, 3rd Edition ($54 value): Learn how to make iPhone and iPad apps from the ground up, with a series of epic-length tutorials for beginners!
  5. iOS Games by Tutorials, 2nd Edition ($54 value): Learn how to make 2D games for the iPhone and iPad using Apple’s brand new game framework, Sprite Kit.
  6. iOS 7 by Tutorials ($44 value): Learn about the new APIs that were introduced in iOS 7 like Text Kit, UIKit Dynamics, and NSURLSession. Still relevant in iOS 8
  7. iOS 6 by Tutorials ($24 value): Learn about the new APIs that were introduced in iOS 6 like Auto Layout, Collection Views, and Passbook. Still relevant in iOS 8!
  8. Space Game Starter Kit ($129 value): Learn how to make a full side-scrolling space game with Sprite Kit!
  9. Platformer Game Starter Kit ($129 value): Learn how to make a Mario-like platformer game with Sprite Kit!
  10. Beat ‘Em Up Game Starter Kit ($129 value): Learn how to make a pixel art beat ‘em up game with Sprite Kit!

Video Tutorials

  1. 1-year raywenderlich.com Subscription (Beta) ($180 value): Get full access to our complete catalog of video tutorials – plus get access to a new video tutorial each week!

Print Books

  1. Advance Print Copy of Swift by Tutorials ($54 value): Right now we only sell the PDF version of Swift by Tutorials, but later this year we’ll be making a print version. We’ll send the grand prize winner the first copy of the book printed!
  2. Advance Print Copy of iOS 8 by Tutorials ($54 value): Similarly, be the first to get the print version of iOS 8 by Tutorials when it’s ready!
  3. Advance Print Copy of Core Data by Tutorials ($54 value): Similarly, be the first to get the print version of Core Data by Tutorials when it’s ready!
  4. Advance Print Copy of The iOS Apprentice, 3rd Edition ($54 value): Similarly, be the first to get the print version of the iOS Apprentice, 3rd Edition when it’s ready!
  5. Advance Print Copy of iOS Games by Tutorials, Second Edition ($54 value): Similarly, be the first to get the print version of iOS Games by Tutorials, 2nd Edition when it’s ready!

Bonus Loot

  1. raywenderlich.com T-shirt ($25 value): Sport a stylish black t-shirt with a colorful mosaic iPhone design!
  2. Plus… cold hard cash for a new iPhone 6! ($199 value)

Once again, a huge thanks to everyone who donated prizes for the iOS 8 Feast! These are all amazing resources for developers that we hand-picked and highly recommend.

And the 1 grand prize winner who will get this huge prize pack of over $6,000 in value is… wait for it…

Epic Grin

Josh Woods(@sdoowhsoj on Twitter)!

Huge congrats to Josh! I will be in touch soon to arrange delivery of your prizes.

If you didn’t win the grand prize don’t worry – we have 100 more second prize winners to announce! :]

Second Prize Winners

Again, anyone who sent a tweet in the past month with the #ios8feast hash tag was eligible to win a second prize – and here are the lucky 100 random winners! :]

  1. @_antoniotrejo
  2. @3holepunch
  3. @3ogdan
  4. @aaronschubert0
  5. @AeroGears
  6. @ajayshroff
  7. @alessandrodn
  8. @AlexHedley
  9. @anthonyblakedev
  10. @aprato
  11. @ashish_as10
  12. @benplantinga
  13. @bfras
  14. @BhagatBhavik
  15. @blacktc1995
  16. @blundin
  17. @boilingpointdev
  18. @brettbrooks
  19. @BrianDinsen
  20. @buttmanizer
  21. @captainfleppo
  22. @carguezu
  23. @chakradharg13
  24. @codingexplorer
  25. @colinnapier
  26. @corvinalex
  27. @createdbysteph
  28. @davidfsmith
  29. @dcsimps
  30. @decatilinae
  31. @dev_jac
  32. @duffman0987
  33. @EdgarYOR
  34. @eezwanlee
  35. @EmmanuelHayes
  36. @emsdnb
  37. @faustoibarra
  38. @firedave1
  39. @GamingMuchroom
  40. @gaylejj
  41. @globdesign
  42. @gopanx
  43. @hanvota
  44. @haxpor
  45. @hcciou
  46. @helen_mx
  47. @idek_bird
  48. @ignazio_c
  49. @Ilias_Stiv
  50. @iosengineer
  51. @james_washer
  52. @jamiedaniel
  53. @jerometonnelier
  54. @jonathanchacon
  55. @joyceechessa
  56. @jpsasi
  57. @jtoeman
  58. @juarezjaramillo
  59. @KitFoxboy
  60. @krishan711
  61. @LincolnBase
  62. @lonejedi70
  63. @lorienmcs
  64. @ltsimps
  65. @luisfcofv
  66. @martinni39
  67. @marufsiddiqui
  68. @mathieuginod
  69. @MichaelTackes
  70. @mind_detonator
  71. @mokeyZ
  72. @mortenditlevsen
  73. @nachocual
  74. @narrativium
  75. @palewar
  76. @patchets
  77. @piotrnaganski
  78. @pointertonil
  79. @prism_studios
  80. @pxstr
  81. @RedX76
  82. @reefwing
  83. @ResSquad
  84. @RickDoorakkers
  85. @Rincy73
  86. @Sheharyar_rr
  87. @simiansim
  88. @singo405
  89. @snake788
  90. @SpottedDog4me
  91. @starman_nl
  92. @themarkeaton
  93. @Thung
  94. @tmurrane
  95. @veasoftware
  96. @WaliAkadne
  97. @walkingway
  98. @walterpt
  99. @yenbekbay
  100. @YogReport

How To Claim Your Prize

If you’re a lucky second prize winner, please email me your top 5-10 choices from the list below (in order of most wanted->least wanted).

I’ll then do my best to match you with your preference (keep in mind each prize only has a limited number available). You have 48 hours to claim your prize, otherwise I’m going to give them away to others (more on that below).

First come, first serve, so be quick!

Unclaimed Prizes

As explained above, there is a chance that some of the prizes may go unclaimed (especially with so many winners!)

So, after 48 hours, if there are any unclaimed prizes, I will give them away to forum members who post a comment on this thread. The prizes will be given away in order from those with the most overall posts on the raywenderlich.com forums to those with the least posts, in order to reward regular forum members.

So if you want one last shot at winning, just post on this thread and who knows, you might get lucky and win an unclaimed prize! :]

And That’s a Wrap!

And that concludes the iOS 8 Feast, we hope you all enjoyed it and got fat and happy along the way!

Congrats to all of the prize winners, and a huge thank you to everyone who supported us by purchasing our new Swift books, subscribing to our video tutorials, signing up for RWDevCon, or recommending our site. You are what makes all of this hard work possible!

Thank you all again, and we’re now back to your regularly scheduled programming at raywenderlich.com!

Aww Yeah!

iOS 8 Feast Giveaway Winners! is a post from: Ray Wenderlich

The post iOS 8 Feast Giveaway Winners! appeared first on Ray Wenderlich.

Video Tutorial: Introduction to Unity Part 14: Lights

Viewing all 4373 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>