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

Video Tutorial: Scroll View School Part 2: Zooming


How to Create Both a Paid and Lite Version of an iPhone App

$
0
0
Learn how to create both a paid and free version of the same iPhone app!

Learn how to create both a paid and free version of the same iPhone app!

There are a ton of different ways you can monetize your app, and the most straightforward way is to make it paid. Unfortunately, a large number of users are not willing to purchase an app without trying it first.

One way to solve this problem on the App Store is to offer two different versions of your app:

  • A free/lite version. These are usually the noisy kind of apps that remind you to buy the paid version to unlock all of the amazing premium features. They commonly monetized by integrating ad networks such as iAd or AdMob.
  • A paid/full version. These usually cut the ads and enable features to further enhance the usefulness of the app.

In this tutorial, you will learn how to create both a paid and lite version of an iPhone app in a single Xcode project, using Xcode target settings.

Specifically, you will create an app focused on iOS interview questions, where the lite version has ads and the paid version does not.

Note: An alternate way to accomplish this is to have a single app that is free, which includes an in-app purchase to hide ads or unlock extra features or content. This was done in the popular app Letterpress.

Which option is best for you depends on your particular app. If you decide to go down the in-app purchase route, we have a tutorial for that.

The Bad Approach: Multiple Projects

The bad approach to creating both a paid and lite version of an app is to have multiple projects:

  1. Create a free version of the app.
  2. Copy the project folder and rename it to something like “Paid Version”.
  3. Add your extra features to the paid app, and Voila! You have both a free and paid version that you can build and deploy to the App Store.

That’s nice and simple, and it will work, but pretty soon you’re going to run into some big headaches. You now have two completely separate projects to update – so if you find a bug, you need to update it in both places! That’s a hassle, it’s error prone, and it’s not good programming practice.

So how can you change your approach to managing two versions that will avoid this issue?

The Better Approach: Multiple Targets

The better approach is to have just a single project, with multiple targets instead – one for each version of your app. So what are targets, and how do they help us achieve this goal?

Apple describes targets as follows:

“A target specifies a product to build and contains the instructions for building the product from a set of files in a project or workspace. A target defines a single product; it organizes the inputs into the build system—the source files and instructions for processing those source files—required to build that product. Projects can contain one or more targets, each of which produces one product.”

In plain english, this means that targets define products that each have their own configurations and source files within a single project. This sounds like a perfect solution for creating a free and paid version of an app while avoiding multiple projects and duplicate code!

Each target has its own plist that defines values like the bundle identifier, version number and build number which allow you to build unique products within a project. The target also has settings accessible from the project editor in XCode, including Preprocessor Macros found under Build Settings:

Target Settings

For this tutorial, you’ll use Preprocessor Macros to identify the product version in your code, thus enabling logical decisions based on the version. You’ll learn how to configure the Plist and Build Settings (most importantly the Preprocessor Macros) to enable product version differences under the same codebase. You’ll also learn how to easily swap assets used by different targets – in this case icons – to further customize product versions.

With that knowledge, your new plan for multiple versions will look something like this:

  1. Create the Free version of your app using a single target.
  2. Create and configure a second target for the paid version.
  3. Tie common source and unique assets (such as icons) to the new target.
  4. Add features for the paid version to your code, wrapped in version checks.

Getting Started

To get you started, I’ve created a simple application that will serve as a cree version of an app focused on iOS interview questions. You will enhance it by adding a paid version.

Download the starter project, unzip it and open it in XCode. Run your project and you’ll see a welcome screen that has some static text and a button:

 Welcome Screen

Once the user presses the Test my skills! button, the quiz will start:

3- Quiz Screen

Play a little bit and see how well you do. Once you hit the question limit, you’ll see an alert with your score:

Game Over

I was able to answer all 5 questions easily, how about you?

Code Tour

Now that you’ve tried the app, let’s take a tour of the code.

IQViewController is the quiz view controller and contains all of the custom code in this simple project. Open up IQViewController.m and take a look at setupQuiz:

- (void)setupQuiz {
  self.navigationItem.title = @"Free Version";
  self.maxAllowedQuestions = 5;
  [self setupAds];
 
  NSString* plistPath = [[NSBundle mainBundle] pathForResource:@"Questions" ofType:@"plist"];
  self.questions = [NSArray arrayWithContentsOfFile:plistPath];
  self.currentQuestionIndex = 0;
  [self showNextQuestion];
}

This is called by viewDidLoad, and configures the UI as well as loading the questions from a plist into an array called questions. Note that along with kicking off iAds, it sets things like the controller title and number of allowed questions. These would all be different in the paid version of the app, so you’ll be seeing this again later in the tutorial.

Since it’s driving much of the app, take a moment to look at Questions.plist:
7- Questions Plist

This is the plist that was stored in the questions array. Each question is a dictionary with the following keys:

  • question: Contains a string with the question to be asked.
  • answer1 .. answer4: These contain strings with the possible answers.
  • correctAnswer: Contains an NSNumber that holds the number of the correct answer.

Head back to IQViewController.m and look at showNextQuestion:

- (void)showNextQuestion {
  //1 - handle last question
  if (self.currentQuestionIndex + 1 > self.maxAllowedQuestions) {
    [[[UIAlertView alloc] initWithTitle:@"Game Over"
                                message:[NSString stringWithFormat:@"Your score is %ld",(long)self.score]
                               delegate:self
                      cancelButtonTitle:@"OK"
                      otherButtonTitles:nil] show];
    return;
  }
 
  //2 - update view for next question
  NSDictionary *questionDetail = self.questions[self.currentQuestionIndex];
  self.questionLabel.text = questionDetail[@"question"];
 
  for (int buttonCount = 1; buttonCount <= 4; buttonCount++) {
    UIButton *answerButton = (UIButton *)[self.view viewWithTag:buttonCount];
    [answerButton setTitle:questionDetail[[NSString stringWithFormat:@"answer%d",buttonCount]]
                  forState:UIControlStateNormal];
  }
}

This method is called each time a new question needs to be displayed, and it does a couple of things:

  1. Once you’ve hit the question limit stored in maxAllowedQuestions, this displays a UIAlertView with your score.
  2. This grabs the current question from the questions array and then uses it to set the label with the question as well as configuring the buttons with the four possible answers. Note that the answer buttons are referenced via their tag (set in Main.storyboard), and are numbered 1 – 4 to match the question numbers.

Finally, take a look at answerButtonPressed:

- (IBAction)answerButtonPressed:(UIButton *)sender {
  int correctAnswer = [(NSNumber *)self.questions[self.currentQuestionIndex][@"correctAnswer"] intValue];
  if (sender.tag == correctAnswer) {
    self.score++;
    self.scoreLabel.text = [NSString stringWithFormat:@"%ld",(long)self.score];
  }
 
  self.currentQuestionIndex++;
  [self showNextQuestion];
}

Once a user presses an answer button, this checks if the answer is correct, adds the score accordingly, and then loads the next question.

Creating a New Target for the Paid Version

Now that you’re familiar with the project and the functionality of the free version, it’s time to implement the paid version using the same project and codebase. The key to accomplishing this is the creation of a second target. This will enable two important things:

  1. You’ll be able add files (such as icon images) to the project that are tied specifically to this new target.
  2. You’ll be able to configure each target with a different Preprocessor Macro (more on this later), which you’ll use to identify the currently running app version in your code.

Creating a new target is easiest if you duplicate an existing target and make some modifications. This saves a lot of time versus configuring a target from scratch. Start by selecting your project from the navigator:

8- Navigator

Now right click your target InterviewQuestionsFree, and choose duplicate:

9- Duplicate Targets

Choose Duplicate Only on the popup:

10- Duplicate Only

Note: The reason this dialog exists is to provide you with an easy way to create both iPhone and iPad versions of an app within a single project, using two different targets. If this is what you wanted to do, you could select “Duplicate and Transition to iPad”.

However, before you go down this route you should consider making your app universal rather than making separate iPhone and iPad versions of your apps – IMHO it’s a nicer experience for users because they don’t have to buy your app twice. For more information on creating a universal app, check out this tutorial.

You want to be able to easily identify this new target as the paid app version target – so you have some renaming to do! First, select the new target, hit return, and rename it to InterviewQuestionsFull:
11- Rename Target

Next there’s a naming issue to fix. If you look up at the top part of XCode where you usually choose the device you want to run your app on, you’ll find something called a scheme just to the left of that:

Scheme Selection

You’ll use the scheme in just a bit to select with target you want to build. Currently you have InterviewQuestionsFree selected, but if you expand the popup, you’ll find a terrible thing:

14- Wrong Scheme

The other scheme is called InterviewQuestionsFree copy. You’ll want to rename that. Press on the current InterviewQuestionsFree to present the popup, then select manage schemes.

15- Manage Scheme

Click on InterviewQuestionsFree copy, hit return to make it editable then rename it to InterviewQuestionsFull. Hit enter once more and then press OK.

16- New Scheme

Everything looks neat now. I can sleep soundly tonight!

Modifying the Paid Target’s Plist

You might have noticed that after you created the new target for the full version, a new plist was added to your project:

17- New plist

This plist has a problem. Its name isn’t consistent with our target name anymore!

Rename it to InterviewQuestionsFull.plist and move it just under the InterviewQuestionsFree.plist by dragging it in the navigator.

20- Drag Plist

Now open your newly renamed InterviewQuestionsFull.plist. Update the Bundle display name – which is the app’s name that you see under it’s icon on the Springboard – to Interview:

18- Change Bund Display

You’ve made a small mistake. What was it? Select your project from the navigator then select your InterviewQuestionsFull target:

Missing Plist

Your target was pointing to the old plist name, and now that you renamed it, the target has no plist! You need to link it back to the target. Press on Choose Info.plist File and choose InterviewQuestionsFull.plist from the popup:

22- Choose Plist

For the final piece of renaming fun, hop over to the Build Settings for this target. In the Packaging section, update Product Name to be InterviewQuestionsFull. Although you’ve already set a display name in the plist, the product name will appear in the bundle identifier, and you should update it for consistency.

product name

It’s time to finally run the app, and test this new target. To identify which product (free or paid) you want to run, you need to select the appropriate scheme followed by a choice of your favorite device. In this case, select the InterviewQuestionsFull scheme so that you can try our new target.

23- Select Scheme

Build and run. You’ll see that the new target is running, and as you might expect it looks identical to the free target you duplicated:

 Welcome Screen

Now press the home button on your sim (or select Hardware->Home from the sim menu). You’ll notice you now have two installs – one with the Bundle display name you chose for Full (Interview), and the other with the default set for Free (Interview Free).This is because each target has its own Bundle Identifier, making it a unique app.
Two Apps

This means your second target is working properly, and you’re now building two distinct apps out of this project.

Adding the Paid Version Resources

Right now the apps are exactly the same, so let’s start adding some differentiation. You’ll start by giving the paid version its own icon and splash screen that don’t say “Free” on them.

Go to your project’s folder in the Finder and navigate to Interview Questions Starter/InterviewQuestions/InterviewQuestions/Images/Full. You’ll find assets for the paid version that haven’t yet been added to the project.

Drag them to your XCode project and place them in the paid folder that you’ll find in Supporting Files/Images, but don’t click finish yet!

Drag to Project

Pay attention to this tricky part:

27- Select Target

The bottom half of the popup has a section labeled Add to targets that you may have ignored when adding resources to a single target project. Now it’s time to start paying attention. These added images will only be used in the paid target, so check the InterviewQuestionsFull target and uncheck the InterviewQuestionsFree target before hitting Finish.

If you go back to your navigator, you’ll notice you now have 3 files in your paid folder that appear with the same names in the Free folder. Go ahead and select the InterviewQuestionsFull scheme, then build and run. While the project still runs, you’ll see XCode throwing some warnings if you look at the Issue Navigator:

Warnings

XCode is pointing out that you’re trying to copy the same file into your product bundle twice – something it cannot do because the bundle is a flat structure. This happened because you copied the paid images to the InterviewQuestionsFull target while the Free versions of the files were already there from when you duplicated the Free target.

Time to fix it! In the Project Explorer, select the 3 images under the Free folder, and then direct your attention to the File Inspector tab of the Utility Pane on the right:

Target Selection

Looking closer at the File Inspector, you’ll see a list of checkboxes under Target Membership:
29- 2 Targets

Uncheck the InterviewQuestionsFull target for these three resources, as you only want them associated with the Free target:

30- Remove Target

Build with the InterviewQuestionsFull scheme again and you’ll get a successful build without any warnings about duplicate files.

Even more exciting is that you can now see unique splash and icon images for the two targets. Take a look at your icons:

unique icons

Now only your free product has the word “free” in it’s icon, and you’ve successfully learned how to tie unique assets to different targets within a project.

That was easy, but what about changes that require code modification?

Adding a Macro to Differentiate the Versions

Now that you have your two targets on the same codebase, you need to make some changes to enable paid features on the paid version. For example, you need the maximum number of allowed questions to be set to 10 in the paid version, rather than the 5 used for Free.

Running on a single codebase, you’re going to need some programatic way to determine which product (target) is currently running so you can make decisions like this appropriately.

This is where a Preprocessor Macro comes into play. Macros are the small fragments of code that you’re used to seeing in #define statements. You’ve probably used them before for something like defining a custom RGB color:

#define GREEN [UIColor colorWithRed:126.0/255.0 green:176.0/255.0 blue:122.0/255.0 alpha:1.0]

The key here is that you can define a preprocessor macro in the configuration of a target. This way, you can define a flag that identifies the product version and make decisions in your code based on that. To set this up, start off by selecting your project form the navigator:

8- Navigator

Select your InterviewQuestionsFree target and then go to the Build Settings tab.

31- Build Settings

Filter on the word “macro” and you’ll find a place to enter preprocessor macros:
macro

You’ll see the Debug build already has a macro called DEBUG=1 here. You want to add something similar to both the Debug and Release profiles to signify this target is tied to the Free product. Double click the values for these, then hit the ‘+’ button and enter a macro called FREE=1:

33- Rename

Once complete, your macros for the InterviewQuestionsFree target should look like this:

34- After Renaming

Now you can use this macro in your code to differentiate between your two targets!

Test this out by changing the navigation item title according to different targets. Open IQViewController.m and replace the following line in setupQuiz:

self.navigationItem.title = @"Free Version";

with this:

#ifdef FREE
    self.navigationItem.title = @"Free Version";
#else
    self.navigationItem.title = @"Paid Version";
#endif

The #ifdef simply confirms if there is a macro called FREE defined. Because you defined this on the free version only, this allows you to handle the two versions differently.

Run your app using the IntervewQuestionsFull scheme, and click Test my skills. You’ll see that the navigation item title has changed to “Full Version”.

35- Full Version

If you go back and run with the InterviewQuestionsFree scheme, you’ll see it’s still displaying “Free Version” as you’d expect.

You can use this same technique to make other changes between the two versions. Let’s make the maximum allowed questions to 5 for the Free target and 10 for Full, and remove ads for the full version.

To do this, still in setupQuiz, find the following lines:

#ifdef FREE
    self.navigationItem.title = @"Free Version";
#else
    self.navigationItem.title = @"Paid Version";
#endif
 
  self.maxAllowedQuestions = 5;
  [self setupAds];

Modify this code to look like the following:

#ifdef FREE
  self.navigationItem.title = @"Free Version";
  self.maxAllowedQuestions = 5;
  [self setupAds];
#else
  self.navigationItem.title = @"Full Version";
  self.maxAllowedQuestions = 10;
#endif

Run your application with each schema to see the differences. You’ll now be able to see all 10 questions for the full version, and rejoice – no more ads!

no ads

Adding the Skip Button for the Full Version

As a bonus, let’s add a new feature to the full version: the ability to allow the users to skip a question.

To do this, add some code to set up this new button only in the full version by pasting the below inside the #else block in setupQuiz:

  self.skipQuestionButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
  [self.skipQuestionButton setFrame:CGRectMake(20, 80, 100, 44)];
  [self.skipQuestionButton setTitle:@"Skip Question" forState:UIControlStateNormal];
  [self.skipQuestionButton addTarget:self
                              action:@selector(skipButtonPressed)
                    forControlEvents:UIControlEventTouchUpInside];
  [self.view addSubview:self.skipQuestionButton];

Your else statement will now look like this:

#else
  self.navigationItem.title = @"Full Version";
  self.maxAllowedQuestions = 10;
  self.skipQuestionButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
  [self.skipQuestionButton setFrame:CGRectMake(20, 80, 100, 44)];
  [self.skipQuestionButton setTitle:@"Skip Question" forState:UIControlStateNormal];
  [self.skipQuestionButton addTarget:self
                              action:@selector(skipButtonPressed)
                    forControlEvents:UIControlEventTouchUpInside];
  [self.view addSubview:self.skipQuestionButton];
#endif

Nothing fancy here. The skip button was created and set to trigger skipButtonPressed when pressed. Now move to the stubbed out skipButtonPressed and replace it with the following:

- (void)skipButtonPressed {
  //1
  self.score++;
  self.scoreLabel.text = [NSString stringWithFormat:@"%ld",(long)self.score];
 
  //2
  self.currentQuestionIndex++;
  [self showNextQuestion];
 
  //3
  self.skipQuestionButton.hidden = YES;
}

This does the following.

1. Gives the user a point and refreshes the displayed score.

2. Display the next question.

3. Hide the skip button, as it’s only allowed once per quiz.

Run your app and test out the Skip Button functionality.

36- Skip

At this point, you’ve got two uniquely functioning versions of the app. Test them well by running different schemes to ensure that all is going great.

Where To Go From Here?

Here is the example project that you developed in this tutorial.

Congratulations – you now have a project that uses two targets with the same code-base, so now if you hit a bug that impacts both versions of your app, you only have to make that fix in one place. So once again, the day is saved. Thanks to the power rangers… oh wait… thanks to targets!

Targets are one of the features that are usually ignored by developers. With this new knowledge in hand, you’ll be able to create powerful products.

For example, you might create a template news app with different targets for each of your clients. Each target could have its own colors, resources, and minor changes in the code. This way you’ll be able to build a totally new app in just few clicks. Sell that to different clients and you’ll become rich in no time… just don’t forget my commission $$$! :]

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

How to Create Both a Paid and Lite Version of an iPhone App is a post from: Ray Wenderlich

The post How to Create Both a Paid and Lite Version of an iPhone App appeared first on Ray Wenderlich.

Video Tutorial: Scroll View School Part 3: Centering Content

Video Tutorial: Scroll View School Part 4: Auto Layout

iOS 7 Game Controller Tutorial

$
0
0
Learn how to add hardware game controller support into your iOS games!

Learn how to add hardware game controller support into your iOS games!

iOS 7 introduced official support for hardware game controllers. This is great because some games are particularly well suited for hardware game controllers – imagine Mario with a touch interface!

It’s also great because now that it’s official, you can support a variety of game controllers just by implementing a single API.

On top of that, Apple has provided prospective controller manufacturers with specific requirements in order to be compatible with iOS. Apple isn’t just letting just any yahoo make a hardware controller for iOS!

In this tutorial, you will add hardware game controller support into a simple platformer game like Mario, made with Sprite Kit.

This tutorial has the following prerequisites:

  • Some basic Sprite Kit experience. If you are new to Sprite Kit, I recommend checking out our Sprite Kit Tutorial for Beginners first.
  • A hardware iOS game controller. There’s no way to test game controllers in the simulator, so you’ll need a hardware iOS game controller for testing. If you’re wondering which one to get, I recommend picking up the Stratus SteelSeries Wireless Gaming Controller.
  • Review starter game (optional). As I mentioned, you will be adding game controller support into a simple Sprite Kit platformer game like Mario. If you’d like to learn how to make this game, we have a tutorial for that.

Grab your game pad and let’s get started!

Supported Game Controller Types

There are exactly three game controller types supported by the Game Controller framework, as specified in Game Controller Programming Guide:

1) A standard form-fitting controller

The form-fitting controller encases the iPhone within the controller, connecting via the lightning connector.

At the time of writing this article, there is only one of these types of controllers available – Logitech’s Powershell controller.

Logitech Powershell

This type of controller supports the “standard” controller profile, which means it has the following inputs:

  • Direction Pad (always on the left)
  • 4 buttons A, B, X, Y (always on the right>
  • 2 shoulder buttons, one on the left and one on the right
  • Pause button

2) An extended form-fitting controller

The second type of controller is also form-fitting, but it contains some extra buttons so is considered “extended.”

At the time of writing this article, there is only one of these types of controllers available – MOGA’s ACE Power controller.

MOGA

Note that an extended controller like this one contains some additional buttons:

  • Two thumbsticks, one left and one right
  • Additional pair of shoulder buttons/triggers

3) An extended wireless controller

The final controller type is the external/bluetooth controller, such as Stratus’s SteelSeries controller.

This supports the extended gamepad (I believe that external controllers are all required to support the extended profile, that’s my impression from the WWDC videos in any case).

SteelSeries

The external controllers connect via bluetooth and must first be paired to the device in order work. Once paired, any time the controller is powered on it will connect via bluetooth to the same device.

The full collection

Here’s an image of my current hardware collection:

Controllers

In this image:

  • Upper-middle: The iCade: A legacy game controller that came out before the iOS 7 game controller API was released.
  • Upper-left: Stratus SteelSeries A extended wireless controller.
  • Upper right: Logitech Powershell: A standard form-fitting controller.
  • Lower left: MOGA’s ACE Power controller: An extended form-fitting controller.
  • Lower right: Xbox 360 controller: Don’t get excited, these don’t work on iOS! :] I just included it in the picture here for size comparison purposes.

Common characteristics

Beyond specifying the controller types, Apple specifies certain characteristics that all controllers must satisfy. These are intended to provide a consistent, high quality experience when using a hardware controller with an iOS device.

If you would like to have a complete picture of the benefits of Apple’s requirements, I suggest watching the video on hardware controllers from WWDC 2013. But, let me just mention a few things:

  1. All buttons are pressure sensitive
  2. Thumb sticks must have no dead zones or drift
  3. Controllers must have LED indicators that indicate player number
  4. A, B, X, and Y buttons always have the same color

Game Controller Design Considerations

Apple has a few requirements that you must satisfy in order to submit an app that supports a hardware controller. The first, and most important, is that you must not require a hardware controller. Your game must be playable with standard touch/tilt controls.

This means that you have to put thought into how you are going to implement your control scheme. An Extended Gamepad has a total of 13 controls, good luck fitting all of those controls on a touch screen!

Don't do this!

Don’t do this!

Because of these issues, many games provide completely different controls schemes on a hardware controller versus the touch screen.

For example, LEGO Star Wars uses the hardware controller to move around the player in 3D space, but if you use the touch screen, you simply touch on the screen where you want the player to go, and he will move to that spot.

You will have to be creative to make a game that takes advantage of the hardware controller, but still plays well with touch screen controls. You don’t want to design for the hardware and then add touch screen controls as an after thought. Realistically, most of your users will be playing your game via the touch screen, so you want both experiences to yield praise and good reviews.

Getting Started

As I mentioned earlier, in this tutorial you will be adding game controller support to the Super Koalio game from our Sprite Kit platformer game tutorial.

In the original tutorial, Super Koalio has a very simple control scheme. Tapping on the left side of the screen walks forward (forward only) and tapping on the right side of the screen jumps.

However, I have created a modified version of the starter project that contains a more complete set of controls and on screen buttons and joystick.

Download the starter project, build and run, and try out the new control scheme.

Final Controls

The new control scheme uses an analog stick (provided on github by the sneaky narwal – you can get that code here), and two buttons:

  • Dash button: This enables Koalio to reach a much higher top speed. You won’t need this in the hardware controller because the analog stick will enable you to move Koalio at a much wider variety of speeds, however you need a solution for touch players, hence this button. Pressing dash makes the Koala change size/shape and shades his image darker to give visual feedback of his state.
  • Jump button: The jump buttons is simple, but often you want to hold dash and press jump and the same time. Because a touch point is a single point rather than the entire surface area of your thumb, you need something else in order to use both buttons. In my scheme, if you press the B button, it stays pressed until you release that touch. That way, you can start on B and slide onto and off of the A button and the B button stays pressed.

Note that the control layer is a separate class called HUDNode. The hardware controller will communicate with the HUD.

Connecting Hardware Controllers

First, make sure your controller is on and paired to your device, following the instructions that came with your controller.

Next, you’ll add some code to connect your game with the controller. Start by opening HUDNode.m and importing the GameController framework:

@import GameController;

Then, add a new GCController property to your private interface:

@property (nonatomic, strong) GCController *controller;

Now you can add the code that interacts with the hardware. Add the following method to HUDNode.m:

- (void)toggleHardwareController:(BOOL)useHardware {
  //1
  if (useHardware) {
    //2
    self.alpha = 0.0;
    //3
    self.controller = [GCController controllers][0];
    //4
    if (self.controller.gamepad) {
      //5
      __weak typeof(self) weakself = self;
      [self.controller.gamepad.buttonA setValueChangedHandler:^(GCControllerButtonInput *button, float value, BOOL pressed) {
        weakself.aPushed = pressed;
      }];
      [self.controller.gamepad.buttonX setValueChangedHandler:^(GCControllerButtonInput *button, float value, BOOL pressed) {
        weakself.shouldDash = pressed;
      }];
      //Add controller pause handler here
    }
  } else {
    //7
    self.alpha = 1.0;
    self.controller = nil;
  }
}
  1. First, you are passing in a boolean to this method. Passing in YES will initiate and set up the methods to handle the input from the controller. It will also hide the on screen HUD. Passing NO will reveal the on screen HUD and reset the controller.
  2. In this part you are just hiding the on screen controls by setting the entire node’s alpha to 0.0.
  3. Here, you set the property to the GCController object that controls the first controller connected. GCController has a controllers class method that returns an array of all the connected hardware. In this app you will only ever communicate with the first controller in the array. You can connect up to four controllers to a single iOS device.

    There are two profiles. The gamepad profile and the extended gamepad profile. The extended gamepad profile has all the controls that the gamepad profile has plus a bunch more. In this app you are going to support both profiles by adding code that responds to both the dpad and the left analog stick. But, for now you are just adding support for the A and B buttons.

  4. In this section you check for the presence of the gamepad profile. If you need to know what profile your controller supports you check for the .gamepad property or the .extendedGamepad property. If the property is not supported, accessing the property will return nil.
  5. Next, you set up the change handlers that will be called when the button is pressed. In this case, it’s very simple. You set the aPushed (or shouldDash) property to the value of pressed.
    Each button or control has a property on the gamePad (or extendedGamePad) object.

    There are two ways to access the game controller object for input. First, you can query the state of these properties and read the state of the various buttons and controls. Alternatively, you can set the changeHandler which executes a block every time the state changes. For the buttons, you use change handlers.

    I’ve mapped the A button on the controller to the A button in the HUD and the X button on the controller to the B button in the HUD. This is the most comfortable way to use both dash and jump on the physical control.

  6. If the method is passed NO, you reset the alpha property to 1.0 (revealing the HUD) and set the controller property to nil.

Now that you have that method in place, it’s time to connect to a controller. First, you will handle the case when a controller is already connected when the app starts. Make sure your bluetooth enables controller is paired with your device or plug your lightning connected controller in (when it’s time to test again).

Find the comment ‘//Add hardware controller code here’ in initWithSize and add this code:

if ([[GCController controllers] count]) {
  [self toggleHardwareController:YES];
}

This will check for any existing controllers and if it finds one or more, it will run the method you just added.

Note: If you have a controller that connects to the lightning cable, testing gets tricky because you have to disconnect your Xcode connected cable to plug your controller in. So, from now on, testing will be several steps:

  1. Build and run.
  2. Disconnect from your Mac.
  3. Connect the controller.
  4. Run your app by tapping on it.

You won’t be able to get logs in that case either, so you may need to create a logging SKLabelNode or do something else to debug issues. You won’t be relying on any specific NSLog statements in this tutorial, but if you get stuck or need to debug something, you won’t be able to do that with a lightning connected controller. If you have a bluetooth controller this will be easier.

Go ahead and connect your controller and run the app. The HUD should be gone and you should be able to dash and jump using the buttons.

Button response

Connecting the Thumb Stick

The next step is to connect the thumb stick to the controller. You already have a custom getter method that accesses the state of the on screen thumbstick, so you’ll be adding a little more code and reading (instead of using a change handler) the hardware left thumbstick input instead.

Change the xJoystickVelocity method to the following:

- (float)xJoystickVelocity {
  //1
  if (self.controller.extendedGamepad) {
    return self.controller.extendedGamepad.leftThumbstick.xAxis.value;
  //2
  } else if (self.controller.gamepad) {
    return self.controller.gamepad.dpad.xAxis.value;
  }
  //3
  return self.joystick.velocity.x / 60.0;
}
  1. You first check for the extended gamepad profile, if it exists, you return the value of its left thumbstick. Apple requires that controller readouts be standardized and have appropriate dead zones, so you don’t have to do any preprocessing of the values coming back from the controller. By the time you retrieve the value, you can just use it.
  2. If you don’t find an extended controller, you check for a gamepad profile. If it exists, you return the value of the dpad. All buttons are pressure sensitive, so the dpad will also return a value between -1.0 and 1.0 instead of just booleans for left/right.
  3. If you don’t have either a gamepad or extended gamepad, you revert to accessing the on screen HUD joystick class to retrieve a value. This code already existed in the method.

Go ahead and build and run now. You should now have full control over your Koala.

Hardware control

Not bad for just a few lines of code, eh? In my opinion this also makes the game much more fun than the on-screen controls as well.

Connecting in the Middle of a Game

The next step is to make your app respond to controller being connected and disconnected during gameplay. This is done with a system notification. First add a couple properties to keep track of the observers and remove them when the class is deallocated. Add this to HUDNode.m, @interface section:

@property (nonatomic, strong) id connectObserver;
@property (nonatomic, strong) id disconnectObserver;

Next, add the following code in the initWithSize method of the HUD at the ‘//Add observers here’ comment:

__weak typeof(self) weakself = self;
self.connectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidConnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
  if ([[GCController controllers] count] == 1) {
    [weakself toggleHardwareController:YES];
  }
}];
self.disconnectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidDisconnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
  if (![[GCController controllers] count]) {
    [weakself toggleHardwareController:NO];
  }
}];

The GCControllerDidConnectNotification and GCControllerDidDisconnectNotification notifications are fired when a new controller is connected or disconnected. If a new controller is connected and the count of controllers is 1, you can conclude that there were no connected controllers before the notification fired and you call your routine that hides the HUD and sets up the controller. When the disconnect notification is fired, you check to see whether there are any controllers left, and if there are none, you call that method to reveal the HUD and remove the GCController.

Pretty straight forward. Finally, when using the block methods for NSNotificationCenter you need to remove those observers in the dealloc method or they will cause a leak (they’ll retain the HUDNode object).

- (void)dealloc
{
  [[NSNotificationCenter defaultCenter] removeObserver:self.connectObserver];
  [[NSNotificationCenter defaultCenter] removeObserver:self.disconnectObserver];
}

Build and run now. You should be able to start the app without a controller, then watch the HUD disappear when you connect and reappear when you disconnect your controller. This is much easier if you have a bluetooth connected controller, but will work in either case.

No controls

Supporting the Pause Button

The last thing you must do in order to support gamepads – and this is a requirement from Apple – is add support for the pause button.

I’m going to use NSNotificationCenter to communicate between the HUDNode and the SKView/SKScene. A delegate protocol would work as well, but this kind of event seems more suited to a notification to me. Add the following line of code to HUDNode.h before the @interface line:

extern NSString * const kGameTogglePauseNotification;

Then add this line before @interface in HUDNode.m:

NSString * const kGameTogglePauseNotification = @"GameTogglePauseNotification";

This is just the NSString name of the notification. Using const like this just makes it easier not to make a mistake typing (and copying/pasting) the string into multiple places. Then switch to the ViewController.m and add a new property to keep track of the observer for removal:

@property (nonatomic, strong) id pauseToggleObserver;

You need to #import the HUDNode.h file to get access to the notification NSString const that you just created:

#import "HUDNode.h"

Then, add this to the end of viewDidAppear:

__weak typeof(self) weakself = self;
self.pauseToggleObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kGameTogglePauseNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
  [weakself togglePause];
}];

This just creates the new NSNotification observer that will fire when the notification is fired. Next, create a dealloc method to remove that observer:

- (void)dealloc {
  [[NSNotificationCenter defaultCenter] removeObserver:self.pauseToggleObserver];
}

Now, in that same file, add the pause method:

- (void)togglePause {
  SKView *view = (SKView *)self.view;
  view.paused = (view.paused) ? NO : YES;
  if (!view.paused) {
    self.pauseView.hidden = YES;
  } else {
    self.pauseView.hidden = NO;
  }
}

I’ve added a hidden UIImageView with a pause image to the storyboard already. It’s called pauseView.

I would prefer to use an SKLabelNode or SKSpriteNode to add a pause label or button the the scene, but once you set self.view.paused = YES, nothing renders in the SKView after that. So you never see the new node or label that you’ve added. There are ways around this issue, but to keep it simple I just used UIKit.

Now, you need to add the code that sends the notification. In HUDNode, in toggleHardwareController, there’s a comment line ‘//Add controller pause handler here’, replace that comment with this code:

[self.controller setControllerPausedHandler:^(GCController *controller) {
  [[NSNotificationCenter defaultCenter] postNotificationName:kGameTogglePauseNotification object:nil];
}];

Build and run now. Press pause button. If everything is in place, you should see something like this (and the game should be paused):

IMG_2726

Serializing Controller Inputs

The Game Controller framework has one more capability that you are going to explore. You can serialize (convert to NSData to be saved in a plist or sent over the network) the state of the controller.

This ability can be used in different ways. For example, you could use this feature to send the controller state across the network to another player, or you can save the entire history of inputs to a file. In this tutorial, you’ll be recording and playing back the sequences of input you use to progress through the level.

The first step is to add a boolean to indicate to the HUD class that it is in snapshot recording mode. Add the following in the @interface section of HUDNode.h:

@property (nonatomic, assign) BOOL shouldRecordSnapshots;

Now, add a new NSMutableArray that will contain the snapshots to HUDNode.m @interface:

@property (nonatomic, strong) NSMutableArray *snapShots;

The next step is to designate a file that the snapshots can be saved to. Open HUDNode.m and add the following two methods (end of the file):

- (NSURL *)snapShotDataPath {
  //1
  NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
  NSString *filePath = paths[0];
  filePath = [filePath stringByAppendingPathComponent:@"snapshotData.plist"];
  //2
  return [NSURL fileURLWithPath:filePath];
}
 
- (void)saveSnapshotsToDisk:(NSArray *)snapShots {
  //3
  if (![snapShots count]) return;
  //4
  if (![snapShots writeToURL:[self snapShotDataPath] atomically:YES]) {
    NSLog(@"Couldn't save snapshots array to file");
  }
}
  1. These two methods make it easier to work with the file representation of the snapshots that you’ll create. The first method just retrieves the NSURL that you’ll use to save and load data to and from. You’ll be referring to this URL location more than once, so it’s better to give it its own method. First, you get the file path that you’ll use to store the plist. You are putting the file into the app’s documents directory.
  2. Then, you return an NSURL form of the path string you just created.
  3. In the second method, you will be saving the array of NSData snapshots that you create. In this first part, you don’t want to save the array if it’s empty, so you check for that and return if there aren’t any snapshots.
  4. Finally, you call writeToURL on the snapshots array (a method that saved an array to disk in plist form). This method returns a BOOL indicating whether the operation was successful or not. If it fails, you want to let yourself know so you can do further investigation.

Now, you are ready to write the code that creates the snapshots and adds them to the array. You need to generate one snapshot per frame. You want to find a place in your code that is called once per frame, every frame. The touch methods aren’t going to work, because they are called when the touches change, so there would be many frames where no touch methods would fire.

I chose to use the xJoystickVelocity method in HUDNode.m. Every frame, the player’s update method calls this method (once per frame) to get the state of the joystick. Change the following block of code:

//1
if (self.controller.extendedGamepad) {
  return self.controller.extendedGamepad.leftThumbstick.xAxis.value;
  //2
} else if (self.controller.gamepad) {
  return self.controller.gamepad.dpad.xAxis.value;
}

To this:

if (self.controller.extendedGamepad) {
  //1
  if (self.shouldRecordSnapshots) {
    //2
    NSData *snapShot = [[self.controller.extendedGamepad saveSnapshot] snapshotData];
    //3
    NSDictionary *snapshotDict = @{@"type": @"extended", @"data":snapShot};
    //4
    [self.snapShots addObject:snapshotDict];
 
  }
  return self.controller.extendedGamepad.leftThumbstick.xAxis.value;
} else if (self.controller.gamepad) {
  //5
  if (self.shouldRecordSnapshots) {
    NSData *snapShot = [[self.controller.gamepad saveSnapshot] snapshotData];
    NSDictionary *snapshotDict = @{@"type": @"gamepad", @"data":snapShot};
    [self.snapShots addObject:snapshotDict];
  }
  return self.controller.gamepad.dpad.xAxis.value;
}
  1. The first thing to do is check whether the shouldRecordSnapshot boolean is YES.
  2. Next, you create the NSData representation of the snapshot. You create a snapshot by calling saveSnapshot on the gamepad profile object. In this case the extendedGamepad profile. The GCExtendedGamepadSnapshot that’s created by calling saveSnapshot is an object that you can query the snapshot buttons the same way to do the controller profile object. More on that in a bit. Once you have the snapshot, you need to convert it to NSData so it can be saved to a plist. You do that by calling snapshotData.
  3. Then, you create a dictionary to contain the NSData. When you load these snapshots to read them back later on, you will need to know what kind of snapshot it is in order to convert it from NSData back into a snapshot object (either a GCGamepadSnapshot or a GCExtendedGamepadSnapshot). You won’t know just by looking at the NSData which type it is. So, you create a dictionary that contains a “type” key so you can determine which you need to initialize with the NSData.
  4. Finally, you add that dictionary to the snapshots array.
  5. This second block is identical to the one I just covered, except that you are saving a GCGamepadSnapshot, so the “type” is “gamepad”.

You need a method that starts the recording process. Add this to HUDNode.m (at the end):

- (BOOL)recordSnapshots {
  if (!self.controller || self.shouldRecordSnapshots) return NO;
  self.shouldRecordSnapshots = YES;
  self.snapShots = [NSMutableArray array];
  return YES;
}

Here, you are checking that there’s a controller connected. You don’t want to enable snapshot recording without a controller. Also, if you are already in recording mode, you don’t want to enable it again, or you’ll erase all the snapshots you’ve collected up to that point.

Then you set shouldRecordSnapshots to YES and create a new array for the snapshots object.

You are returning a BOOL from this method. This is a way to tell if the recording mode successfully started.

I’m not going to be creating UI to start/stop the recording mode or the playback mode. I’ll have you do all that in code. In a real game, you’d want buttons or a settings pane to enable these options. Returning a boolean from this method makes it easier to change the state of that UI (like turning a recording button to a YES state).

Now, add this line to the very end of HUDNode.m, initWithSize:

[self recordSnapshots];

That is all you need to do in order to retrieve snapshots and store then in an array. However, you still need to call the method that saves the snapshots to a plist on the disk. For simplicity, you’re going to be calling that when the player wins the game (if he dies before reaching the end of the level, that run won’t be saved).

Find this line in GameLevelScene.m, gameOver:

gameText = @"You Won!";

Add these lines immediately after it:

if (self.hud.shouldRecordSnapshots) {
  [self.hud saveSnapshots];
}

There’s one last thing you must do, create the saveSnapshots method. You already have a saveSnapshotsToDisk method, but that one must be called internally (to have access to the private snapshots array).

Add this method declaration to HUDNode.h:

- (void)saveSnapshots;

Now, add this method to the end of HUDNode.m:

- (void)saveSnapshots {
  [self saveSnapshotsToDisk:self.snapShots];
}

That’s it. You can now build and run. Make sure when you start the game, the controller is already connected, or the recordSnapshots method with return without enabling the function. Play through the level and make sure you win!

IMG_2771

When you are done, you’ll have a new plist inside the app’s bundle on the device. In order to validate that this worked correctly, you’ll need to use a program that allows you to browse all the contents of your iPhone, not just the pictures. I use iExplorer. Navigate to the app, find the Documents folder, and you should have a snapshotsData.plist file that looks like this:

Screen Shot 2014-02-24 at 9.46.33 AM

If you don’t have iExplorer or a program that can navigate the device’s file system, you can still proceed. The next build and run step will validate whether or not you’ve got the recording part working right.

Playing Back Serialized Controller Data

The next step is to play back those snapshots.

You’ll need some new instance variables, a boolean to indicate whether you are in replay mode and a index number of the current snapshot in the array. Add these two properties to HUDNode.m, @interface section:

@property (nonatomic, assign) NSUInteger currentSnapshotIndex;
@property (nonatomic, assign) BOOL shouldReplaySnapshot;

Next, set add the replaySnapshots method:

- (BOOL)replaySnapshots {
  //1
  self.snapShots = [NSArray arrayWithContentsOfURL:[self snapShotDataPath]];
  //2
  if (!self.snapShots || ![self.snapShots count]) return NO;
  //3
  self.shouldReplaySnapshot = YES;
  //4
  return YES;
}
  1. First, you initialize the snapshots object with the contents at the plist location. This gives you back the original array before you wrote it to disk in the previous section.
  2. If there isn’t a file at that location or if there’s an error parsing it, arrayWithContentsOfURL returns nil. You check for that next, or if there is a valid plist that’s initialized and it’s empty, then you return NO and you do not set the game into replay mode.
  3. However, if there is a valid data, you proceed to set shouldReplaySnapshot to YES.
  4. Finally, you return YES indicating that you are now in replay mode.

The next step is to convert the objects in the snapshots array back into GCGamepadSnapshot or GCExtendedGamepadSnapshot objects. Create a convenience method that parses the dictionary, initializes the right object of the two depending on the value in the “type” key, and returns whichever is correct.

Add this method to HUDNode.m:

- (id)currentGamepadFromSnapshot {
  //1
  NSDictionary *currentSnapshotData = self.snapShots[self.currentSnapshotIndex];
  //2
  id snapshot = nil;
  //3
  if ([currentSnapshotData[@"type"] isEqualToString:@"gamepad"]) {
    //4
    snapshot = [[GCGamepadSnapshot alloc] initWithSnapshotData:currentSnapshotData[@"data"]];
  } else {
    //5
    snapshot = [[GCExtendedGamepadSnapshot alloc] initWithSnapshotData:currentSnapshotData[@"data"]];
  }
  return snapshot;
}
  1. First, you retrieve the dictionary from the array based on the currentSnapshotIndex. You’ll be incrementing that index in another place to ensure that it’s only incremented once per frame.
  2. Next, initialize a generic object pointer. This needs to be generic because it can either be a GCExtendedGamepadSnapshot or a GCGamepadSnapshot object. You won’t know, so the pointer and the return type of the method are ‘id’.
  3. Next, you check the “type” entry in the dictionary to see if it’s “gamepad”, meaning that it’s a GCGamepadSnapshot type.
  4. If it is, you initialize a GCGampepadSnapshot object, using the “data” entry (the NSData from the snapshot) in the dictionary. Both types of snapshot contain the initWithSnapshotData method.
  5. If it isn’t a gamepad type, then it’s an extended profile, and you initialize that type of object. You then return whichever type you’ve created.

This method is just a way to compartmentalize code and make it easier to write the several bits that query the snapshot, using this common method in multiple places.

The next step is to change the way the inputs are queried if shouldReplaySnapshot is YES. First, modify xJoystickVelocity. Add this block of code to the beginning of that method (before all the existing code):

//1
if (self.shouldReplaySnapshot) {
  //2
  id currentSnapshot = [self currentGamepadFromSnapshot];
  //3
  self.currentSnapshotIndex++;
  //4
  if ([currentSnapshot isKindOfClass:[GCGamepadSnapshot class]]) {
    //5
    GCGamepadSnapshot *gamepadSnapshot = (GCGamepadSnapshot *)currentSnapshot;
    //6
    return gamepadSnapshot.dpad.xAxis.value;
  } else {
    //7
    GCExtendedGamepadSnapshot *extendedGamepadSnapshot = (GCExtendedGamepadSnapshot *)currentSnapshot;
    return extendedGamepadSnapshot.leftThumbstick.xAxis.value;
  }
}
  1. First, you check to see if shouldReplaySnapshot is YES. If it isn’t then the rest of the existing code runs as though you hadn’t added this new block.
  2. Next, retrieve the latest snapshot object using the method that you just built. This returns an id type, so, you still don’t know what kind of snapshot you’re getting. You’ll figure that out in a second.
  3. Third, you increment the currentSnapshotIndex variable. You know that this method, xJoystickVelocity, will be called exactly once per frame. So, it is the right place to increment the index of the snapshot to reliably get a new snapshot each frame.
  4. Then, you inspect the class type of the currentSnapshot object to see if it’s a GCGamepadSnapshot class using isKindOfClass. isKindOfClass is an NSObject method that you can use to determine which class type an object is at runtime.
  5. If you have a GCGamepadSnapshot, you cast that variable to that type so you can access its properties without a compiler error.
  6. Finally, you return the xAxis value from the dpad control.
  7. If you have an extended profile, you change two things, you must cast the snapshot to the GCExtendedGamepadSnapshot type and you ask for the leftThumbstick control instead of the dpad.

The only thing left to handle are the buttons. You may wonder how to do this, because currently, the player’s update method is just querying the state of the two booleans you created earlier, aPushed and shouldDash. There’s actually a really easy way to handle this, create a custom property accessor.

Add the following custom accessor method for shouldDash:

- (BOOL)shouldDash {
  //1
  if (self.shouldReplaySnapshot) {
    //2
    id snapshot = [self currentGamepadFromSnapshot];
    //3
    return [[snapshot valueForKeyPath:@"buttonX.pressed"] boolValue];
  }
  //4
  return _shouldDash;
}
  1. Check whether shouldReplaySnapshot is YES.
  2. If so, get the current snapshot from the array.
  3. This line is doing a couple things. You could have cast the snapshot to its type, either gamepad or extended gamepad, then access the buttons by their dot properties. But, that would take more code.

    The approach I’m using is Key Value coding. KVC is a way of accessing an object’s properties with an NSString matching the property’s name. KVC has a couple important methods, valueForKey and valueForKeyPath. If you need to access a property of a property, like you do here, use the valueForKeyPath. This means that you don’t have to know whether the object is a GCExtendedGamepadSnapshot or a GCGamepadSnapshot, because they both contain the same keys for buttons, you can ask for the value of that same key path from both objects.

    KVC returns an NSNumber representation of the BOOL instead of the BOOL value. So, if you were to return this without calling boolValue, you get a pointer to an NSNumber which would always evaluate to YES. That would give you a bunch of erroneous values, essentially it would interpret the snapshot as you pressing both buttons continuously.

    One word on Key Value Coding. It’s a very useful tool, and there are times when it can save you a lot of code. But, if you can use either dot property notation or Key Value Coding, normally it’s better to use dot property access instead. You get better compile time checking. If you misspell a key or ask for a key that doesn’t exist, with KVC your code will compile then crash at runtime. That wouldn’t happen with dot property notation. I’m using it in this case to bring it to the attention of those who’ve never used it, and because it saves me several lines of code. I’m able to avoid the branching and casting calls on the different types of snapshot objects. It happens to work because the property names on the different objects are the same.

  4. If you aren’t in shouldReplaySnapshot mode, then you just return the value of the properties backing instance variable, _shouldDash.

Go ahead and add the getter for aPushed. It follows identical logic to shouldDash:

- (BOOL)aPushed {
  if (self.shouldReplaySnapshot) {
    id snapshot = [self currentGamepadFromSnapshot];
    return [[snapshot valueForKeyPath:@"buttonA.pressed"] boolValue];
  }
  return _aPushed;
}

That’s it, your recording and replaying code should now all be in place. However, you’ll need to do some careful actions to test it. First, make sure you beat a game as mentioned in the previous section so it saves a valid snapshots plist file.

Then, find this line:

[self recordSnapshots];

Remove that line and replace it with:

[self replaySnapshots];

If you’ve done everything correctly, you will see your player performing the same motions, almost as if by magic, as you directed using your controller.

Moving without buttons

Note: Note that this is a simplistic method of recording screenshots, and suffers from timing variations between the frame rate at which the recording took place versus the frame rate at which the playback takes place.

Due to these variations, the simulation might not be exactly as you expect when you play back the recording. In a real app, you’d want to use a more advanced algorithm that takes into effect timing, and perhaps has periodic checkpoints of player state.

Setting the LED Player Indicator

One last minor thing. You can control the state of the LED lights on the controller. These lights are there to indicate which player is controlled by that controller.

In toggleHardwareController, right after this line:

self.controller = [GCController controllers][0];

Add this line:

self.controller.playerIndex = 0;

This will set the value on the controller for the playerIndex to 0. This does two things, it should set the LED indicator on the controller (on the SteelSeries it didn’t work consistently for me, but it worked fine on the MOGA).

Secondarily, it will remember the playerIndex for that controller. So, if you disconnect that controller, then reconnect it again later, that hardware will still identify itself to the GameController framework as playerIndex 0. If you want to clear the playerIndex (and I recommend that you do when you are finished with a controller), you set the playerIndex value to GCControllerPlayerIndexUnset. This constant is the default value when a controller is connected.

Build and run, and check out the LED!

Where To Go From Here?

You can download the final project here.

Now that you understand hardware controllers, you should add support into your games! There are more than a hundred games now that support hardware controllers, with hopefully many more to come.

To learn more about hardware controllers, check out Apple’s Game Controller Programming Guide.

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

iOS 7 Game Controller Tutorial is a post from: Ray Wenderlich

The post iOS 7 Game Controller Tutorial appeared first on Ray Wenderlich.

Video Tutorial: Scroll View School Part 6: Content Insets and Content Offsets

Video Tutorial: Scroll View School Part 7: Paging Scroll Views

Documenting in Xcode with HeaderDoc Tutorial

$
0
0
Learn the best practices for documenting your code!

Learn the best practices for documenting your code!

When Xcode 5 and iOS 7 were announced, a small addition was mentioned that most people might have missed: HeaderDoc.

HeaderDoc is a command line tool that you can use to automatically generate nice HTML documentation for your code – as long as you structure your comments in a particular way.

In addition, Xcode parses HeaderDoc-style comments behind the scenes to automatically present your documentation in quick look panels.

In this HeaderDoc tutorial, you will learn how to:

  1. Write HeaderDoc-style comments
  2. Preview your documentation in Xcode
  3. Generate HTML documentation from your comments
  4. Learn about a third-party tool to make documentation even easier (VVDocumenter-Xcode)

Let’s get documenting!

Getting Started

Download the starter project for this tutorial, and build and run. It should look like this:

RW_Documentation_Initial

This is a simple little test project that includes two main helper classes:

  • Car: Contains a few properties, and a method to “drive” a car and run a block upon completion
  • MathAPI: Contains a helper method to add two numbers

Right now, these files are barely documented. Let’s see how you can use HeaderDoc to make creating documentation for these classes super easy.

HeaderDoc Comments

HeaderDoc is a tool that you can either run from the command-line, or is automatically run by Xcode. Basically it scans your files for comments made in a particular style.

There are three styles of comments that HeaderDoc scans for:

Option 1:

/// Your documentation comment will go here

Option 2:

/**
 * Your documentation comment will go here
 */

Option 3:

/*!
 * Your documentation comment will go here
 */

Note that these are similar to “normal” comments, except that there’s an extra / in option 1, and an extra character in the first line of options 2 and 3 (* and !, respectively).

Note: In options two and three, there is an additional asterisk on each line in-between the required opening and closing lines. This is purely aesthetic, and is not required.

All three syntaxes will produce the same result, if done in Xcode.

Since we could start a small war over which way is the “best” way to document your code, we’ll stick with the following rules for the purposes of this tutorial:

  • For large comment blocks, use the style used in Apple’s documentation (/*!)
  • For single line comments, use the triple forward slash syntax (///) comment to save room

HeaderDoc Tags

Once HeaderDoc finds a comment in one of the above styles, it will search that comment for tags for more information. You will use tags to mark-up your code.

A tag starts with the @ symbol and a keyword, followed by a space, and a string that contains a description relative to that keyword (such as @param foo). There are two levels of tags:

  • Top-Level Tags: These are tags that declare the type of thing you are commenting (Headers, classes, methods, etc.)
  • Second-Level Tags: These tags help to give more detail about the specific thing you are commenting.

An example of a top-level tag is @typedef, which you use to indicate typedefs for things like enums, structs and function pointers.

HeaderDoc is pretty good at adding Top-Level tags automatically via the context, so they are generally optional. In this tutorial, you’ll focus mostly on Second-Level tags.

Let’s take a look at some helpful Second-Level tags:

  • @brief: Quickly describes the data type, method, etc. that you are documenting.
  • @abstract: Equivalent to @brief.
  • @discussion: Similar to @abstract and @brief, but it allows multiple lines. It’s not required to actually write this keyword out; but it is good to use for clarity’s sake.
  • @param: The name and description of a parameter to a method, callback or function.
  • @return: A description of what a method or function returns. (You can also use the equivalent @result)

This is by no means all of the tags, and you can find all of the available tags in the HeaderDoc User Guide.

For the sake of this tutorial, all comments will be placed in the header files, just to keep the implementation files clean.

Documenting Properties

Let’s start by documenting a few properties.

Back in Xcode, in the DocumentationExamples project, open ViewController.h. You’ll see two properties that are lacking some documentation. Just above the declaration for the car property, add a comment block so that it looks like this:

/*!
 * @brief The ViewController class' car object.
 */
@property (nonatomic) Car *car;

Now, build your project. When it finishes, hold the option key, and click on the car variable name. You should see a popover with your comment.

RW_Documentation_FirstComment

Troubleshooting: If your popover didn’t contain your comment, you may not have waited long enough for the project to build. If it has finished, try restarting Xcode, just to make sure.

Since that was so easy, try adding a documentation comment to the other property in ViewController on your own. It should say something about how this is a title that is supposed to be funny.

Solution Inside: Solution SelectShow>

Before you complete the remainder of your documentation, check out another way to view documentation in Xcode. Open the Utilities panel’s Quick Help Inspector. Now click on the “car” variable name. In the Quick Help Inspector, you should see your comment appear:

RW_Documentation_QuickHelp

Now, there are two more classes that need to be documented: MathAPI, and Car.

Documenting Methods

MathAPI includes a method that needs to be commented, so open MathAPI.h.

Examine the method addNumber:toNumber:. It returns a value and takes two parameters. So you’ll need to add a @description tag, two @param tags and a @return tag. Go ahead and create a comment that looks like the following:

/*!
 * @discussion A really simple way to calculate the sum of two numbers.
 * @param firstNumber An NSInteger to be used in the summation of two numbers
 * @param secondNumber The second half of the equation. 
 * @return The sum of the two numbers passed in.
 */
+ (NSInteger)addNumber:(NSInteger)firstNumber toNumber:(NSInteger)secondNumber;

Now, Build the project again then option-click on part of the method name to see your handiwork.

Screen Shot 2014-04-05 at 5.31.52 PM

Troubleshooting: Many symbols are option-clickable in the Xcode text editor. Make sure you click on the thing you want to get help on. In the above example, you’ll need to click on either “addNumber:” or “toNumber:” to see the correct help.

Now, unbeknownst to you, I’ve created a pretty terrible implementation of this method. It will only really work with non-negative numbers. To inform the user of this method of that, you can add a little more information to your comment. In this case, let’s add a @warning tag. Add the following text just above the @return tag:

 * @warning Please make note that this method is only good for adding non-negative numbers.

Now, build your project again, and option-click on the method name when it finishes. You’ll see a nice warning to the user.

RW_Documentation_SecondComment

Making Your Life Easier: Code Snippets

That was really fast, no? But what if you could make that process faster?

There’s something that’s been mentioned before on the site, and on the the raywenderlich.com podcast: code snippets.

Code snippets are one of the unsung heroes of Xcode. A snippet is a block of code that you can save, to a snippet library, and reuse over and over again. Snippets can even contain placeholders for you to know what you need to fill in. What’s that you say? You want a snippet for documenting your code? Fabulous idea.

In MathAPI.h, copy and paste in the following, just before the comment you already have:

/*!
 * @discussion <#description#>
 * @param <#param description#>
 * @return <#return description#>
 */

Notice that when you copied or wrote out the code, the parts that had “<# #>” around them became tokens that you could tab between. It’s exactly the same thing when you use autocomplete for your code.

Screen Shot 2014-04-05 at 5.35.35 PM

The next part may be a little tricky. You’ll need to select the Code Snippet Library in the Utilities panel, highlight your comment block, and drag the text to the Code Snippet Library section (by dragging from one of the placeholder text areas like <#description#>):

RW_Documentation_CreateSnippet

A popover will appear that lets you edit some information about the snippet and create an autocompletion shortcut. It will even let you edit the code. Fill out the information as you see it below:

RW_Documentation_EditSnippet

If you ever need to change the code or autocomplete shortcut, you can always go back and do it later. Feel free to change it however you’d like, or make new ones. To edit the snippet, click on it in the Code Snippet Library, then click the Edit button.

To see your new snippet in action, delete the comments you added for addNumber:toNumber:, place your cursor to the left of the “+”, type doccomment, and hit enter. Your snippet text will appear.

Tab through the three tokens filling out each one to complete your documentation as follows:

/*!
 * @discussion A really simple way to calculate the sum of two numbers.
 * @param firstNumber An NSInteger to be used in the summation of two numbers.
 * @param secondNumber The second half of the equation.
 * @warning Please make note that this method is only good for adding non-negative numbers.
 * @return The sum of the two numbers passed in.
 */

Note you’ll need to still manually add a second @param tag and the @warning tag, but this snippet still saves a ton of time.

You’re doing great so far. See, this documentation stuff isn’t so bad after all!

Documenting Typedefs

Open Car.h. You’ll see there are a few more things here than the previous class. There’s an NS_ENUM, typedef enum, a block, multiple properties, and a void method. Don’t freak out – it’s still really easy to document a class with more than one or two things in it. :]

Remember the @typdef tag? This Top-Level tag is a little special. It can be used to document things like enum typedefs and struct typedefs. But depending on what you are documenting, it should only contain Second-Level tags that match the type being defined.

For enum, you’ll want to include the @constant tag for each constant you have. (For struct, you would include @field tags.)

Find the enum OldCarType. It has two constants, and these should always be really old cars. Above the typedef declaration, replace the existing comment so that it looks like this:

/*!
 * @typedef OldCarType
 * @brief A list of older car types.
 * @constant OldCarTypeModelT A cool old car.
 * @constant OldCarTypeModelA A sophisticated old car.
 */
typedef enum {
    OldCarTypeModelT,
    OldCarTypeModelA
} OldCarType;

Build, and option+click on OldCarType. You’ll notice your popover has the information from your @brief tag. Now, option+click on OldCarTypeModelA. Did you see your comment? Queue the sad music. :[

But fear not, you can still get your information where you need it - we've got the trusty triple forward slash in our tool belt. Add the comments to the enum like you see here:

typedef enum {
    /// A cool, old car.
    OldCarTypeModelT,
    /// A sophisticated older car.
    OldCarTypeModelA
} OldCarType;

When you build, and option+click, you'll now see your comment.

Since there's an NS_ENUM in the class, go head try documenting it on your own. The constants are already documented, it just needs to be commented overall.

Solution Inside: Solution SelectShow>

Note: Since this enum is created through a macro, sadly Xcode doesn’t actually give you the same documentation features as a traditional typedef enum, even though NS_ENUM is the recommended way to make enums. Perhaps one day this will change, but for now, that’s the way it is.

Now take a minute to document the carType property. Add the following line above it’s declaration, so it looks like this:

/// Indicates the kind of car as enumerated in the "CarType" NS_ENUM
@property (nonatomic, assign) CarType carType;

Build again and then view your shorthand documentation by option-clicking the carType variable name.

Moving on, there’s also a typedef block in Car.h. Commenting a block is no more difficult than anything you’ve done so far. Add the text below so it looks like this:

/*!
 * @brief A block that makes the car drive.
 * @param distance The distance is equal to a distance driven when the block is ready to execute. It could be miles, or kilometers, but not both. Just pick one and stick with it. ;]
 */
typedef void(^driveCompletion)(CGFloat distance);

Notice that it’s not too different from anything else. It has:

  • A @brief tag, giving a very simple explanation about the block.
  • A @param tag, to let you know that you’ll need to pass something as a parameter when you call the block

Adding Formatted Code to Your Documentation

Sometimes, it’s nice for a programmer to have an example of how to use a method.

To try this out, you’re going to document the Car class’ driveCarWithCompletion: method. This method takes a block as a parameter, and it might be a good idea to show a programmer how to use it – since blocks seem to be a little hard for new developers.

For this, you can use a @code tag. Add the following in Car.h above the driveCarWithCompletion: declaration:

/*!
 * @brief The car will drive, and then execute the drive block
 * @param completion A driveCompletion block
 * @code [car driveCarWithCompletion:^(CGFloat distance){
     NSLog(@"Distance driven %f", distance);
 }];
 */

Build, and option+click the method name. You should see a nicely formatted code block in the popover. Beauty comes in many forms, readers.

RW_Documentation_Code

Checking Yourself

Now that you’ve learned how to comment, wouldn’t it be nice if Xcode would check your work, much the same way it checks if your code is typed correctly? Good news! Clang has a flag (“CLANG_WARN_DOCUMENTATION_COMMENTS”) that you can set to make Xcode check your HeaderDoc style comments.

In Xcode, open the DocumentationExamples Project Settings, click the Build Settings button at the top, search for Documentation Comments, and set the value to YES.

RW_Documentation_Warnings

To see it in action, open to MathAPI.h, and change your first @param tag’s parameter name to thirdNumber, instead of firstNumber, then Build.

RW_Documentation_WarningEx

Notice that a warning was generated and even gave you an auto-fix option to change the variable to the correct name. While it won’t catch everything, it can be very useful to double check yourself.

Special Types of Comments

While using HeaderDoc style comments to document your code is useful for yourself and others, there are a few other special types of comments Xcode supports. These are really useful for you, or others that work in your code.

Open Car.m and in driveCarWithCompletion:, paste the following three comment lines above the call to completion:

// FIXME: This is broken
// !!!: Holy cow, it should be checked!
// ???: Perhaps check if the block is not nil first?

you have added three different types of comments here:

  • FIXME: A comment to yourself that something needs to be fixed.
  • !!!: A comment that something needs attention.
  • ???: A comment that there is a question about the code. Or, the code is questionable.

Not only are these types of comments useful to see as you go through code, Xcode recognizes them, and will show them in the Jump Bar at the top of the editor. Select the method menu from the Jump Bar, shown here:

RW_Documentation_JumpBar

Once you do, you’ll see the three comments you entered, bolded, with the text of your comment:

RW_Documentation_JumpBarSelect

With all of this, you’ve learned enough to document the rest of this project.

Take some time to practice on the other properties and methods included in the project, and try adding a few things yourself. See what happens when you change things around in your comment blocks, or if you leave a tag out. It’s important to know how your formatting will impact your documentation.

Creating HTML Documentation with headerdoc2html

All of this documentation magic is done with a tool called HeaderDoc. It’s already installed on your computer if you have Xcode installed. Not only does it parse your comments, making those cool popovers and Quick Help panels, it can also create HTML, XML and man pages containing your documentation.

You’ll focus on creating HTML files in this section. But if you want to learn more about all of the options for creating stand-alone documentation with HeaderDoc, check out Appple’s HeaderDoc User Guide.

Open Terminal by going to /Applications/Utitlities/Terminal. Once you do, navigate to the DocumentationExamples project folder. You can do this by typing in the following:

cd /path/to/your/folder

Make sure to enter the path to the top level folder that contains the Xcode project file. (“DocumentationExamples.xcodeproj”)

Now, create a set of HTML documentation files by typing in the following in Terminal:

headerdoc2html -o ~/Desktop/documentation DocumentationExamples/

You’ll see a lot of output in the Terminal. Once it finishes, go to your Desktop, and you’ll see a new directory named documentation. Open it up, and navigate to Car_h, and open index.html. Awesome – you have pretty docs!

Screen Shot 2014-04-05 at 5.58.18 PM

So what just happened? Well, you ran the headerdoc2html script with 2 options:

  • -o ~/Desktop/documentation – This told the script to output its results to the documentation on your desktop.
  • DocumentationExamples/ – This told the script to only parse files in the DocumentationExamples/ folder inside the project folder. (There are other folders in the project directory that do not contain code files.)

Troubleshooting: You may find that with the latest versions of headerdoc2html and Google Chrome, that opening index.html does not correctly show the Table of Contents toc.html in the left sidebar. However, opening index.html in Safari should show both the documentation content and the Table of Contents correctly.

Also, you may have noticed that the documentation for the carType property you added earlier did not appear. It looks like the latest version of headerdoc2html does not correctly parse /// styled comments. For now, you might want to stick the /*! style.

That’s all really cool, but it gets better. Instead of having to navigate down into the output directory you want, HeaderDoc can create a master table of contents page for you. Back in Terminal, navigate to your new documentation directory by entering the following:

cd ~/Desktop/documentation

Now, to create the table of contents, enter the following:

gatherheaderdoc .

gatherheaderdoc will now search your documentation directory, indicated by the period (representing the current Terminal directory) in the command. In Finder, go back to your documentation directory. You’ll notice there’s a new file named masterTOC.html. Open this file in Safari. You’ll see a page that contains links to all of your documented properties, methods, enums and blocks.

Screen Shot 2014-04-05 at 6.01.35 PM

Now, you can host all of this HTML content on a web server, and give access to your documentation to anyone!

VVDocumenter-Xcode

Last up in our roundup of documentation tips is VVDocumenter-Xcode, a third party Xcode plugin that will make documenting even easier than using the Code Snippet you created earlier.

To get started, download the plugin from Github.

All you need to do is open the project, and build. As it builds, it will automatically install the plugin for you in your ~/Library/Application Support/Developer/Shared/Xcode/Plug-ins directory.

Once it finishes, restart Xcode, and open your DocumentationExamples project if it is not already open. In MathAPI.h delete the entire comment block for addNumber:toNumber:. Now, type the following above the method declaration:

///

Once you do, VVDocumenter-Xcode will automatically create a comment block with all of the necessary @param tags, with autocomplete tokens between all necessary fields.

RW_Documentation_VVDocumentor

Convenient, eh?

Now, go to Car.h and delete all of your comments for the CarType NS_ENUM, even the comments for each constant. Above the NS_ENUM declaration, type:

///

This time, it created the discussion section above the enum, and even put the necessary comments above each constant!

VVDocumenter-Xcode can make your life so much easier. If you want to customize VVDocumenter-Xcode, in Xcode, go to Window>VVDocumenter.

VW_Documentation_VVDocPrefs

Here, you can change the autocomplete keyword, the comment style, and more. Feel free to customize it however you’d like. I’ve found it saves a ton of time.

Where To Go From Here?

You can download the finished project from this HeaderDoc tutorial here.

As a challenge, go through some of your own code, and create documentation for yourself. Try using the code snippet you made, and VVDocumentor. See what fits your style, and how you can work it in to your workflow.

Also, be sure to check out Appple’s HeaderDoc User Guide for more information now that you know the basics.

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

Documenting in Xcode with HeaderDoc Tutorial is a post from: Ray Wenderlich

The post Documenting in Xcode with HeaderDoc Tutorial appeared first on Ray Wenderlich.


Video Tutorial: Scroll View School Part 8: UIPageViewController

Video Tutorial: Scroll View School Part 9: Sidebar Navigation

Readers’ App Reviews – May 2014

$
0
0
sbapix

May Readers’ Apps: Robots, Colors, and Vegetables?!

May has arrived and you guys really let the apps fly this month. There were 62 submissions this month!

It was a battle to narrow them down this month. After you finish trying the few I found time to review, you’ve got to give the Honorable Mentions a look as well. There were tons of great games and apps I didn’t have time to cover here in detail.

Highlights this month include:

  • Games that will make your head spin
  • Apps for you and your kids
  • Some tools I think all us power users need

What are you waiting for? Dive into over 60 apps from your fellow readers!

Rotatetris

Rotatetris
Rotatetris is a tetris style game with a big twist.

As balls are falling, its up to you to rotate your device to control where they land. Match three colors to eliminate them and clear some space.

With three different game modes, GameCenter leaderboards, and powerups to keep it interesting, this gyro-tastic game will keep you moving.

Quiver: The Programmer’s Notebook

Quiver
Quiver is a note taker’s dream. Quiver is a Mac app that lets you combine text and code snippets into notes.

Notes can be organized by tags and then grouped into notebooks. You entire note is editable inline anytime and your code snippets can be syntax highlighted in the language of your choice. Quiver supports super fast searching full text searching to find your notes fast.

And best of all, Quiver stores all your notes in plain JSON so you have full control of your content.

Rolling Zimro

Zimro
Rolling Zimro is a game that will have your head spinning!

Zimro is wanted in the galaxy for his unique knowledge of growing wisdom weeds. He’s running for his life from UFOs and aliens trying to capture him.

Rolling Zimro has beautiful low poly graphics across several spinning worlds. Run as far as you can collecting powerups to boost your GameCenter highscore and save Zimro.

I Love Vegie Classic

vegies
This is an awesome game for your kids. I Love Vegie Classic uses the front facing camera and face detection to create an awesome experience for kids.

The app tracks your mouth while vegetables fall from the sky. You’ve got to move your iPad or your mouth to make sure the vegetables end up in the right place.

Its a supremely fun and unique game that takes advantage of the iPad’s mobility. Everyone should give this game a try.

sbapix

sbapix
Sbapix is an awesome app to express your creativity.

Spapix uses a simple pixel grid and color wheel to let you design masterpieces of your very own. Its simple interface and bright colors make for a very relaxing artistic experience.

Spapix offers up any size pixel grid, color theory education, sharing, and a colorful way to use your iPhone.

Jetpack-Jones

JumpingJones
Jetpack-Jones is a side scroller that takes us back to the basics.

Jetpack-Jones takes simple controls for thrusting and blasting and sends you on a lunar adventure. Aliens, asteroids, and more stand between you collecting stars while you bounce along the moon’s surface.

Jetpack-Jones takes you back to a pixelated past of simple fun.

Siesta Testa

SiestaTesta
If you have kids who refuse to sleep, Siesta Testa is the app you’ve been waiting for.

Siesta Testa is a tool to track your kids batteries using special scanning technology. Show your kids how low their batterie are so they can understand the importance of getting a good nights rest early.

I love the idea of this app. Its a cute app well executed to help kids get to bed on time.

Robots hate Bugs

RobotsHateBugs
Robots absolutely hate bugs, incase you didn’t know.

Robots hate Bugs is a reflex game with three lanes of pain. Bugs crawl down to you and you launch Robots to defend yourself. But don’t launch too many Robots or you’ll blow up everything.

The game offers a unique experience that combines spam tapping with calculated control. Its difficult to master but easy to play.

Gfx Hotkeys

GFXHotkey
There are tons of visual creation applications these days and its getting hard to keep up with all their hotkeys.

Just intime GFX Hotkeys comes along as an excellent reference tool to keep track of all your hotkeys. GFX Hotkeys packs over 80 applications full hotkey sets.

With all those different applications its important to have it clearly organized to find what you need quickly. GFX hotkeys delivers with color coded applications and favorites to track your most used applications.

Rampaging Dragons

RagingDragons
Rampaging Dragons are attacking and you don’t want to be on the receiving end of a fireball!

Dodge hurly balls of fire with simple side scrolling controls. Watch out for the dragons themselves, they have something extra sinister for you. Between dodging fireballs find time to tap the dragons to hold back their fire.

Compete against friends’ highscores in GameCenter, but don’t get burned! ;]



Honorable Mentions

Every month I get flooded with more apps than I can handle. Its not a popularity contest or even a favorite picking contest. I thoroughly enjoy all of your apps but there is only so much time in the day. Active forum members get bumped to the top of the list, but otherwise just do your best and I’ll do mine to review as many apps as I can!

Splatty Bug
Archange
iMathGenius
EPICYCLE
Tiny Hop
Drawings
KnockToCall
The Holy Hand Grenade
Shifty – Calendar Assist
NotPong
Bodytrack.it
TraductoPro
SuYeeQu
Yoink
ScreenFloat
Briefly
Transloader
Do You Know Your USA?
2048 Slider
Flip Blip
Snapster
Permeate
BugStar
Word Match – The Language Game
Zippy Finger
Obstruction
Auto Pin
Car Pal
Front Flash:Selfie Camera
Jumping Josh
ChargedUp!
Flappy Duck – Fly Home
Eco Recorder
TapTrap
Von Neumann
I Love Fruit Classic
Bricks
Do Not Collide
iMathGenius
Math Trick
Young June Jung
Bombs and Sombreros
Who let the bird out ?
Space-Rocket
Iggy Bubble
Scored – A Better Sports App
Face Yoga Bear
Onboard Camera
Word Connectz
Taskiary



Where To Go From Here?

Another month, another group of excellent apps. We love seeing what our readers build each month.

If you’ve never made an app, we’ve got you covered! Check out our free tutorials to become an iOS star. What are you waiting for – I want to see your app next month!

If you’ve already made the next great app, let me know about it. Submit here!

Readers’ App Reviews – May 2014 is a post from: Ray Wenderlich

The post Readers’ App Reviews – May 2014 appeared first on Ray Wenderlich.

Video Tutorial: Scroll View School Part 10: Pull to Refresh (Part 1)

Cookbook: Using NSURLSession

$
0
0

Get started quick with NSURLSession!

Welcome to cooking with Chef Charlie!

Tonight’s menu doesn’t include smoked trout; but it does include three recipes for working with NSURLSession.

In this cookbook-style tutorial, you will learn how to download data, download an Image, and post data all using the NSURLSession suite of classes. Bon Apetit!

What do you need?

  • NSURLSession
  • Some data or images to download
  • A web service to POST data to
  • 5 minutes

Download some data

Downloading data from a web service is a very common task. NSURLSession makes this very easy. Check out the following code snippet

// 1
NSString *dataUrl = @"YOUR_DATA_URL";
NSURL *url = [NSURL URLWithString:dataUrl];
 
// 2
NSURLSessionDataTask *downloadTask = [[NSURLSession sharedSession]
  dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
  // 4: Handle response here
}];
 
// 3
[downloadTask resume];
  1. Specify a URL that can return XML, a plist, JSON, etc.
  2. Create an NSURLSessionDataTask using the NSURLSession shared session. The data task is the object that does the work for you.
  3. All of the the different tasks from NSURLSession start in a suspended state. Start the task here.
  4. Handle any response in the completionHandler.

Download an Image

NSURLSession also makes it incredibly easy to download Images.

//1  	
NSURL *url = [NSURL URLWithString:
  @"http://upload.wikimedia.org/wikipedia/commons/7/7f/Williams_River-27527.jpg"];
 
// 2	
NSURLSessionDownloadTask *downloadPhotoTask = [[NSURLSession sharedSession]
 downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
  // 3 
  UIImage *downloadedImage = [UIImage imageWithData:
    [NSData dataWithContentsOfURL:location]];
}];
 
// 4	
[downloadPhotoTask resume];
  1. Specify the URL of a photo. Use this one of our great fishing spot. Or you can substitute your own.
  2. Create a task from the NSURLSession. This time create a download task.
  3. An NSURLSessionDownloadTask downloads the file to a temporary location on the iOS device. In the completionHandler, you can save this file permanently. Check out the sample app code at the end of the tutorial to see how to save the image to your Photo Album.
  4. I guarantee that you will forget to start a task when working with NSURLSession :]

Posting data

You should now have a good grasp on how to download data. If you need to post data to a web service, NSURLSession can handle that too.

Until now, you have been using the convenience method [NSURLSession sharedSession] to create NSURLSessionTasks on a pre-configured session. This time, you will create a configurable NSURLSession using an NSURLSessionConfiguration object, so that you can set any attributes you may need (such as HTTP header attributes).

 
// 1
NSURL *url = [NSURL URLWithString:@"YOUR_WEBSERVICE_URL"];
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
 
// 2
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
request.HTTPMethod = @"POST";
 
// 3
NSDictionary *dictionary = @{@"key1": @"value1"};
NSError *error = nil;
NSData *data = [NSJSONSerialization dataWithJSONObject:dictionary 
  options:kNilOptions error:&error];
 
if (!error) {
 // 4
 NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request
   fromData:data completionHandler:^(NSData *data,NSURLResponse *response,NSError *error) {
   // Handle response here
   }];
 
   // 5
   [uploadTask resume];
}
  1. First, create the NSURLSessionConfiguration and then create a session with that configuration. This allows you to create a session with specific attributes set on it. For example, your web service might require you to set an API key in the HTTP Header (see the sample project.) Note that the configuration property of an NSURLSession is read-only so any configuration needs to be done before creating the session.
  2. All of the NSURLSessionTask subclasses can be created using either an NSURL or an NSMutableURLRequest. Here, create an NSMutableURLRequest so that you can specifically set the request to be a POST.
  3. Create a JSON representation of the dictionary you will post to the web service.
  4. If everything goes OK, create the NSURLSessionUploadTask using the JSON data you created in the previous step. This will make an HTTP POST with the body set as JSON data.
  5. Don’t forget! (You will)

TroutTrip: Sample project

Well, we didn’t have any smoked trout to cook up this time. But we do have a sample app where you can track your own fishing adventures.

You can download the TroutTrip source code here. This simple application will show you all three of the above recipes by doing the following:

  1. Download weather data for our trout fishing location in RWWeatherDataTaskViewController.m. This sample uses the forecast.io API (Dark Sky’s)
  2. Download a photo of our fishing spot in RWLocationDownloadTaskViewController.m
  3. Post your notes about the “one that got away” to a Parse.com backend. RWStoryUploadTaskViewController.m

Note: You will need to provide your own API keys for forecast.io and parse.com. There are #warning pragmas in the code to show you where to enter your API keys. And, there are some helpful URLs there to follow to get more information on the two services.

Where To Go From Here?

You have just scratched the surface of what’s available with NSURLSession. For further information and examples check out these other great resources:

Cookbook: Using NSURLSession is a post from: Ray Wenderlich

The post Cookbook: Using NSURLSession appeared first on Ray Wenderlich.

Video Tutorial: Scroll View School Part 11: Pull to Refresh (Part 2)

Video Tutorial: Scroll View School Part 12: Pull to Refresh (Part 3)


Top 5 iOS 7 Animations

$
0
0
MainImage

Welcome to our Top 5 iOS 7 Animations!

We recently had a call for nominees for the best animations introduced by apps in iOS 7.

Well, after tons of great nominations and careful consideration, we have selected our choices for the Top 5 iOS 7 Animations from the past year! The quality of apps nominated for this article were outstanding, making the final decision incredibly difficult.

Because the apps were such great quality, I would like to thank judges Kirill Muzykov, Ricardo Rendon Cepeda, Rocir Santiago, and Tammy Coron who volunteered to collectively decide these top five winners. It was no easy task!

Also, a big thank you to the readers who nominated animations in the first article. Without you all, this article would not have been possible.

Without further ado, here are the Top 5 iOS 7 Animations!

5. Flight

Flight is a utility app that informs you of a variety of information regarding your flights. The developers did a great job at packaging this information in an app that is useful and looks great too.

FlightInfo

In this animation, information regarding the flight, such as the type of plane and the duration, protrudes from the bottom of the screen, pushing the main flight label up to the top of the screen. Any other labels fade out, making way for the new information to be presented.

FlightPlanes

As seen in the first article, the planes gracefully fly in and out of the presented views. Also, if you look closely at views like the flight number and the terminal, the information changes with a great cube-like animation. As the transition begins, the views fold back to show the new information.

Overall, the animations in this app are very high quality and greatly improve the user experience.

4. Taasky

Taasky is a To-Do list that uses animations extensively to engage the user.

TaaskySelectList

In this animation, the four list icons pop in like bubbles. Coming in one after another with the currently selected choice highlighted, this presentation looks great, clearly delivers the content to the user, and makes the app fun to use.

TaaskyFoldingNavAndNew

The folding effects in Taasky are also very impressive. When a new task is added, or the navigation bar is revealed, these new views are presented like they are unfolding from a cube. In addition to the 3-D effect, take a look at the top left bar button item while the navigation bar is unfolded. The rotating icon adds clarity to the user interface and adds a nice touch to top off the cube effect.

3. City Guides

City Guides, by National Geographic, is an app for tourists in some of the world’s most famous cities, including New York City, London, Paris, and Rome. It informs the user about places to see, currency conversions, facts about the city and its history, and much more.

CityGuideSwipe

The city-picker in this app is a customized collection view. The items rotate 3-dimensionally around the center on their entrance and exit. The effect acts like a carousel rotating around you— notice the items appearing to grow as they exit the screen, like they are actually getting closer.

CityGuidesStatistics

Here is another very interesting animation. As views go offscreen, you can see the numbers decrease rapidly to 0, and as the views come back to the screen, they return to their original values. This dynamic behavior really looks great and leaves a strong impression on the user. It fits perfectly into the user interface in a non-disruptive way.

Thanks filipzamorsky for pointing out this great app!

2. Flickr

Flickr, built by Yahoo’s fantastic iOS development team, is a great example of the company’s efforts to become more relevant on mobile platforms.

FlickrPullToRefresh

While many apps have pull-to-refresh controls, Flickr’s animation looks great and changes according to the current user’s profile. When the animation begins, the profile picture rotates with the other sphere, and when the loading is finished, the picture returns to the spotlight. The rotating spheres are eye candy while you are waiting for your content to load.

FlickrIntro

Lots of apps have tutorials/introductions when they first start, but Flickr’s is the most impressive that I have seen, especially because of the great 3-D effects. Of these effects, the camera stands out the most to me.

1. Paper

Paper claims our title as the Best iOS 7 Animations app. The developers at Facebook clearly put a lot of time and effort into making this app look great – even developing their own open source animation API!

PaperSections

The sections at the top have a fun free-floating animation. When a new section is dragged up to the top row, the other sections make room for the new item while continuing to “float.” The bottom row also has a similar animation to City Guides where the items rotate around a point below the screen.

PaperOpenArticle

This paper-folding animation is the most recognizable aspect of Paper. The article folds and unfolds according to how far your finger pans on the screen, and locks into place once you have pulled far enough in either direction. While Paper is not the first to use this animation on iOS, the developers put a lot of effort into perfecting this great paper-like effect.

But Wait! There’s More!

We have received several requests for more tutorials covering animations, especially since the Call for Nominees was announced. Because of this, we are going to cover how you can implement similar animations to the ones listed above.

Starting today, you can vote on one animation from the apps listed above to be featured in a future tutorial. Instead of more generic tools and techniques, the tutorial will focus specifically on the animations from the app.

What are you waiting for? Vote now!

Note: There is a poll embedded within this post, please visit the site to participate in this post's poll.

Where To Go From Here?

If you want to see more interesting animations like these, I recommend looking at capptivate.co. This site has been putting together a very respectable compilation of iOS animations for quite some time.

Next time you are planning to release your app, make sure to think about your user experience. Is there anything in your app that stands out or leaves a good impression? If not, try adding some animation just to spice things up. A little animation can go a long way.

Animation allows these apps to really engage the user and create great experiences. Maybe next time it will be your app that really catches our eyes!

Top 5 iOS 7 Animations is a post from: Ray Wenderlich

The post Top 5 iOS 7 Animations appeared first on Ray Wenderlich.

Video Tutorial: Scroll View School Part 13: Sprite Kit Integration

raywenderlich.com at AltConf!

$
0
0
We hope to see you at AltConf!

We hope to see you at AltConf!

Are you super excited about WWDC next week? I know we are!

Well, there’s one more thing to be excited about too: AltConf! AltConf is a free, community-driven iOS conference running next week, right across the street from Moscone West. It’s split into two parts:

  • AltConf talks are in the Children’s Creativity Theatre
  • AltConf labs are Jillian’s

Myself and several members of the team are going to be participating in AltConf this year, and have some fun things ready for you. Keep reading to find out what’s in store!

1-on-1 Tutorials

First, on Monday 6/2 from 1PM-4PM (after the WWDC keynote) we’ll be offering something special at the AltConf labs in Jillian’s: 1-on-1 Tutorials!

Drop in and pick from our menu of 1-on-1 tutorials:

Alt_1on1_tuts

We’ll give you a live walkthrough of your chosen subject, with a cool demo and supporting material, doing their best to tailor the content to your interests and skill level. It should be a blast!

AltConf Talks

Several of us from the team will also be giving talks at AltConf. I’ll be giving a talk where I start with a game loosely based on a tutorial by Toby Stephens:


And then show you how to add “juice” to turn it into a game like this:


Special note for subscribers: I will be making a video tutorial series on this soon too :]

Also, upcoming book author Saul Mora will be giving a talk on “Are we doing what we should be with our time?”, and Code Team member Orta Therox will be giving a talk on “Project Eigen Post Mortem.”

You can see the full AltConf talk schedule here.

Hope to See You There!

AltConf is shaping up to be an amazing conference – whether you got a WWDC ticket or not. We can’t wait to see you there!

raywenderlich.com at AltConf! is a post from: Ray Wenderlich

The post raywenderlich.com at AltConf! appeared first on Ray Wenderlich.

Video Tutorial: Scroll View School Part 14: Sprite Kit Level Selector

Reminder: WWDC Keynote – Podcasters React Live Today!

$
0
0
Free live tech talk (Procedural Level Generation in Games) tomorrow!

Free live tech talk (Procedural Level Generation in Games) tomorrow!

This is a reminder that today immediately following the WWDC keynote, we have a special live tech talk for you.

It’s titled WWDC Keynote – Podcasters React!

Our podcasters will discuss all of the highlights of the WWDC keynote and give their reactions. We’ll also have live Q&A to hear your questions and reactions as well. This should be a blast!

  • When: Today, June 2nd at 3:00 PM EST – 4:00 PM EST
  • What: WWDC Keynote – Podcasters React! followed by live Q&A (come w/ comments and questions!)
  • Who: Podcasters Tammy Coron, Jake Gundersen, Felipe Laso Marsetti, and Mic Pringle
  • 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: WWDC Keynote – Podcasters React Live Today! is a post from: Ray Wenderlich

The post Reminder: WWDC Keynote – Podcasters React Live Today! appeared first on Ray Wenderlich.

Viewing all 4373 articles
Browse latest View live


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