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

Travis CI Tutorial: Getting Started

$
0
0
Automate tests with Travis CI

Automate tests with Travis CI

You’ve got 99 problems, and testing is one of ’em!

Developers know that testing an application thoroughly is necessary to catch problems before they affect users. Forgetting to test can result in complications like annoyed clients, ranting one-star reviews in the App Store, and bruises from smacking yourself in the head for letting simple mistakes slip through the net.

But remembering to run tests before each commit or merge can be tough if you have to do it manually. What’s a time-crunched developer to do?

Continuous Integration

Thankfully, Continuous Integration can save the day. Continuous Integration, often abbreviated to just CI, is the process of automatically building and running tests whenever a change is committed.

Now, Apple has their own solution for this with Xcode Bots, which are designed to run on OS X Server. But the downside of Apple’s solution is that you, yes you have to manage the entire process. You have to set up and maintain OS X Server and Xcode versions on the server, figure out access control for viewing results, and handle provisioning and signing issues. Sounds like a lot of work, right? You don’t have time for this; you have code to write, apps to design, and happy hour to get to – that beer isn’t going to drink itself.

Shout it to the cosmos with me: there must be an easier way!

Travis CI

Luckily, the cosmos heard us, and responded with Travis CI.

What is Travis CI?
Usually simply called Travis, it’s a Continuous Integration service that is free for open-source projects and has a monthly fee for closed-source projects based on how many simultaneous builds you want to run.

What does it do?
Travis sets up “hooks” with GitHub to automatically run tests at specified times. By default, these are set up to run after a pull request is created or when code is pushed up to GitHub.

In this Travis CI tutorial, you’ll use a public GitHub repo and the free version of Travis to set up tests that run every time you try to merge new changes into that repo.

Note: this tutorial assumes that:
  • You already have a GitHub account. If you don’t, sign up for a free one here.
  • Git is installed on your system. You can check this by opening up Terminal and typing which git. If there’s a result – typically /usr/bin/git – then you’re good to go. If not, you can download an installer from the Git website here.

Getting Started

Let’s do this! Download the starter project, then open up the zip file and put the resulting MovingHelper folder on your Desktop so you can find it easily. MovingHelper is a to-do list app which, as you might suspect from the name, helps manage tasks related to moving.

Build and run your project in Xcode; you’ll see the following:

iOS Simulator Screen Shot Jul 11, 2015, 9.46.21 PM

Use the picker to choose a date a little less than a month from the current date, then tap the Create Tasks button. You’ll see the following:

simulator_task_list

The app has created a list of tasks. The red sections are past-due tasks, while the green sections are upcoming tasks.

Looking through the code, you’ll see that a few tests have been set up. Execute the tests by using the Command-U shortcut, and they will quickly run and pass:

xcode_test_succeeded

So far so good, right? Now that you know the tests are passing, you’re ready to get GitHub and Travis set up to run them automatically.

Setting Up Git and GitHub

First, you’ll create a local Git repo with the files in the starter project. Fire up Terminal, then change the directory to your desktop folder:

cd ~/Desktop/MovingHelper

Next, initialize a local repository on your computer:

git init

Next, add everything in the MovingHelper folder – since you’re already in it, just type:

git add --all

Finally, commit all the code:

git commit -m "Starter project from raywenderlich.com"

Now that everything is committed locally, it’s time to create a public repository on GitHub. This is what Travis will watch for changes.

Note: Leave this Terminal window open as you’ll need it again later, and it’ll save you having to navigate back into the appropriate folder.

Head over to github.com and make sure you’re logged in to your account. In the top right corner of the page, there’s a plus sign with a little down arrow next to it – click it and select New repository:

github_add_repo

You will see a page to set up the new repository:

github_repo_add_screen

The owner will be you. Name the repo MovingHelper, give it a brief description, make sure it’s public, and don’t add a README, license, or .gitignore as these are all included in the sample project. Next, click the big green Create repository button. You’ll see a page explaining how to get your code to GitHub.

github_after_add_screen

Leave this page open in a tab of your browser – you’ll want to come back to it shortly.

Set Up Travis

Open a new tab in your browser and go to travis-ci.org to get started using the free version of Travis. In the upper right corner is a button which allows you to sign in using your GitHub account:

travis_sign_in_with_github

Use this button to sign up for Travis. Since you’re already signed in to GitHub, you should not need to sign in again. If you haven’t already signed up for Travis, you’ll need to agree to the permissions they request:

travis_permissions

Travis needs access to read and write webhooks, services, and commit statuses. That way that it can create the automated “hooks” it needs to automatically run when you want it to.

Click the green Authorize Application button. GitHub will ask you to verify your password:

Screen Shot 2015-07-11 at 11.05.03 PM

Enter your password and click Confirm password. Now you’re on the Travis “getting-started” page.

Your avatar and GitHub username are in the upper right hand corner:

travis_account_icon

Click that to be taken to your Travis profile page. You’ll see an alphabetical list of all your public repos. If you haven’t set up Travis previously, they should all be unchecked.

Scroll down to MovingHelper:

travis_switch_off-700x106

Flick the switch to turn it on:

travis_switch_on-700x106

There! Travis is now watching for changes to your MovingHelper repository.

Pushing to GitHub

Go back to the tab with your newly created GitHub repo. Copy the commands from the “…or push an existing repository from the command line” section:

github_after_add_screen_highlighted-676x500

Note: Use what’s on your repo, not what’s shown in the screenshot, since you will need to push to the remote that’s tied to your GitHub username, not mine. :]

Copy the text from that section either manually or by clicking the clipboard icon on the right, then paste it into Terminal and press enter. This adds your new GitHub repo as a remote and pushes everything up to it.

Since Travis is now watching this repo, it will notice this push and put a build in the line of all the other open source builds waiting to be run.

Note: Builds on the open-source version of Travis may take a while to run – you’re basically in line with anyone else running open-source tests. And unlike at the Post Office, you can’t skip in line by pretending you’re late for your kid’s dance recital. ;]

Whenever your tests run, you’ll get an email that contains something like this:

travis_initial_build_fail_email-700x338

Ruh roh! What happened? Click on the big Build #1 Failed to be taken to the results of the failed build:

travis_initial_fail_details-700x354

That warning at the bottom contains one specific line that explains why the build failed:

Could not find .travis.yml, using standard configuration.

What does that mean? Well, .travis.yml file uses YAML to tell Travis how to set up a build. Since Travis works with many different languages, it doesn’t know how to build your specific project without some information about what kind of project it is.

To get a quick look at some of Travis’ best features requiring very little configuration, check out a new branch from the command line by typing the following into Terminal:

git checkout -b travis-setup

Terminal will confirm that you created and checked out a new branch:

Switched to a new branch 'travis-setup'

Next, open your plain-text editor of choice. TextWrangler is particularly helpful here because it highlights the syntax of YAML files automatically, but any plain-text editor will work.

Create a new document and save it in the root of your repo as .travis.yml.

Note: You may get a warning about names prefixed with a . being reserved for the system, but use the dot anyway – Travis will be looking for a file named exactly .travis.yml, so the dot is safe to use here.

Add the following five lines to your new .travis.yml file:

language: objective-c  #1
osx_image: xcode6.4 #2
xcode_project: MovingHelper.xcodeproj #3
xcode_scheme: MovingHelper #4
xcode_sdk: iphonesimulator8.4 #5

Note that YAML will disregard anything prefixed with a # as a comment. Here’s what you’re telling Travis to do with each line:

  1. Build a project using … Objective-C!? Don’t panic! Even though your project is in Swift, Travis only uses the objective-c value to know to build with Xcode command line tools. Since Xcode knows how to tell what’s in Swift and what’s in Objective-C, your Swift project will be just fine. :]
  2. Use the Xcode 6.4 tools to create the build, since you’re using Swift 1.2. This presently requires specifying which VM image you want to use – in this case xcode6.4.
  3. Use the specified Xcode project file. Note that if you have a project you want to build using an .xcworkspace (for example, a project using CocoaPods), you can replace the xcode_project parameter with xcode_workspace and use your .xcworkspace file as the value instead of your .xcodeproj.
  4. Use the specified scheme to decide what tests to run. Since your default scheme is called MovingHelper, Travis should use that scheme.
  5. Run the tests on an iPhone simulator, because doing so does not require setting up code signing (which is not covered in this tutorial).

Make sure your .travis.yml file is saved, then add and commit it to Git:

git add .travis.yml
git commit -m "Added .travis.yml file"

Next, push your branch up to your remote:

git push -u origin travis-setup

Reload the webpage for your MovingHelper GitHub repo. You should see something like this, indicating that the branch has made it up to GitHub:

github_branch_pushed

Click the green Compare & pull request button.

Note: If you don’t see Recently Pushed Branches, click the green button next to the branch name. Leave the base branch as master, but change the compare branch to travis-setup, and then click Create pull request.

Change the title of the pull request to Travis Setup:

github_open_pr_setup

Click the green Create pull request button, and Travis will automatically start working. As soon as your build completes, you’ll see something like this on your GitHub page:

github_travis_setup_fail

Argh! You’ve added the .travis.yml file like you were supposed to, so why isn’t it working?

Click one of the Details links to see the results of this build. A new error leads you directly to the problem:

travis_need_shared_scheme

D’oh! Travis knows the name of the scheme, but because it was automatically created and isn’t shared in your GitHub repository, Travis can’t see it. Fix that by going back to Xcode, and from the scheme drop-down, selecting Edit Scheme…

xcode_edit_scheme

When the scheme editor comes up, check the Shared checkbox at the bottom of the panel:

xcode_share_scheme-700x393

Click the Close button, then add and commit all shared data (which will include the new shared scheme):

git add MovingHelper.xcodeproj/xcshareddata
git commit -m "Added shared scheme"

Push up to GitHub again:

git push -u origin travis-setup

Since you already have an open pull request, Travis will immediately know that you added changes and start building again:

github_travis_waiting_to_hear

Once the build completes, you should see what you’ve been waiting for: green!

github_travis_success

All is well indeed. Click on Show all checks and the dialog will expand, showing you the builds which passed:

github_travis_success_expanded

Click on either Details link, and you’ll be taken to Travis’ output. You can scroll through and see the details of how your project was built and how your tests ran, but the bottom line – and the good news – is all the way at the end:

travis_initial_success

Each item with a green checkmark next to it is a passing test – and as you can see with the happy green text at the end, all of the tests are passing! Woohoo!

Go back to your GitHub page and click the green Merge pull request button, then click Confirm merge to officially merge your changes.

Hello, World!

Now that your tests are running automatically, it’s time to tell other people that your tests are passing by adding a badge to your README which shows the current status of the build on Travis.

Before you go too far, make sure you’re up to date with everything in your master branch:

git checkout master
git pull origin master

Switch back to your travis-setup branch and merge the changes from master into it:

git checkout travis-setup
git merge master

Now that the merge commit has been merged back into your travis-setup branch, open up the README.md file from the root folder of your project in your markdown or plain-text editor of choice.

Add the following lines to the end of the file:

####Master branch build status: 
![](https://travis-ci.org/[your-username]/MovingHelper.svg?branch=master)

Don’t forget to replace [your-username] with your actual GitHub username.

You’ve just added a link to a graphic which will be a “passing” or “failing” badge served up by Travis based on the status of your build for the branch specified in the branch URL query parameter.

Save the changes to the README, then add, commit, and push them up:

git add .
git commit -m "Add Travis badge to README"
git push origin travis-setup

Go back to the GitHub page. Follow the same steps as before to create a new pull request. Name this new pull request Badges, and click Create pull request.

Travis will once again do its business – and since you didn’t change any of the code, the tests will continue to pass:

github_travis_success

Again, click the Merge pull request and then Confirm merge buttons to merge your changes. Once merged, you’ll see your badge right on your main MovingHelper GitHub page:

github_has_badge

Breaking the Build

Now that you’ve gotten a couple of passing pull requests without changing any code, it’s time to take things to the next level: breaking the build. :]

Start by bringing your master branch up to date with the latest changes you just merged in:

git checkout master
git pull origin master

To see the problem you want to fix, build and run the application, and check off one of the boxes. Build and run again. The box is no longer checked. Oops!

When you get a report of a bug from a tester or a user, it’s a good idea to write a test that illustrates the bug and shows when it is fixed. That way, when the tests are run you can be confident that the bug hasn’t magically reappeared – commonly known as a regression.

Let’s make sure that when you mark a task done in the list, the app remembers. Create a new branch for this work and name it to-done:

git checkout -b to-done

Open up Xcode and go to the TaskTableViewCell.swift file. You can see in tappedCheckbox() that there’s a TODO comment instead of the actual code to mark a task as done. For the cell to communicate the task state change, it will need a reference to the task and a delegate to communicate the change to. Add variables for these two items below the outlets:

var currentTask: Task? 
public var delegate: TaskUpdatedDelegate?

Since cells are reused, clear the values of these variables before the cell is reused by overriding prepareForReuse() and resetting each value to nil:

public override func prepareForReuse() {
  super.prepareForReuse()
  currentTask = nil      
  delegate = nil
}

Add a line to the top of configureForTask(_:) to store the current task:

currentTask = task

Replace the TODO in tappedCheckbox() with code to mark the task as done and notify the delegate of the change:

if let task = currentTask {
  task.done = checkbox.isChecked
  delegate?.taskUpdated(task)
}

Finally, go to MasterViewController.swift, and in tableView(_:cellForRowAtIndexPath:), add a line just above where the cell is returned, setting the MasterViewController as the delegate of the cell:

cell.delegate = self

Build and run. Check off an item, then stop the app. Build and run again. Hooray, the item is still checked off!

Commit your changes:

git add .
git commit -m "Actually saving done state"

Automation

Now that you have fixed the bug, it’s time to write a test which Travis can run automatically. That way if things change, you’ll know immediately.

First, select the MovingHelperTests group in the Xcode sidebar, then choose File\New\File… and select the iOS\Source\Swift File template. Name this new file TaskCellTests.swift, and make sure it’s being added to the test target, not the main target:

xcode_add_to_test_target

Next, set up the basic test case class by replacing the existing import statement with the following:

import UIKit
import XCTest
import MovingHelper
 
class TaskCellTests: XCTestCase {
}

Add a test which verifies that when the checkbox in a TaskTableViewCell is tapped, the associated task is updated:

func testCheckingCheckboxMarksTaskDone() {
  let cell = TaskTableViewCell()  
 
  //1
  let expectation = expectationWithDescription("Task updated")
 
  //2
  struct TestDelegate: TaskUpdatedDelegate {
    let testExpectation: XCTestExpectation
    let expectedDone: Bool
 
    init(updatedExpectation: XCTestExpectation,
      expectedDoneStateAfterToggle: Bool) {
      testExpectation = updatedExpectation
      expectedDone = expectedDoneStateAfterToggle
    }
 
    func taskUpdated(task: Task) {
      XCTAssertEqual(expectedDone, task.done, "Task done state did not match expected!")
      testExpectation.fulfill()
    }
  }
 
  //3
  let testTask = Task(aTitle: "TestTask", aDueDate: .OneMonthAfter)
  XCTAssertFalse(testTask.done, "Newly created task is already done!")
  cell.delegate = TestDelegate(updatedExpectation: expectation,
    expectedDoneStateAfterToggle: true)
  cell.configureForTask(testTask)
 
  //4
  XCTAssertFalse(cell.checkbox.isChecked, "Checkbox checked for not-done task!")
 
  //5
  cell.checkbox.sendActionsForControlEvents(.TouchUpInside)
 
  //6
  XCTAssertTrue(cell.checkbox.isChecked, "Checkbox not checked after tap!")
  waitForExpectationsWithTimeout(1, handler: nil)
}

This is what each part does:

  1. Create an expectation for which to wait. Since the delegate is a separate object from the test, you may not hit the success block immediately.
  2. Create an inline struct, conforming to the test delegate, which allows you to check and see whether it was called or not. Since you want this struct to tell you when the expectation has been met, and do a check based on a value you pass it, you make it accept both the expectation and the expected values as parameters.
  3. Set up the test task and verify its initial value, then configure the cell.
  4. Make sure the checkbox has the proper starting value.
  5. Fake a tap on the checkbox by sending the TouchUpInside event which would be called when a user tapped on it.
  6. Make sure everything gets updated – starting with the checkbox by verifying its state has updated, and then wait for the expectation to be fulfilled to make sure the delegate is updated with the new value.

Build the test, but don’t run it – it’s time to be lazy, kick back, and let Travis do it for you. Commit your changes and push them up to the remote:

git add .
git commit -m "Test marking tasks done"
git push -u origin to-done

Create a new pull request following the steps you used previously, and call it To-Done. As you probably guessed from the instruction not to run your tests, this build fails:

github_to_done_integration_fail

Click the Details link to get the details of the build failure. Scroll all the way to the bottom, where you’ll see the following:

travis_test_error-700x50

Scroll up a bit to see information about a crash which occurred while running the tests:

travis_fail_stack_trace

D’oh! The force-unwrap of an IBOutlet didn’t work, so the test crashed. Why would that be?

If you think about how the TaskTableViewCell is normally created – through the cell reuse queue managed by a view controller loaded from a storyboard – this crash makes sense. The cell isn’t being loaded from the storyboard, so the IBOutlets don’t get hooked up.

Fortunately, this isn’t too hard to fix – grab a reference to a cell from an instance of MasterViewController instantiated from the storyboard, and use its tableView(_:cellForRowAtIndexPath:) method to grab a valid cell.

Add the following lines at the top of testCheckingCheckboxMarksTaskDone(), wrapping the code you already added in the if statement:

var testCell: TaskTableViewCell?
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
if let navVC = mainStoryboard.instantiateInitialViewController() as? UINavigationController,
  listVC = navVC.topViewController as? MasterViewController {
  let tasks = TaskLoader.loadStockTasks()
  listVC.createdMovingTasks(tasks)
  testCell = listVC.tableView(listVC.tableView, cellForRowAtIndexPath: NSIndexPath(forRow: 0,
      inSection: 0)) as? TaskTableViewCell       
  //REST OF CODE YOU ALREADY ADDED GOES HERE
}

Next, to make sure the test doesn’t pass if listVC is somehow nil, add an else clause to the if let which fails the test if it gets hit:

} else {
  XCTFail("Could not get reference to list VC!")
}

Now update your existing test code to use the cell you’ve just generated. Replace:

let cell = TaskTableViewCell()

with:

if let cell = testCell {
  //REST OF THE CODE BELOW SETTING UP THE CELL GOES HERE
} else {
  XCTFail("Test cell was nil!")
}

Once again, be lazy and let glorious automation do your work for you. Build the test to make sure the code compiles, but don’t run it. Commit your changes and push them up to the remote:

git add .
git commit -m "Update grabbing cell for test"
git push -u origin to-done

Again, you have an existing pull request, so when Travis runs the tests, you should see good news in your GitHub repo:

github_to_done_pass

Click the Merge pull request button, then the Confirm merge button, and you’re done.

Congratulations! Thanks to the effort you’ve put in as you’ve worked through this Travis CI tutorial, you now have a base of tests you can use to make sure you don’t break anything as you improve the application, and Travis is set up to run them automatically. No more running tests manually – and there’s still time for happy hour :]

Where To Go From Here

You can download the finished project here.

This tutorial has only scratched the surface of what Travis CI can do. No, it won’t fetch you coffee, or beer, but Travis is useful for considerably more than just running tests.

Further Capabilities of Travis

Travis isn’t always sunshine and lollipops, however.

A few caveats to keep in mind:

  • New versions of Xcode are not typically made available until they’ve been publicly released. This means you can’t use Travis to build a version of your app that’s using a beta SDK.
  • Since they have a paid service, Travis has an incentive to upgrade everything in a timely fashion. Sometimes, however, that incentive doesn’t cause them to upgrade fast enough for everyone’s tastes. If you always need to be on the bleeding edge, keep this in mind.
  • Build machines can be a bit slower than your local machine. Particularly if you’re running UI tests with KIF, you may run in to instances where the slowness of the build machine means you see race conditions you wouldn’t see on real devices, or test flakiness on the build server you don’t see locally.
  • You get a lot of information in the logs from Travis, but you can’t get crash logs without setting up scripts to upload them to a third-party service after a build complete.
  • All tests are run on simulators. If you have tests which must be run on a device, Xcode Bots is a better choice since it can run on both simulators and real devices – although this comes with the responsibility to manage provisioning and signing.

Want to know more?

If you’re interested in learning more about continuous integration with Travis, check out the following documentation:

I’ve hope you’ve enjoyed this Travis CI. If you’ve got and questions then please feel free to ask them in the comments below!

The post Travis CI Tutorial: Getting Started appeared first on Ray Wenderlich.


Video Tutorial: Intermediate Core Data Part 4: Fetched Results Controllers

Firebase Tutorial: Getting Started

$
0
0

firebase-discs

Firebase is a mobile-backend-as-a-service that provides several features for building powerful mobile apps. Firebase has three core services: a realtime database, user authentication and hosting. With the Firebase iOS SDK, you can use these services to build powerful apps without writing a single line of server code.

The realtime database is one of the most unique features of Firebase.

Ever used pull-to-refresh to fetch new data? You can forget about it with Firebase.

When a Firebase database updates, all connected users receive updates in realtime. This means your app can stay up to date without user interaction.

In this Firebase tutorial, you’ll learn all the fundamentals of Firebase by making a collaborative grocery list app called Grocr. When items get added to the list they’ll appear instantly on any users’ devices. But you’re not going to stop there, no, you’ll tweak Grocr to work offline, so the list stays in sync even with a spotty grocery store data connection.

As you work, you’ll learn about:

  • Saving data to a Firebase database
  • Syncing data from Firebase a database in realtime
  • Authenticating users
  • Monitoring online users
  • Enabling offline support

Get ready to realtime all the things!

Getting Started

Download the Grocr starter project. It uses CocoaPods to manage the Firebase dependency and contains a basic working project.

Open the Grocr.xcworkspace in Xcode. This project contains three view controllers:

  1. The first is the LoginViewController.swift. Right now the login is using hard coded user credentials, but you’ll fix that soon.
  2. Second is the GroceryListTableViewController.swift. This view is a subclass of UITableViewController that adds items to a list of local data using a UIAlertController.
  3. Last is the OnlineUsersTableViewController.swift. This view will use Firebase’s presence feature to display all of the users currently online.

In addition to the view controllers, there are two models: GroceryItem.swift and User.swift. These are just two structs that serve as models for your data.

Build and run, and you’ll see the app looks like this:

Grocr-Starter

If you play around, you’ll see that it only works with local data. You can log in just by tapping Login using the hard-coded user. Next, you’ll use Firebase to bring the app to life.

Setting up a Firebase Account

There are two main steps to setting up Firebase in an iOS project:

  1. Create a free Firebase account;
  2. Get the URL of your first app.

To create an account, visit the sign up page. After signing up, you’ll have a shiny new Firebase App created for you. Don’t worry about forking over any money — everything covered today falls well within Firebase’s free plan.

You’ll get routed to the Account dashboard where you’ll see that default Firebase app that was created upon sign up.

firebase-signup

Click Manage App, which takes you into the App dashboard where you can manage your Firebase app.

This app will serve as the container for all Firebase services. You’ll use it to store data and authenticate your users.

Every Firebase app has a unique URL associated with it, which you’ll use to save and sync data in Firebase. It looks something like: https://<your-firebase-app>.firebaseio.com. Navigate to it and you’ll see something like this:

firebase-app-dash

This is where you view and manage the app’s data as it updates. The main thing to note is the current URL because you’ll use to save and sync data.

Creating a Connection to Firebase

With your Firebase app set up, go to Xcode and open GroceryListTableViewController.swift. Where the properties are defined, add the following:

let ref = Firebase(url: "https://<your-firebase-app>.firebaseio.com/grocery-items")

This establishes a connection to your Firebase database using the unique URL. In the documentation, these Firebase properties are referred to as references because they refer to a location in your Firebase database.

In short, this property allows for saving and syncing of data to the given location.

You’ll notice that the base URL is not used, instead, it uses a child path of grocery-items. The Firebase database is a JSON NoSQL database, so all data is stored as JSON.

JSON is a hierarchical key-value data structure, meaning a key refers to an object that can contain keys pointing to other objects. JSON data is simply a tree of key value pairs.

With Firebase, the key is a URL and the value is arbitrary data that could be a number, string, boolean or object.

Structuring Data

No matter how it’s formatted on the client, all data stored in Firebase is JSON. Take a look at the following sample JSON data:

// The root of the tree
// https://<your-firebase-app>.firebaseio.com/
{
  // https://<your-firebase-app>.firebaseio.com/grocery-items
  "grocery-items": {
 
    // https://<your-firebase-app>.firebaseio.com/grocery-items/milk
    "milk": {
 
      // https://<your-firebase-app>.firebaseio.com/grocery-items/milk/name
      "name": "Milk",
 
      // https://<your-firebase-app>.firebaseio.com/grocery-items/milk/addedByUser
      "addedByUser": "David"
    },
 
    "pizza": {
      "name": "Pizza",
      "addedByUser": "Alice"
    },
  }
}

In the JSON tree above, you can see there’s a URL mapped to every piece of data. You can continue to traverse down the tree and retrieve data at deeper locations.

In the case of the data above, you can retrieve all grocery items by using the URL:

https://<your-firebase-app>.firebaseio.com/grocery-items

If you only want to get the first grocery item you can navigate to a child path using the URL:

https://<your-firebase-app>.firebaseio.com/grocery-items/milk

Since all Firebase keys map to URLs, the key names you choose are especially important.

Understanding Firebase References

A fundamental theme to grasp is that a Firebase reference points a location in Firebase where data is stored. If you create multiple references, then they all share the same connection.

Have a look at this sample code:

// 1
let rootRef = Firebase(url: "https://<your-firebase-app>.firebaseio.com/")
 
// 2
let childRef = Firebase(url: "https://<your-firebase-app>.firebaseio.com/grocery-items")
 
// 3
let itemsRef = rootRef.childByAppendingPath("grocery-items")
 
// 4
let milkRef = itemsRef.childByAppendingPath("milk")
 
// 5
println(rootRef.key)   // prints: ""
println(childRef.key)  // prints: "grocery-items"
println(itemsRef.key)  // prints: "grocery-items"
println(milkRef.key)   // prints: "milk"

Here’s what’s going on:

  1. You create a reference to the root of the Firebase database.
  2. Using a URL, you can create a reference to a child location in your Firebase database.
  3. From the rootRef you can use childByAppendingPath(_:) to create a child reference by passing the child path. This reference is the same as the one above.
  4. Using the itemsRef, you can create a child reference to the milk location.
  5. Every reference has a key property. This property tells you what the key name is in the Firebase database.

You don’t need to add this code anywhere in the sample project, it’s purely for illustrative purposes. :]

Adding New Items to the List

At the bottom of GroceryListTableViewController.swift, find addButtonDidTouch(_:).

This is where you present the user with a UIAlertController to add a new item.

Inside the method, locate saveAction. Currently, it only saves the data to a local array, so saveAction won’t sync across multiple clients and disappears when you restart the app.

Nobody’s going to want to use an app that doesn’t remember or sync their grocery list! Replace saveAction with the following:

let saveAction = UIAlertAction(title: "Save",
    style: .Default) { (action: UIAlertAction!) -> Void in
 
  // 1
  let textField = alert.textFields![0] as! UITextField
 
  // 2
  let groceryItem = GroceryItem(name: textField.text, addedByUser: self.user.email, completed: false)
 
  // 3
  let groceryItemRef = self.ref.childByAppendingPath(textField.text.lowercaseString)
 
  // 4
  groceryItemRef.setValue(groceryItem.toAnyObject())
}

Here’s what’s going on:

  1. Get the text field from the alert controller.
  2. Using the current user’s data, create a new GroceryItem that is not completed by default.
  3. Create a child reference using childByAppendingPath(_:). The key value of this reference is the item’s name in lowercase, so when users add duplicate items — even if they capitalize it, or use mixed case — the database saves only the latest entry.
  4. Use setValue(_:) to save data to the database. This method expects a dictionary. GroceryItem has a helper function to turn it into a dictionary called toAnyObject().

Build and run. Open up a browser and point it to the Firebase App dashboard and position it next to the simulator. When you add an item, you’ll see it appear in the dashboard:

fb-save

Now you have a grocery list app that adds data to Firebase in realtime! So this key feature is working correctly, but none of the items are added to the table view.

So, how about you get that data synchronizing from the database to the table view?

Retrieving Data

You retrieve data in Firebase by attaching an asynchronous listener to a reference using observeEventType(_:withBlock:).

Add the following to viewDidAppear() in GroceryListTableViewController.swift:

ref.observeEventType(.Value, withBlock: { snapshot in
  println(snapshot.value)
}, withCancelBlock: { error in
  println(error.description)
})

Here you’ve added an observer that executes the given closure whenever the value that ref points to is changed.

Build and run. You’ll see list items logged to the console as they’re added.

This function takes two parameters, an instance of FEventType and a closure.

The event type specifies what event you want to listen for. The code above listens for a .Value event type, which in turn listens for all types of changes to the data in your Firebase database — add, removed, and changed.

When the change occurs, the database updates the app with the most recent data.

The app is notified of the change via a closure, which is passed an instance FDataSnapshot. The snapshot, as its name suggests, represents the data at that specific moment in time. To access the data in the snapshot, you use the value property.

Synchronizing Data to the Table View

So that took care of logging — now to actually display the grocery list in your table view.

In GroceryListTableViewController.swift, replace viewDidAppear(_:) with the following:

override func viewDidAppear(animated: Bool) {
  super.viewDidAppear(animated)
 
  // 1
  ref.observeEventType(.Value, withBlock: { snapshot in
 
    // 2
    var newItems = [GroceryItem]()
 
    // 3
    for item in snapshot.children {
 
      // 4
      let groceryItem = GroceryItem(snapshot: item as! FDataSnapshot)
      newItems.append(groceryItem)
    }
 
    // 5
    self.items = newItems
    self.tableView.reloadData()
  })
}

Here’s what happening:

  1. Attach a listener to receive updates whenever the grocery-items endpoint is modified.
  2. Store the latest version of the data in a local variable inside the listener’s closure.
  3. The listener’s closure returns a snapshot of the latest set of data. The snapshot contains the entire list of grocery items, not just the updates. Using children, you loop through the grocery items.
  4. The GroceryItem struct has an initializer that populates its properties using a FDataSnapshot. A snapshot’s value is of type AnyObject, and can be a dictionary, array, number, or string. After creating an instance of GroceryItem, it’s added it to the array that contains the latest version of the data.
  5. Reassign items to the latest version of the data, then reload the table view so it displays the latest version.

Build and run. Add an item — how about some pizza? — it shows up in the table view.

fb-sync

No pull-to-refresh required to get the list to update in real time!

realtime-updates

Removing Items From the Table View

The table view will synchronize on any kind of change to your data, but right now there’s nothing to update Firebase when the user decides not to get that pizza.

To notify the database of a deletion, you need to set a Firebase reference to delete an item when the users swipes it away.

Locate tableView(_:commitEditingStyle:forRowAtIndexPath:). Right now, this method removes a grocery item from the local array using the index path’s row. It works, but there’s a better way. Replace the existing implementation with the following:

override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
  if editingStyle == .Delete {
    // 1
    let groceryItem = items[indexPath.row]
    // 2
    groceryItem.ref?.removeValue()
  }
}

Firebase follows a unidirectional data flow model, so the listener in viewWillAppear(_:) notifies the app of the latest value of the grocery list. A removal of an item triggers a value change.

The index path’s row is used to retrieve the corresponding grocery item. Each GroceryItem has a Firebase reference property named ref, and calling removeValue() on that reference causes the listener in viewDidLoad() to fire. The listener has a closure attached that reloads the table view using the latest data.

Build and run. Swipe an item, tap delete, and watch it vanish from both your app and in Firebase.

fb-delete

Nice work! Your items now delete in realtime.

Checking Off Items

Now you know how to add, remove, and sync items, and that’s all pretty cool. But what about when you’re actually shopping? Should you just delete stuff that you’ve got, or would it be better to mark things off as you add them to your basket?

Back in the analog days of pens and paper, people used to cross stuff off the grocery list, so you’ll mimic that familiar behavior in this app, but with a modern twist!

When tapped, items should turn gray and show a checkmark to give the user some visual feedback that the item is no longer needed.

checked-off-grocr

Open GroceryListTableViewController.swift and find toggleCellCheckbox(_:isCompleted:). This method toggles the necessary view properties for UITableViewCell, depending on whether its associated item is complete.

It’s called from within tableView(_:cellForRowAtIndexPath:) when the table view is first loaded, and from within tableView(_:didSelectRowAtIndexPath:) when the user taps on a row.

Replace the current implementation of tableView(_:didSelectRowAtIndexPath:) with the following:

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
  // 1
  let cell = tableView.cellForRowAtIndexPath(indexPath)!
  // 2
  var groceryItem = items[indexPath.row]
  // 3
  let toggledCompletion = !groceryItem.completed
  // 4
  toggleCellCheckbox(cell, isCompleted: toggledCompletion)
  // 5
  groceryItem.ref?.updateChildValues([
    "completed": toggledCompletion
  ])
}

Here’s the play-by-play of what’s happening:

  1. Find the cell the user tapped using cellForRowAtIndexPath(_:).
  2. Get the corresponding GroceryItem by using the index path’s row.
  3. Negate completed on the grocery item to toggle the status.
  4. Call toggleCellCheckbox() update the visual properties of the cell.
  5. Use updateChildValues(_:), passing a dictionary, to update Firebase. This method is different than setValue(_:) because it only applies updates, whereas setValue(_:) is destructive and replaces the entire value at that reference.

Build and run. Tap on an item and see that it toggles back and forth between the complete and incomplete statuses.

fb-toggle

Congratulations, you’ve got yourself a pretty sweet grocery list app now!

Sorting the Grocery List

You know how sometimes you forget to pick up that ice cream because it’s nestled between a couple of things you’ve already marked off and your eyes played tricks on you? Well you, dear reader, can fix that.

The app would be 10x more awesome if checked items moved themselves to the bottom of the list automatically. Then the remaining items would be clear and easy for your eyes to see.

Using Firebase queries, you can sort the list by arbitrary properties. Still working in GroceryListTableViewController.swift, replace viewDidAppear(_:) with the following:

override func viewDidAppear(animated: Bool) {
  super.viewDidAppear(animated)
 
  ref.queryOrderedByChild("completed").observeEventType(.Value, withBlock: { snapshot in
    var newItems = [GroceryItem]()
    for item in snapshot.children {
      let groceryItem = GroceryItem(snapshot: item as! FDataSnapshot)
      newItems.append(groceryItem)
    }
    self.items = newItems
    self.tableView.reloadData()
  })
}

To order the data by the completed value you call queryOrderedByChild(_:) on the Firebase reference, which takes a key to order by.

Since the list needs to order by completed, the key completed is passed to the query. Then, queryOrderedByChild(_:) returns a reference that informs the server to return data in an ordered fashion.

Build and run. Tap on a row to toggle its completion status. The completed items magically move to the bottom of the list.

fb-order

Wow! You’re really making grocery shopping easier here. Seems like it should be simple enough to sync the data across multiple users, for instance, with a significant other or housemate. This sounds like a job for…authentication!

Authenticating Users

Firebase has an authentication service that allows apps to authenticate through several providers. You can authenticate users with Google, Twitter, Facebook, Github, email & password, anonymous, and even custom backends. Here you’ll use email and password because it’s the easiest to set up.

To enable email and password authentication go to the Firebase App dashboard and click on Login & Auth.

fb-login-auth

Check Enable Email & Password Authentication.

fb-enable-login

Now you’re ready to authenticate your users using their email and password!

Registering Users

Open LoginViewController.swift. Add the following to the top of the class:

let ref = Firebase(url: "https://<your-firebase-app>.firebaseio.com")

Find signUpDidTouch(_:). This presents a UIAlertController that allows the user to register for an account. Locate saveAction and modify its closure to the following:

// 1
self.ref.createUser(emailField.text, password: passwordField.text) { (error: NSError!) in
  // 2
  if error == nil {
    // 3
    self.ref.authUser(emailField.text, password: passwordField.text,
        withCompletionBlock: { (error, auth) -> Void in
      // 4
    })
  }
}

Here’s what’s going on in the above code:

  1. Call createUser(_:password:) on the Firebase reference passing the supplied email and password.
  2. In the closure, check if there was an error.
  3. Creating a user doesn’t imply authentication. To authenticate, call authUser(_:password:withCompletionBlock:), again passing in the given email and password.
  4. For now, you simply do nothing in the closure.

Build and run. Tap the Sign up button and enter an email and a password, then tap save. The view controller won’t navigate to anything on successful login just yet. If you refresh the Firebase Login & Auth tab you’ll see the newly created user.

fb-register-user

W00T! The app now registers users and then lets them log in. Don’t celebrate yet though, you need to finish the process so people can actually use the app as intended.

Logging Users In

The Sign up button can register and log in users. However, the login button effectively does nothing because no segue is performed.

Still working in LoginViewController.swift, find loginDidTouch(_:) and modify it so it matches the following:

@IBAction func loginDidTouch(sender: AnyObject) {
  ref.authUser(textFieldLoginEmail.text, password: textFieldLoginPassword.text,
      withCompletionBlock: { (error, auth) in
 
  })
}

This code will authenticate the user when they attempt to log in by tapping the Login button.

It’s time to perform the segue to the next controller.

Observing Authentication State

Firebase has observers that allow you to monitor a user’s authentication state. This is a great place to perform a segue.

You need to replace the current viewDidAppear(_:) implementation with the following:

override func viewDidAppear(animated: Bool) {
  super.viewDidAppear(animated)
 
  // 1
  ref.observeAuthEventWithBlock { (authData) -> Void in
    // 2
    if authData != nil {
      // 3
      self.performSegueWithIdentifier(self.LoginToList, sender: nil)
    }
  }
}

Here’s a run-down of what’s happening:

  1. Create an authentication observer using observeAuthEventWithBlock(_:).
  2. The block is passed the authData parameter. Upon successful user authentication, this is populated with the user’s information. If authentication fails, the variable is nil.
  3. On successfull authentication, perform the segue. Pass nil as the sender. This may seem strange, but you’ll set this up in GroceryListTableViewController.swift.

Setting the User in the Grocery List

Go to GroceryListTableViewController.swift, and add the following to the bottom of viewDidAppear(_:):

ref.observeAuthEventWithBlock { authData in
  if authData != nil {
    self.user = User(authData: authData)
  }
}

Here you attach an authentication observer to the Firebase reference, that in turn assigns the user property when a user successfully signs in.

Build and run. If a user is logged in, they bypass LoginViewController and segue to the GroceryListTableViewController. When users add items, their email will show in the detail of the cell.

fb-user-add

Success! The app now has basic user authentication.

Monitoring Users Online Status

Now that the app has user authentication, its time to detect which users are online. Open GroceryListTableViewController.swift and add the following property:

let usersRef = Firebase(url: "https://<your-firebase-app>.firebaseio.com/online")

Remember to replace your-firebase-app with your app’s name.

This is a Firebase reference that points to an online location that stores a list of online users.

Next, modify the observeAuthEventWithBlock(_:) closure inside viewDidAppear(_:):

ref.observeAuthEventWithBlock { authData in
  if authData != nil {
    self.user = User(authData: authData)
    // 1
    let currentUserRef = self.usersRef.childByAppendingPath(self.user.uid)
    // 2
    currentUserRef.setValue(self.user.email)
    // 3
    currentUserRef.onDisconnectRemoveValue()
  }
}

The code above the follows these steps:

  1. Create a child reference using a user’s uid, which is generated when Firebase creates an account.
  2. Use this reference to save the current user’s email.
  3. Call onDisconnectRemoveValue() on currentUserRef. This removes the value at the reference’s location after the connection to Firebase closes, for instance when a user quits your app. This is perfect for monitoring users who have gone offline.

Build and run. When the view loads the current user’s email is added as a child in the online location.

fb-monitoring

Great! Now it’s time to change the number of the bar button item as the user count grows.

Updating the Online User Count

Still working in GroceryListTableViewController.swift, add the following code to viewDidAppear():

usersRef.observeEventType(.Value, withBlock: { (snapshot: FDataSnapshot!) in
  if snapshot.exists() {
    self.userCountBarButtonItem?.title = snapshot.childrenCount.description
  } else {
    self.userCountBarButtonItem?.title = "0"
  }
})

This creates an observer that is used to monitor online users. When users go on-and-offline, the title of userCountBarButtonItem updates with the current user count.

Displaying a List of Online Users

Open OnlineUsersTableViewController.swift and add the following to viewDidAppear(_:):

// 1
usersRef.observeEventType(.ChildAdded, withBlock: { (snap: FDataSnapshot!) in
  // 2
  self.currentUsers.append(snap.value as! String)
  // 3
  let row = self.currentUsers.count - 1
  // 4
  let indexPath = NSIndexPath(forRow: row, inSection: 0)
  // 5
  self.tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Top)
})

Here’s what’s happening in the code:

  1. Create an observer that listens for children added to the location managed by usersRef. This is different than a value listener because only the added child are passed to the closure.
  2. Take the value from the snapshot, and then append it to the local array.
  3. The current row is always the count of the local array minus one because the indexes managed by the table view are zero-based.
  4. Create an instance NSIndexPath using the calculated row index.
  5. Insert the row using an animation that causes the cell to be inserted from the top.

This will only render items as they are added rather than reloading the entire list, and it also gives you the ability to specify a nice animation. :]

Since users can go offline, the table needs to react to users being removed as well. Add the following below the code you just added:

usersRef.observeEventType(.ChildRemoved, withBlock: { (snap: FDataSnapshot!) -> Void in
  let emailToFind: String! = snap.value as! String
  for(index, email) in enumerate(self.currentUsers) {
    if email == emailToFind {
      let indexPath = NSIndexPath(forRow: index, inSection: 0)
      self.currentUsers.removeAtIndex(index)
      self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
    }
  }
})

This simply adds an observer that listens for children of the usersRef reference being removed. It searches the local array for the email value to find the corresponding child item, and once located, it deletes the associated row from the table.

Build and run.

Tap Online in the Firebase users dashboard, and the current user’s email will appear in the table. Using a bit of trickery, it’s possible to add a user to Online, and once you do, it shows in the list. Click the Remove button in the App Dashboard and the user fades from existence….

fb-users-table

Booyah! The table updates when users are added and removed.

monintoring-users

Enabling Offline

Grocery stores are notorious for spotty data connections. You’d think they’d all have Wi-Fi now, but no!

No problem, you’ll just set up your database to work offline. Open AppDelegate.swift and add the following:

override init() {
  super.init()
  Firebase.defaultConfig().persistenceEnabled = true
}

Yup, that’s it! Just like that your app works offline. Even offline updates that occur across app restarts will apply to your Firebase database once a connection is made. Oooh-ahhhh!

Where To Go From Here?

You can download the completed version of Grocr here.

Throughout this Firebase tutorial, you’ve learned the basics of Firebase by building a collaborative grocery list app. You’ve implemented saving data to a Firebase database, syncing data from a Firebase database in realtime, authenticating users, monitoring online user status, and finally enabling offline support. And you did all this without writing a single line of server code! :]

If you’re curious about Firebase, please do check out the documentation, as well as the examples provided by Firebase themselves.

If you have any comments or questions about this tutorial, Firebase, or the project app, please join the forum discussion below!

The post Firebase Tutorial: Getting Started appeared first on Ray Wenderlich.

An iOS 9 Surprise Coming Soon!

$
0
0

This is just a quick heads-up that we have a special iOS 9 surprise coming for you this Wednesday in conjunction with the iOS 9 release:

iOS9_Feast_blank

I bet some of you can guess what this is ;]

Be sure to check back in on Wednesday – and come hungry!

The post An iOS 9 Surprise Coming Soon! appeared first on Ray Wenderlich.

Video Tutorial: Intermediate Core Data Part 5: Managed Object Contexts

Carthage Tutorial: Getting Started

$
0
0
Learn how to use Carthage to manage your project's dependencies.

Learn how to use Carthage to manage your project’s dependencies.

Two great things about iOS development are the fantastic community, and the wide range of available third party libraries.

If you’ve coded on the platform for a while, chances are you’ve used at least one of these libraries. Whether it’s AFNetworking, SDWebImage, SSKeychain or CocoaLumberjack, you already know the value of making use of someone else’s code because you’re not fond of reinventing the wheel.

Then there’s CocoaPods. If you’re not acquainted with this lovely tool, it’s a popular dependency manager that streamlines the process of integrating these sorts of libraries into your project.

It’s widely used in the iOS community, and even Google now uses it to distribute their various iOS SDKs.

While CocoaPods is awesome, there are other options. Carthage is one such alternative; it’s a ruthlessly simple dependency manager for Mac and iOS, created by a group of developers from Github.

It was the first dependency manager to work with Swift; in fact, Carthage itself is written in Swift! It exclusively uses dynamic frameworks instead of static libraries – this is only way to distribute Swift binaries that are supported by iOS 8 and up.

In this Carthage tutorial, you’ll learn the following:

  • Why and when to use a dependency manager, and what makes Carthage different
  • How to install Carthage
  • Declaring your dependencies, installing and integrating them with a project
  • Upgrading your dependencies to different versions
  • Build an app that provides definitions for search terms using the DuckDuckGo API

Note: This tutorial assumes that you have basic familiarity with iOS and Swift, that you’re familiar with Xcode, working with the command line and consuming web JSON from services.

If you need to brush up on any of these topics, check out some of our other written or video tutorials on this site.

Getting Started

First of all, download the starter project for this tutorial.

It includes the basic skeleton of DuckDuckDefine, a simple tool to look up the definitions of words using the DuckDuckGo API. There’s just one problem: It doesn’t actually perform any searches yet!

Open the starter project in Xcode and have a quick look round to familiarize yourself. Note the two view controllers: SearchViewController provides a search bar for the user to perform a search, and DefinitionViewController displays the definition of a search term.

Project Navigator showing the DuckDuckDefine starter project

The brains of the operation are in DuckDuckGo.swift — or at least they will be by the time you’re finished! At the moment, performSearch(_:completion:) is a lazy, good-for-nothing block of code.

To make it perform a search you’ll need to do two things:

  • Make a query using the DuckDuckGo API
  • Parse the JSON data in the response to extract a definition

There are a number of open source libraries that can help with these two tasks. Alamofire is a great Swift library which simplifies making web requests, and SwiftyJSON makes dealing with JSON in Swift a more pleasant experience.

And guess what? You’ll use Carthage to add both of these dependencies to your project.

Dependency Management

To add Alamofire and SwiftyJSON to your project, you could of course just visit their respective Github pages, download a zip file of the source and drop them into your project. So why bother with a tool like Carthage?

Dependency managers perform a number of handy functions:

  • They simplify and standardize the process of fetching third party code and incorporating it into your project. Without such a tool, this might be done by manually copying source code files, dropping in precompiled binaries, or using a mechanism like Git submodules.
  • They make it easier to update third party libraries in the future. Imagine having to visit each dependency’s GitHub page, download the source, and place it into your project every time there’s an update. Why would you do that to yourself?
  • They pick out appropriate and compatible versions of each dependency you use. For instance, if you’re manually adding dependencies, things can get tricky when they depend on one another or share another dependency.

Example dependency graph

Most dependency managers will construct a dependency graph of your project’s dependencies, and each of their sub-dependencies, and then determine the best version of each to use.

You could probably do the same manually, but at what cost? Your sanity?

Carthage vs CocoaPods

So how exactly is Carthage different from CocoaPods, and why would you use anything besides the most popular dependency manager for iOS?

Carthage’s developers felt that whilst CocoaPods is generally easy to use, simple it is not. The philosophy behind Carthage is that this tool should be ruthlessly simple.

CocoaPods adds complexity to both the app development and the library distribution processes:

  • Libraries must create, update and host Podspec files (or app developers must write their own if one doesn’t exist for a library that they wish to use).
  • When adding “pods” to a project, CocoaPods creates a new Xcode project with a target for each individual pod, as well as a containing workspace. Then you have to use the workspace and trust that the CocoaPods project works correctly. Talk about a lot of extra build settings to maintain.
  • CocoaPods’ Podspecs repository is centralized, which could be problematic if for some reason it were to disappear or become inaccessible.

CocoaPods?! This! Is! CARTHAGE!
The Carthage project’s aim is to provide a simpler tool than CocoaPods; one that’s easier to understand, easier to maintain and more flexible.

It achieves this in a number of ways:

  • Carthage doesn’t modify your Xcode project or force you to use a workspace.
  • There’s no need for Podspecs or a centralized repository for library authors to submit their pods to. If your project can be built as a framework, it can be used with Carthage. It leverages existing information straight from Git and Xcode.
  • Carthage doesn’t really do anything magic; you’re always in control. You manually add dependencies to your Xcode project and Carthage fetches and builds them.

Note: Carthage uses dynamic frameworks to achieve its simplicity. This means your project must support iOS 8 or later.

Now that you ‘ve got some background on things, that’s enough talk. It’s time to learn for yourself how ruthlessly simple Carthage is!

Installing Carthage

At the “core” of Carthage is a command line tool that assists with fetching and building dependencies.

There are two ways to install it: downloading and running a .pkg installer for the latest release, or using the Homebrew package manager. In the same way that Carthage helps install packages for your Cocoa development, Homebrew helps install useful Unix tools for OS X.

You’ll use Homebrew for this task, so if you don’t already have Homebrew installed, simply open Terminal and run the following command:

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

This will download and install the latest version of Homebrew. Once that’s finished, make sure that Homebrew’s index is up to date by running:

brew update

Finally, to install Carthage, run:

brew install carthage

And you’re done! To check that Carthage installed correctly, you can just run:

carthage version

If all has gone to plan, you’ll see the version number of Carthage that was installed.

Note: At the time of writing, the current version of Carthage was 0.7.5.

Next, you need to tell Carthage which libraries to install. This is done with a Cartfile.

Cartophile?!

Creating Your First Cartfile

A Cartfile is a simple text file that describes your project’s dependencies to Carthage, so it can determine what to install. Each line in a Cartfile states where to fetch a dependency from, the name of the dependency, and optionally, which version of the dependency to use. A Cartfile is the equivalent of a CocoaPods Podfile.

Navigate to the root directory of your project in Terminal (the directory that contains your .xcodeproj file) using the cd command:

cd ~/Path/To/Starter/Project

Create an empty Cartfile with the touch command:

touch Cartfile

And then open the file up in Xcode for editing:

open -a Xcode Cartfile

If you’re familiar with another text editor, like Vim, then feel free to use that instead. Don’t, however, use TextEdit to edit the file; with TextEdit it’s too easy to accidentally use so-called “smart quotes” instead of straight quotes, and they will confuse Carthage.

Add the following lines to the Cartfile and save it:

github "Alamofire/Alamofire" == 1.2
github "Thomvis/SwiftyJSON" == 2.2.1

These two lines tell Carthage that your project requires Alamofire version 1.2, and SwiftyJSON version 2.2.1.

Note: This tutorial is currently using a specific version of SwiftyJSON in a forked repository that fixes an outstanding issue where SwiftyJSON doesn’t build correctly with the latest version of Carthage. Hopefully the pull request for this fix will be merged soon!

The Cartfile Format

Cartfiles are written in a subset of OGDL: Ordered Graph Data Language. It sounds fancy, but it’s really quite simple. There are two key pieces of information on each line of a Cartfile:

  • Dependency origin: This tells Carthage where to fetch a dependency from. Carthage supports two types of origins:
    • github for Github-hosted projects (the clue’s in the name!). You specify a Github project in the Username/ProjectName format, just as you did with the Cartfile above.
    • git for generic Git repositories hosted elsewhere. The git keyword is followed by the path to the git repository, whether that’s a remote URL using git://, http://, or ssh://, or a local path to a git repository on your development machine.
  • Dependency Version: This is how you tell Carthage which version of a dependency you’d like to use. There are a number of options at your disposal, depending on how specific you want to be:
    • == 1.0 means “Use exactly version 1.0”
    • >= 1.0 means “Use version 1.0 or higher”
    • ~> 1.0 means “Use any version that’s compatible with 1.0″, essentially meaning any version up until the next major release.
      • If you specify ~> 1.7.5, then any version from 1.7.5 up to, but not including 2.0, is considered compatible.
      • Likewise, if you specify ~> 2.0 then Carthage will use a version 2.0 or later, but less than 3.0. .
      • Compatibility is based on Semantic Versioning – for more information check out our tutorial on Using CocoaPods with Swift.
    • branch name / tag name / commit name means “Use this specific git branch / tag / commit”. For example, you could specify master, or a commit has like 5c8a74a.

If you don’t specify a version, then Carthage will just use the latest version that’s compatible with your other dependencies. You can see examples of each of these options in practice in Carthage’s README file.

Building Dependencies

So now you have a Cartfile, it’s time to put it to use and actually install some dependencies!

Close your Cartfile in Xcode and head back to Terminal. Run the following command:

carthage update --platform iOS

This instructs Carthage to clone the Git repositories that are specified in the Cartfile, and then build each dependency into a framework. You should see output that shows what happened, similar to this:

*** Fetching Alamofire
*** Fetching SwiftyJSON
*** Downloading SwiftyJSON at "2.2.1: Carthaginem esse"
*** Checking out Alamofire at "1.2.0"
*** xcodebuild output can be found in /var/folders/h8/qp5163ln7mz2d7_l_yn6hd0m0000gp/T/carthage-xcodebuild.HBRNcq.log
*** Building scheme "Alamofire iOS" in Alamofire.xcworkspace

The --platform iOS option ensures that frameworks are only built for iOS. If you don’t specify a platform, then by default Carthage will build frameworks for all platforms (often both Mac and iOS) supported by the library.

If you’d like to take a look at further options available, you can run carthage help update.

By default, Carthage will perform its checkouts and builds in a new directory named Carthage in the same location as your Cartfile. Open up this directory now by running:

open Carthage

You should see a Finder window pop up that contains two directories: Build and Checkouts. Take a moment to see what Carthage created for you.

Carthage Build Artifacts

Build Artifacts

If you’re familiar with CocoaPods, you know that it makes a number of changes to your Xcode project and binds it together with a special Pods project into an Xcode workspace.

Carthage is a little different. It simply checks out the code for your dependencies, builds it into binary frameworks, and then it’s up to you to integrate it into your project. It sounds like extra work, but it’s beneficial. It only takes a few steps and you’ll be more cognizant of the changes to your project as a result.

When you run carthage update, Carthage creates a couple of files and directories for you:

carthage-directory-2

  • Cartfile.resolved: This file is created to serve as a companion to the Cartfile. It defines exactly which versions of your dependencies Carthage selected for installation. It’s strongly recommended to commit this file to your version control repository, because its presence ensures that other developers can get started quickly by using exactly the same versions of dependencies as you.
  • Carthage directory, containing two subdirectories:
    • Build: This contains the built framework for each dependency. These can be integrated into your project, which you’ll do shortly. Each framework is either built from source, or downloaded from the project’s “Releases” page on Github.
    • Checkouts: This is where Carthage checks out the source code for each dependency that’s ready to build into frameworks. Carthage maintains its own internal cache of dependency repositories, so it doesn’t have to clone the same source multiple times for different projects.

Whether you commit the Build and Checkouts directories to your version control repository is entirely up to you. It’s not required, but doing so means that anybody who clones your repository will always have the binaries and / or source for each dependency available.

This can be a useful insurance policy of sorts, for example, if Github is unavailable or a source repository is removed completely then you’d have a clean backup.

Don’t modify any code inside the Checkouts folder because its contents may be overwritten at any time by a future carthage update or carthage checkout command, and your hard work would be gone in the twinkling of an eye.

If modifications to your dependencies are a must do, you can run carthage update using the --use-submodules option.

With this option, Carthage adds each dependency in the Checkouts folder to your Git repository as a submodule, meaning you can change the dependencies’ source, and commit and push those changes elsewhere without fear of an overwrite.

Note: If other users need to use your project, and you haven’t committed the built frameworks with your code, then they will need to run carthage bootstrap after checking out your project.

The bootstrap command will download and build the exact versions of your dependencies that are specified in Cartfile.resolved.

carthage update, on the other hand, would update the project to use the newest compatible versions of each dependency, which may not be desirable.

Now, how about actually using these build artifacts you worked so hard to create?

Adding Frameworks to Your Project

Open up the starter project in Xcode if you haven’t already, and click the DuckDuckDefine project in the Project Navigator. Select the DuckDuckDefine target, choose the General tab at the top, and scroll down to the Linked Frameworks and Libraries section at the bottom.

In the Carthage Finder window, navigate into Build\iOS. Now, drag both Alamofire.framework and SwiftyJSON.framework into the Linked Frameworks and Libraries section in Xcode:

Adding frameworks to a target in Xcode

This tells Xcode to link your app to these frameworks, allowing you to make use of them in your own code.

Next, switch over to Build Phases and add a new Run Script build phase. Add the following command:

/usr/local/bin/carthage copy-frameworks

Click the + under Input Files and add an entry for each framework:

$(SRCROOT)/Carthage/Build/iOS/Alamofire.framework
$(SRCROOT)/Carthage/Build/iOS/SwiftyJSON.framework

Strictly speaking, this build phase isn’t required for your project to run. However, it’s a slick workaround for an App Store submission bug where apps with frameworks that contain binary images for the iOS simulator are automatically rejected.

The carthage copy-frameworks command strips out these extra architectures. w00t!

There won’t be anything new to see yet, but build and run the app to ensure everything’s still working as expected. When the app launches, you should see the search view controller:

DuckDuckDefine Search View Controller

OK, great. Things are looking good. Next, upgrading dependencies.

Upgrading Frameworks

I have a confession to make.

Oh no, what?

Remember when you created your Cartfile earlier, and I told you what versions of Alamofire and SwiftyJSON to install? Well, you see, I gave you bad information. I told you to use an old version of Alamofire.

How could you?!

Don’t be mad though! It was done with the best of intentions. Look on this as an opportunity…yes, an opportunity to learn how to upgrade a dependency. It’s a gift, really.

Oh, how can I stay mad at you?

Open up your Cartfile again. From your project’s directory in Terminal, run:

open -a Xcode Cartfile

Change the Alamofire line to:

github "Alamofire/Alamofire" ~> 1.0

As you saw earlier, this means to use any version of Alamofire that’s compatible with 1.0, so, any version up to but not including 2.0.

When adding dependencies with Carthage, it’s a good idea to consider compatibility and limit the version that you’re targeting. That way, you know the exact state of its API and functionality.

For example, version 2.0 of a dependency might include app-breaking API changes — you likely wouldn’t want to automatically upgrade to it if you built your project against 1.4.

Save and close the Cartfile, and return to the terminal. Perform another update:

carthage update --platform iOS

Carthage will check for newer versions of each of your dependencies, and check them out and build them, if necessary. You should see it fetch the latest version of Alamofire.

Because your project already contains a reference to the built .framework for Alamofire, and Carthage rebuilds the new version in the same location on disk, you can sit back and let Carthage do the work; your project will automatically use the latest version of Alamofire!

Duck, Duck… GO!

Now that you’ve integrated Alamofire and SwiftyJSON with the project, you can put them to use to perform some web searches. Are you ready?

In Xcode, open DuckDuckGo.swift. At the top of the file, add imports for each dependency:

import Alamofire
import SwiftyJSON

Next, add the following method to ResultType, just below the two case entries:

func parseDefinitionFromJSON(json: JSON) -> Definition {
  switch self {
  case .Answer:
    let heading = json["Heading"].stringValue
    let abstract = json["AbstractText"].stringValue
    let imageURL = NSURL(string: json["Image"].stringValue)
 
    return Definition(title: heading, description: abstract, imageURL: imageURL)
  case .Exclusive:
    let answer = json["Answer"].stringValue
 
    return Definition(title: "Answer", description: answer, imageURL: nil)
  }
}

This uses SwiftyJSON to extrapolate the necessary data from the JSON response and construct a Definition containing a title, a description and an image URL.

The DuckDuckGo API can return a range of different result types, but the two covered here are Answer, which provides a simple definition of the search term, and Exclusive which provides instant answers to things like calculations.

Next, still working within DuckDuckGo, replace the existing definition of performSearch(_:completion:) with this:

func performSearch(searchTerm: String, completion: ((definition: Definition?) -> Void)) {
  // 1
  let parameters: [String:AnyObject] = ["q": searchTerm, "format": "json", "pretty": 1,
      "no_html": 1, "skip_disambig": 1]
 
  // 2
  Alamofire.request(.GET, "http://api.duckduckgo.com", parameters: parameters).responseJSON {
      (_, _, jsonObject, error) in
    // 3
    if let error = error {
      completion(definition: nil)
    }
 
    // 4
    if let jsonObject: AnyObject = jsonObject {
      let json = JSON(jsonObject)
 
      // 5
      if let jsonType = json["Type"].string, resultType = ResultType(rawValue: jsonType) {
 
        // 6
        let definition = resultType.parseDefinitionFromJSON(json)
        completion(definition: definition)
      }
    }
  }
}

There’s quite a bit here, so let’s break it down:

  1. First, you build up the list of parameters to send to DuckDuckGo. The most important two here are q: the search term itself, and format: which tells the web service to respond with JSON.
  2. Then you perform the request using Alamofire. This call makes a GET request to http://api.duckduckgo.com, using the parameter dictionary created above.
  3. Once the response comes back, check if there’s an error. If there is, fail early.
  4. Optionally, bind the JSON response object to ensure it has a value, and then use it to construct a SwiftyJSON JSON struct.
  5. Next, grab the value for the Type key from the JSON, and use it to construct a ResultType enum, which is declared at the top of DuckDuckGo.swift.
  6. Finally, tell the result type to parse the definition out of the provided JSON object.

Note: If you’re wondering why the skip_disambig parameter exists, it’s to tell DuckDuckGo not to return ‘disambiguation’ results.

Disambiguation results are like those pages you see on Wikipedia: did you mean Chris Evans the movie actor, Chris Evans the British TV personality, or Chris Evans the train robber?

skip_disambig means the API will just pick the most likely result and return it.

Build and run! Once the app starts, enter a search term in the search bar; perhaps try “Duck”, or “Carthage”. If everything’s working correctly, you should see a definition on the next screen.

DuckDuckDefine Search Results - No Thumbnail

There’s one thing missing, however: a picture! It’s one thing being able to read what a duck is, but who reads anymore? Pictures are worth — okay, I’ll spare you the cliché — you know what I mean.

Anyways, who doesn’t like looking at pictures of ducks? Kittens are so last season, right?

Open DefinitionViewController.swift, and add import Alamofire just below the existing UIKit import at the top:

import Alamofire

Then, at the bottom of viewDidLoad(), add the following:

if let imageURL = definition.imageURL {
  Alamofire.request(.GET, imageURL).response { _, _, data, _ in
    self.activityIndicator.stopAnimating()
 
    if let data = data as? NSData {
      let image = UIImage(data: data)
      self.imageView.image = image
    }
  }
}

This code unwraps the definition’s image URL if it has one and performs a GET request to fetch the image. If the request successfully returns data, then it’s used to construct an image and display it in the image view.

Build and run, and perform your search again.

DuckDuckDefine Search Results

Quack quack!

 Where To Go From Here?

You can download the complete project here.

Congratulations, you’ve learnt about the philosophy behind dependency management and behind Carthage itself, gained some experience using Carthage to add some dependencies to a project, and used those dependencies to make a useful app!

You also know how to update your dependencies for future releases.

If you want to learn more about Carthage, your first stop should be the Carthage README and the documentation on Build Artifacts.

Justin Spahr-Summers, one of the project’s founders, gave a smashing talk at Realm.io about Carthage, entitled “Ruthlessly Simple Dependency Management.”

Finally, if you’d like to learn more about CocoaPods for a different take on iOS dependency management, be sure to check out our tutorial on How To Use CocoaPods With Swift. It also contains a great section on Semantic Versioning, which you saw in use in Cartfiles.

I hope you got a lot out of this Carthage tutorial. If you have any questions or comments, please join in the forum discussion below!

The post Carthage Tutorial: Getting Started appeared first on Ray Wenderlich.

Google Maps iOS SDK Tutorial: Getting Started

$
0
0

Update July 11, 2015: Updated for Xcode 6.4, iOS 8.4, and Google Maps SDK 1.10.1

Main2

Up to iOS 5, Google Maps was an integral part of iOS and was the mapping engine used by all iOS devices. With the release of iOS 6 in 2012, Apple made a dramatic change and replaced Google Maps with an in-house mapping engine.

Just a few months later, Google released its own standalone Google Maps app for iOS, along with the Google Maps iOS SDK for developers.

There are benefits and drawbacks to both MapKit and the Google Maps iOS SDK, but this tutorial will walk you through implementing Google Maps into your apps to see for yourself how well it can work in your geolocating apps.

In this tutorial, you’ll build an app called Feed Me, which gets the user’s current location and searches for nearby places to eat, drink, or even go grocery shopping. The results will be presented in-app using the Google Maps iOS SDK.

This tutorial assumes some familiarity with Swift and iOS programming. If you’re new to Swift, or to iOS programming altogether, you might want to check out some of our other tutorials before continuing.

This tutorial also requires familiarity with Cocoapods. You must have Cocoapods installed in order to follow this tutorial. To learn more about Cocoapods, check out this tutorial by Joshua Greene, published right here on the site.

This tutorial uses Xcode 6.4 and iOS 8.4, and requires knowledge of Auto Layout, Size Classes, and of course, Swift.

Getting Started

Download the Feed Me Starter Project This project already uses Cocoapods, so open it using the Feed Me.xcworkspace file.

Take a look around to get familiar with the project. The important elements to notice are:

  • MapViewController.swift: This is the main view controller of this project, and you’ll only be working with this controller in this tutorial.
  • GoogleDataProvider.swift: This is a wrapper class for making Google API calls. You’ll review the methods contained within later in the tutorial.
  • GooglePlace.swift: This is a model for place results returned from Google.
  • MarkerInfoView.swift: This is a subclass of UIView that displays details of places. It comes with a matching xib file.

Before you start coding it’s a good idea to see how the app works. Build and run your app; you’ll see the following screen appear:

GoogleMaps_update_GettingStarted_01

Right now all you’ll see is a blank screen with a pin in the middle. Press the action button on the right side of the navigation bar to see the TypesTableViewController screen like so:

GoogleMaps_GettingStarted_02

That’s all there is to see in the app at the moment — it’s up to you to add some magic!

Creating API Keys

The first thing you’ll need are some API keys for the Google Maps SDK and the Google APIs you’ll be using. If you don’t already have a Google account, create one (they’re free!) and log in to the Google Developers Console.

Click on Create Project, name your project Feed Me, and click Create:

GoogleMaps_update_APIKeys_01

Select APIs & auth and then APIs from the left pane menu. Search and enable these APIs:

  • Google Maps SDK for iOS
  • Google Places API Web Service

Now switch to the Enabled APIs tab, and verify that your screen now looks like the following:

Screen Shot 2015-07-13 at 18.53.54

Select Credentials under APIs & auth in the left pane menu. Click Create new key, and then click iOS key to create the Google Maps SDK key:

GoogleMaps_APIKeys_03

Enter the starter project’s bundle identifier (tutorial.feedme.com) and click Create:

GoogleMaps_APIKeys_04

Create another key, only this time choose Server key to create the Places API key. Leave the text box empty and click Create. You should now have two boxes with server and iOS keys, like this:

API_KEYS_SERVER

You’ll use both keys in a moment, but first you’ll add the actual Google Maps iOS SDK.

Adding the SDK

Open Podfile (in the Pods project) and add the following, right above end:

pod 'GoogleMaps'

Next, Open Terminal and navigate to the directory that contains your Feed Me project by using the cd command:

cd ~/Path/To/Folder/Containing/Feed Me

Enter the following command to install the Google Maps iOS SDK:

pod install

You should see output similar to the following:

Downloading dependencies
Installing GoogleMaps (1.10.1)
Using SwiftyJSON (2.2.0)
Generating Pods project
Integrating client project

You now have GoogleMaps in your project. Doesn’t Cocoapods make life a whole lot easier? :]

Before you start writing some actual code, you need to create a bridging header and add Google Maps to it. This is because Google Maps is written in Objective-C, and you need to make it available for your Swift code.

Select the Feed Me folder in the Navigator and select File\New\File…, then choose the iOS\Source\Objective-C File template. Name the file whatever you like, you’ll delete this file in a moment, and then save it. When saving the file, Xcode offers to create an Objective-C bridging header file for you like so:

GoogleMaps_AddingMaps_04

Click Yes and Xcode will create the bridging header file and add it to your project. Delete the Objective-C files (.h & .m) you just created as you no longer need then.

Open the newly created Feed Me-Bridging-Header.h and add the following line of code to the bottom of the file:

#import <GoogleMaps/GoogleMaps.h>
Note: While you should be able to start using the Google Maps SDK at this stage, there is one more step you need to take because of a bug in Cocoapods. In the Project Navigator, select the Feed Me project at the top. Choose the Feed Me target, select the Build Settings tab, and in Other Linker Flags add -ObjC as shown below:

linker

Hopefully this issue will be resolved in a future update to Cocoapods, and the tutorial will be updated accordingly.

The Google Maps iOS SDK is now available in your Swift app — it’s finally time to write some code! :]

Open AppDelegate.swift and replace it’s contents with the following:

import UIKit
 
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
 
  var window: UIWindow?
  // 1
  let googleMapsApiKey = "YOUR_GOOGLE_IOS_API_KEY"
 
  func application(application: UIApplication, didFinishLaunchingWithOptions 
      launchOptions: [NSObject: AnyObject]?) -> Bool {
    // 2
    GMSServices.provideAPIKey(googleMapsApiKey)
    return true
  }
}

There are two new elements here:

  1. A constant to hold your Google iOS API key. Replace YOUR_GOOGLE_IOS_API_KEY with the Google iOS API key you created earlier.
  2. Your app will instantiate Google Maps services with the API Key using the GMSServices class method provideAPIKey().

Next, open Main.storyboard to bring up Interface Builder. Bring up the Object Library by selecting the third tab in the view toolbar — Utilities — and then select the third tab in the library toolbar — Object Library — as shown in the screenshot below:

GoogleMaps_update_AddingMaps_05

Locate the MapViewController scene and drag a simple UIView from the Object Library to the approximate center of the MapViewController’s view. Change the view’s background color to light gray. Next, open the Document Outline using Editor\Show Document Outline and re-order the view hierarchy so that the object tree looks like this:

GoogleMaps_AddingMaps_06

To turn this simple UIView into a GMSMapView, select the view you just added and open the Identity Inspector by selecting the third tab from the left in the Utilities toolbar. Change the view’s Class to GMSMapView, as shown in the screenshot below:

GoogleMaps_update_AddingMaps_06

Your MapViewController scene should now look like this:

GoogleMaps_update_AddingMaps_08

Next, you’ll need to add some constraints to make the map fill the entire screen. Select Map View in the Document Outline and then choose the second button from the left in the bottom right of the Interface Builder window — the Pin button. Ensure that Constrain to margins is unchecked — this ensures that the map will fill all the available space on the screen — and add 0 (zero) space constraints from the top, left, bottom and right of the superview.

Your Pin editor should look like this:

Screen Shot 2015-07-13 at 21.14.33

Click on Add 4 Constraints to add the constraints to the map view. To update the frame, select the button to the right of the Pin button — the Resolve Auto Layout Issues button — and select Update Frames.

Your MapViewController scene should look like the following, where the gray area represents the GMSMapView:

GoogleMaps_update_AddingMaps_09

Before you build and run the project, add an IBOutlet for the map view. To do that, bring up the Assistant Editor by selecting the second tab in the Editor toolbar:

GoogleMaps_update_AddingMaps_12

Select the map view in Interface Builder, hold down the Ctrl key and drag a line from the map view to MapViewController.swift. A popup will appear; set the connection type to Outlet and the name to mapView. Keep the Type as GMSMapView, and click Connect:

GoogleMaps_AddingMaps_13

This will create a GMSMapView property in MapViewController.swift and automatically hook it up in Interface Builder. Build and run your project; you should now see a map, like so:

GoogleMaps_update_AddingMaps_14

You’re now using the Google Maps iOS SDK in your app — but you can do more than show a basic map, right? :]

Getting the Location

Feed Me is all about finding places near the user, and you can’t do that without getting the user’s location.

First, open MapViewController.swift and add the following property:

let locationManager = CLLocationManager()

This will add and instantiate a CLLocationManager property named locationManager.

Next, find viewDidLoad() and add these two lines to the bottom:

locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()

This will make MapViewController the delegate of locationManager and request access to the user’s location.

Next, open the Feed Me project at the top of the Navigator, select the Feed Me target and go to the Info tab, select the first line in the Custom iOS Target Properties section and click the + icon to add a new row.

Enter NSLocationWhenInUseUsageDescription as the key, choose String for the type, and enter the following text as the value:
By accessing your location, this app can find you a good place to eat.

When you’re finished, it should look something like this:

Custom iOS Target Properties

Note: For more information on the changes to CLLocationManager in iOS 8, check out the class documentation.

Before you can run the app, you need to make MapViewController conform to the CLLocationManagerDelegate protocol.

Add the following extension to the bottom of MapViewController.Swift:

// MARK: - CLLocationManagerDelegate
//1
extension MapViewController: CLLocationManagerDelegate {
  // 2
  func locationManager(manager: CLLocationManager!, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
    // 3
    if status == .AuthorizedWhenInUse {
 
      // 4
      locationManager.startUpdatingLocation()
 
      //5
      mapView.myLocationEnabled = true
      mapView.settings.myLocationButton = true
    }
  }
 
  // 6
  func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
    if let location = locations.first as? CLLocation {
 
      // 7
      mapView.camera = GMSCameraPosition(target: location.coordinate, zoom: 15, bearing: 0, viewingAngle: 0)
 
      // 8
      locationManager.stopUpdatingLocation()
    }
  }
}

Taking each numbered comment in turn:

  1. You create a MapViewController extension that conforms to CLLocationManagerDelegate.
  2. locationManager(_:didChangeAuthorizationStatus:) is called when the user grants or revokes location permissions.
  3. Here you verify the user has granted you permission while the app is in use.
  4. Once permissions have been established, ask the location manager for updates on the user’s location.
  5. GMSMapView has two features concerning the user’s location: myLocationEnabled draws a light blue dot where the user is located, while myLocationButton, when set to true, adds a button to the map that, when tapped, centers the map on the user’s location.
  6. locationManager(_:didUpdateLocations:) executes when the location manager receives new location data.
  7. This updates the map’s camera to center around the user’s current location. The GMSCameraPosition class aggregates all camera position parameters and passes them to the map for display.
  8. Tell locationManager you’re no longer interested in updates; you don’t want to follow a user around as their initial location is enough for you to work with.

Build and run your app; once it loads you’ll be prompted with an alert, asking for location permissions. Tap on Allow:

GoogleMaps_update_Location_01

You should now see a map centering around your location. Scroll the map and tap the Locate button and the map will center back to your location like so:

GoogleMapsSwift1_update

Implementing Geocoding

Now that you have the user’s location, it would be nice if you could show the street address of that location. Google has an object that does exactly that: GMSGeocoder. This takes a simple coordinate and returns a readable street address.

First, you’ll need to add some UI to present the address to the user.

Open Main.storyboard and add a UILabel to the MapViewController scene. Make sure you add the label to the MapViewController view, and not the GMSMapView.

Next, open the Attributes Inspector, and give the label the following attributes:

  • Set Alignment to center.
  • Set Lines to 0. Surprisingly, this lets the label take up as many lines as it needs to fit the text. Go figure! :]
  • Set Background to white with 85% opacity.

The label’s Attributes Inspector and the scene’s Object Tree should look like this when done:

GoogleMaps_Geocoding_01

Map View Controller Scene

Finally, add to the label left, bottom and right constraints of 0 as shown below:

GoogleMaps_Geocoding_02

This pins the label to the bottom of the screen and stretches it over the entire width of the screen. Update the frames and continue.

Your storyboard scene should look like the following:

Screen Shot 2015-07-13 at 17.21.24

Next, create an outlet for the label. Select the Assistant Editor, and ctrl+drag from the label in the Document Outline to MapViewController.swift. Set the connection type to Outlet, the name to addressLabel and click Connect.

This adds a property to your MapViewController that you can use in your code:

@IBOutlet weak var addressLabel: UILabel!

Add the method below to MapViewController.swift:

func reverseGeocodeCoordinate(coordinate: CLLocationCoordinate2D) {
 
  // 1
  let geocoder = GMSGeocoder()
 
  // 2
  geocoder.reverseGeocodeCoordinate(coordinate) { response, error in
    if let address = response?.firstResult() {
 
      // 3
      let lines = address.lines as! [String]
      self.addressLabel.text = join("\n", lines)
 
      // 4
      UIView.animateWithDuration(0.25) {
        self.view.layoutIfNeeded()
      }
    }
  }
}

Once again, here’s what each commented section does:

  1. Creates a GMSGeocoder object to turn a latitude and longitude coordinate into a street address.
  2. Asks the geocoder to reverse geocode the coordinate passed to the method. It then verifies there is an address in the response of type GMSAddress. This is a model class for addresses returned by the GMSGeocoder.
  3. Sets the text of the addressLabel to the address returned by the geocoder.
  4. Once the address is set, animate the changes in the label’s intrinsic content size.

You’ll want to call this method every time the user changes their position on the map. To do so you’ll use GMSMapViewDelegate.

Add another extension to the bottom of MapViewController.swift as follows:

// MARK: - GMSMapViewDelegate
extension MapViewController: GMSMapViewDelegate {
 
}

This will declare that MapViewController conforms to the GMSMapViewDelegate protocol.

Next, add the following line of code to viewDidLoad():

mapView.delegate = self

This makes MapViewController the map view’s delegate.

Finally, add the following method to the newly added extension:

func mapView(mapView: GMSMapView!, idleAtCameraPosition position: GMSCameraPosition!) {
  reverseGeocodeCoordinate(position.target)
}

This method is called each time the map stops moving and settles in a new position, where you then make a call to reverse geocode the new position and update the addressLabel‘s text.

Build and run your app; you’ll see the address of your current location — real or simulated — pop up at the bottom of the screen:

iOS Simulator Screen Shot Jul 13, 2015, 17.52.57

Notice anything wrong with this picture?

Solution Inside SelectShow>

Fortunately, GMSMapView provides a very simple solution for this: padding. When padding is applied to the map, all of the visual elements will be placed according to that padding.

Head back to reverseGeocodeCoordinate(_:), and make these changes to the animation block:

// 1
let labelHeight = self.addressLabel.intrinsicContentSize().height
self.mapView.padding = UIEdgeInsets(top: self.topLayoutGuide.length, left: 0, 
    bottom: labelHeight, right: 0)
 
UIView.animateWithDuration(0.25) {
  //2
  self.pinImageVerticalConstraint.constant = ((labelHeight - self.topLayoutGuide.length) * 0.5)
  self.view.layoutIfNeeded()
}

This does two things:

  1. Prior to the animation block, this adds padding to the top and bottom of the map. The top padding equals the navigation bar’s height, while the bottom padding equals the label’s height.
  2. Updates the location pin’s position to match the map’s padding by adjusting its vertical layout constraint.

Build and run your app again; this time the Google logo and locate button will move to their new position once the label becomes visible:

iOS Simulator Screen Shot Jul 13, 2015, 17.53.08

Move the map around; you’ll notice that the address changes every time the map settles to a new position. Let’s add a visual effect to dampen the address changing.

Add the following method to the GMSMapViewDelegate extension:

func mapView(mapView: GMSMapView!, willMove gesture: Bool) {
  addressLabel.lock()
}

This method is called every time the map starts to move. It receives a Bool that tells you if the movement originated from a user gesture, such as scrolling the map, or if the movement originated from code. You call the lock() on the addressLabel to give it a loading animation.

When there’s a lock(), there must also be an unlock(). Add the following to the top of reverseGeocodeCoordinate(_:)‘s closure:

func reverseGeocodeCoordinate(coordinate: CLLocationCoordinate2D) {
  let geocoder = GMSGeocoder()
  geocoder.reverseGeocodeCoordinate(coordinate) { response, error in
 
    //Add this line
    self.addressLabel.unlock()
 
    //Rest of response handling
  }
}
Note: For the full implementation of the lock() and unlock(), check out UIViewExtensions.swift.

Build and run your app; as you scroll the map you should see a loading animation on the address label like so:
iOS Simulator Screen Shot Jul 13, 2015, 18.01.59

Finding Something to Eat

Now that the map is set up and you have the user’s location in hand, it’s time to get this user fed!

You’ll use the Google Places API to search for places to eat and drink around the user’s location. Google Places API is a free web service API you can use to query to find establishment, geographic locations, or other points of interest near any given point.

Unfortunately, Google does prohibit direct usage of this API from mobile apps, and allows usage only from server-side apps. This means that in order to use this service, you will have to use your own server to fetch the results, and query that server from your iOS app.

Note: For more information on the Google Places API, check out the official documentation.

Since writing the server is out of scope for this tutorial, I have supplied you with the server code, written in Dart. Let’s go over the steps for running the server:

  1. Download the server code.
  2. To install Dart, you’ll use Homebrew. Homebrew is a package manager for mac that allows simple installation of various packages. If you do not already have it installed, open Terminal and run:
    ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
  3. When Homebrew is done installing, run the following command in Terminal:
    brew tap dart-lang/dart
  4. Install Dart by running the following command in Terminal:
    brew install dart
  5. Next, locate the path where you downloaded the server code to, and open it in terminal:
    cd [PATH_TO_SERVER_CODE]
  6. Install the server code by running the following in Terminal:
    pub install
  7. Finally, run the server with the following command:
    pub run bin/main.dart -k [YOUR_API_KEY] -p 10000

    Replace YOUR_API_KEY with the server key you created earlier

Note: For more information, checkout the readme.md file in places_api_key_proxy folder you downloaded in step 1.

If everything went well, you should see the following in you Terminal window:
Server_Google_Maps_iOS_2

To check that querying the Google Places API works, click here. You should see the query result in a format of JSON. If you open your Terminal window you’ll see some logs:
Server_Google_Maps_iOS_3

Note: You must keep the terminal window open while running your app. If you close it, follow steps 5 & 7 to run the server again.
Note: The current configuration will allow you to run the server from the iPhone simulator. To run it from a device, locate GoogleDataProvider.swift, search for localhost and replace it with your mac’s ip address. In addition, make sure you’re connected to the same WiFi network on both your mac and iOS device.

Now that you can query places from Google, let’s go back to the Feed Me project.
Google Maps iOS SDK provides you with the GMSMarker class to mark locations on a map. Each marker object holds a coordinate and an icon image and renders on the map when added.

For this app you’ll need some more info on each marker, so you’ll need to create a subclass of GMSMarker.

Create a new Cocoa Touch Class, name it PlaceMarker and make it a subclass of GMSMarker. Ensure you choose Swift as the language for this file.

Replace the contents of PlaceMarker.swift with the following:

class PlaceMarker: GMSMarker {
  // 1
  let place: GooglePlace
 
  // 2
  init(place: GooglePlace) {
    self.place = place
    super.init()
 
    position = place.coordinate
    icon = UIImage(named: place.placeType+"_pin")
    groundAnchor = CGPoint(x: 0.5, y: 1)
    appearAnimation = kGMSMarkerAnimationPop
  }
}

This is a relatively straightforward bit of code:

  1. Add a property of type GooglePlace to the PlaceMarker.
  2. Declare a new designated initializer that accepts a GooglePlace as its sole parameter and fully initializes a PlaceMarker with a position, icon image, anchor for the marker’s position and an appearance animation.

Next, add two more properties to MapViewController.swift as follows:

let dataProvider = GoogleDataProvider()
let searchRadius: Double = 1000

You’ll use dataProvider to make calls to the Google Places API, and searchRadius to determine how far from the user’s location to search for places.

Add the following method to MapViewController.swift:

func fetchNearbyPlaces(coordinate: CLLocationCoordinate2D) {
  // 1
  mapView.clear()
  // 2
  dataProvider.fetchPlacesNearCoordinate(coordinate, radius:searchRadius, types: searchedTypes) { places in
    for place: GooglePlace in places {
      // 3
      let marker = PlaceMarker(place: place)
      // 4
      marker.map = self.mapView
    }
  }
}

Let’s go over what you just added:

  1. Clear the map of all markers.
  2. Use dataProvider to query Google for nearby places around the searchRadius, filtered to the user’s selected types.
  3. Enumerate through the results returned in the completion closure and create a PlaceMarker for each result.
  4. Set the marker’s map. This line of code is what tells the map to render the marker.

Here’s the $64,000 question — when do you want to call this method?

First, the user can reasonably expect to see places nearby when the app launches.

Locate locationManager(_:didUpdateLocations:) and add the following line of code at the end, within the if let statement:

fetchNearbyPlaces(location.coordinate)

Second, the user has the ability to change the types of places to display on the map, so you’ll need to update the search results if the selected types change.

Locate typesController(_:didSelectTypes:) and add the following line of code to the end:

fetchNearbyPlaces(mapView.camera.target)

Finally, you’ll need to give the user the option to fetch new places when their location changes.

Open Main.storyboard and drag a UIBarButtonItem from the Object Library to the left side of the MapViewController’s navigation bar. Change the button’s Identifier to Refresh, as shown below:

Screen Shot 2015-07-13 at 18.25.44

Select the Assistant Editor and ctrl+drag from the Refresh button to MapViewController.swift. Choose Action and name the method refreshPlaces. Replace the contents of the newly added method with the following:

@IBAction func refreshPlaces(sender: AnyObject) {
  fetchNearbyPlaces(mapView.camera.target)
}

Build and run your project; you’ll see location pins popping up around the map. Change the search types in the TypesTableViewController and see how the results change:

iOS Simulator Screen Shot Jul 13, 2015, 18.30.13

Note: If you do not see any of the locations appear, you can debug the issue by opening GoogleDataProvider.swift and underneath the line of code that serializes the json object, print the error to the console by adding the following: println(json["error_message"]).

All these markers sure add some color to the map, but they’re not much use without additional info to give the user some details on the pinned location.

Add the following method to the GMSMapViewDelegate extension in MapViewController.swift:

func mapView(mapView: GMSMapView!, markerInfoContents marker: GMSMarker!) -> UIView! {
  // 1
  let placeMarker = marker as! PlaceMarker
 
  // 2
  if let infoView = UIView.viewFromNibName("MarkerInfoView") as? MarkerInfoView {
    // 3
    infoView.nameLabel.text = placeMarker.place.name
 
    // 4
    if let photo = placeMarker.place.photo {
      infoView.placePhoto.image = photo
    } else {
      infoView.placePhoto.image = UIImage(named: "generic")
    }
 
    return infoView
  } else {
    return nil
  }
}

This method is called each time the user taps a marker on the map. If you return a view, then it pops up above the marker. If nil is returned, nothing happens. How does that happen?

  1. You first cast the tapped marker to a PlaceMarker.
  2. Next you create a MarkerInfoView from its nib. The MarkerInfoView class is a UIView subclass that comes with the starter project for this tutorial.
  3. Then you apply the place name to the nameLabel.
  4. Check if there’s a photo for the place. If so, add that photo to the info view. If not, add a generic photo instead.

Before you run the app, you want to make sure the location pin doesn’t cover the info window. Add the following method to the GMSMapViewDelegate extension:

func mapView(mapView: GMSMapView!, didTapMarker marker: GMSMarker!) -> Bool {
  mapCenterPinImage.fadeOut(0.25)
  return false
}

This method simply hides the location pin when a marker is tapped. The method returns false to indicate that you don’t want to override the default behavior — to center the map around the marker — when tapping a marker.

Obviously, the pin needs to re-appear at some point. Add the following to the end of mapView(_:willMove:):

if (gesture) {
  mapCenterPinImage.fadeIn(0.25)
  mapView.selectedMarker = nil
}

This checks if the movement originated from a user gesture; if so, it un-hides the location pin using the fadeIn(_:) method. Setting the map’s selectedMarker to nil will remove the currently presented infoView.

Finally, add the following method to the GMSMapViewDelegate extension:

func didTapMyLocationButtonForMapView(mapView: GMSMapView!) -> Bool {
  mapCenterPinImage.fadeIn(0.25)
  mapView.selectedMarker = nil
  return false
}

This method runs when the user taps the Locate button; the map will then center on the user’s location. Returning false again indicates that it does not override the default behavior when tapping the button.

Build and run your app; select a marker and you’ll see the location pin fade out. Scrolling the map closes the infoView and brings the pin back:
iOS Simulator Screen Shot Jul 13, 2015, 18.37.52

That’s it, you’ve done it! You now have a fully functioning Google Maps app. :]

Where To Go From Here?

Here’s a link to the complete project from this tutorial.

Keep in mind that before you’re able to run this finished project, you will need to insert your API keys as you did at the beginning of this tutorial.

Our purpose here is not to convince you that Google Maps SDK is better than Apple’s own MapKit; however, here’s a few pros and cons of Google Maps:

Pros

  • Frequent Updates to the SDK by Google.
  • Uniform experience for cross platform (iOS and Android) apps.
  • Google Maps are often more detailed, especially outside the United States. For example:
    Compare_Apple Compare_Google

Cons

  • Unlike Google Maps, MapKit is native to iOS, which means it’s always synced with iOS and works with Swift out of the box.
  • Lack of stability in comparison to MapKit.
  • MapKit has a much better integration with CoreLocation and CoreAnimation.

This tutorial only showed you the basics of what the Google Maps SDK can do. There’s much more to learn; you should definitely check out the full documentation for more cool features the SDK has to offer.

Among the other things you can do with Google Maps are showing directions, indoor maps, overlays, tile layers, Street View, and advanced integration with the Google Maps app. For brownie points, try to use some of these features to enhance the Feed Me app.

If you have any questions, tips, or just wanna show off your cool mapping app, feel free to post about it in the discussion below!

The post Google Maps iOS SDK Tutorial: Getting Started appeared first on Ray Wenderlich.

Video Tutorial: Intermediate Core Data Part 6: Conclusion


Introducing the iOS 9 Feast!

$
0
0

It’s the iOS 9 release date, and you know what that means: time to party!

This year marks our 5th annual iOS release celebration: the iOS 9 Feast.

Introducing the iOS 9 Feast!

The iOS 9 Feast consists of 9 courses:

  • Appetizers: Beginning UIStackView & tvOS Tutorials
  • First Course: iOS Apprentice Fourth Edition
  • Second course: iOS Animations by Tutorials Second Edition
  • Third course: Core Data by Tutorials Second Edition
  • Fourth course: iOS 9 by Tutorials
  • Fifth course: watchOS 2 by Tutorials
  • Sixth course: Swift Apprentice
  • Seventh course: 2D iOS & tvOS Games by Tutorials
  • Eighth course: iOS 9 Tutorial Month
  • Dessert: iOS 9 Feast Giveaway

During the iOS 9 Feast, we’ll help you get fully up-to-speed with iOS 9, Swift 2, tvOS, and watchOS 2 development, no matter how you prefer to learn. You’ll learn about UIStackView, iOS 9 Search APIs, Swift 2 error handling, GameplayKit, and much more.

Plus, we have over $17,000 in giveaways for lucky readers – our biggest giveaway yet!

Appetizers: Beginning UIStackView & tvOS Tutorials

UIStackView Tutorial

One of the most exciting new features in iOS 9 is the brand new UIStackView class, which makes creating cool customized layouts a snap.

We think you’re going to love it, so Jawwad Ahmad from the Tutorial Team has written a beginning UIStackView tutorial to show you the basics.

This tutorial is currently scheduled to run later this month. But what if you want it right now?

All you have to do is retweet this post to help get the word out! If/when the post reaches 100 retweets, we will immediately post the UIStackView tutorial to whet your appetite.

Learn how to make your first tvOS app!

But wait – there’s more!

As you know the Tutorial Team and I have been digging into tvOS ever since it was launched last Wednesday.

Kelvin Lau has been hard at work from day one making an awesome tutorial to help get you started with making your own tvOS apps with TVML! If this post reaches 200 retweets, we’ll release Kelvin’s tvOS tutorial early as well.

Get started with tvOS and UIStackView early – just click the button below!


First Course: iOS Apprentice Fourth Edition

Still hungry? Don’t worry, we’ve got a full course ready for you: the iOS Apprentice Fourth Edition!

The iOS Apprentice Fourth Edition

The iOS Apprentice is our book for complete beginners to iOS development. It has a series of epic-length tutorials that each show you how to build four complete apps from scratch.

In this update, Matthijs has completely updated the text and illustrations for Xcode 7, iOS 9, and Swift 2 to help get you fully up-to-date with the latest and greatest improvements in Apple’s development environment and programming language.

And best of all – this book is 100% complete and available today!

This is a free update for existing PDF customers – you can download the update on your My Loot page.

Did you know that iOS Apprentice was first written for iOS 5, and Matthijs has updated it for every version of iOS since then for free? You can’t beat that value! :]

[Order Now]

Second Course: iOS Animations by Tutorials Second Edition

iOS Animations by Tutorials Second Edition

Next, we are happy to announce the second edition of Marin Todorov’s popular book iOS Animations by Tutorials!

iOS Animations by Tutorials teaches you how to make delightful animations in your apps with Swift 2. You start with basic view and layer animations, move all the way through Auto Layout animations, view controller transitions, and finally look into third party animation libraries like Facebook’s Pop.

In the second edition, Marin has added 3 brand new chapters to the book:

  • Layer Springs: A tour of the shiny new CASpringAnimation class in iOS 9, which allows you to easily create layer spring animations.
  • Replicating Animations: Introduces the little known but powerful CAReplicatorLayer class. This is one of Marin’s favorite animation classes so you’re in for some fun!
  • Easy Animation: Learn how to get started with a third party animation library written by Marin that makes building complex animations really easy.

This is a free update for existing PDF customers, as our way of thanking you for supporting this site.

As part of the iOS 9 Feast, we are releasing a new iOS 9 book each week. iOS Animations by Tutorials Second Edition will be released next Wednesday, Sep 23.

We can’t wait to show you the new edition of the book, and Marin and I hope you enjoy the new chapters!

[Order Now]

Third Course: Core Data by Tutorials Second Edition

Core Data by Tutorials Second Edition

There’s yet another update to announce – the second edition of Core Data by Tutorials!

Core Data by Tutorials teaches you everything you need to know about Core Data, starting with the basics like setting up your own Core Data Stack and moving all the way to advanced topics like syncing with iCloud, migration, performance, multithreading, and more.

The second edition of the book is fully updated for iOS 9 and Swift 2. Here are some of the changes in this update:

  • Swift 2. All code has now been updated to Swift 2. This includes using the new error handling model — moving away from the complexities of NSError.
  • New uniqueness model constraint. iOS 9 introduces the ability to specify that an attribute should be unique across all objects.
  • Bugfixes. All chapters have been fully re-tested and tech edited and are verified as 100% working.

This is also a free update for existing PDF customers, and will be released on Wednesday, Sep 30. We hope you enjoy! :]

[Order Now]

Fourth Course: iOS 9 by Tutorials

iOS 9 by Tutorials

So far we’ve been talking just about updates – now let’s talk about some new books!

The first new book is one you might have been able to guess :] That’s right, it’s our 5th installment of our popular iOS by Tutorials series!

iOS 9 by Tutorials is a book for intermediate and advanced iOS developers looking to learn the new APIs introduced in iOS 9 quickly and easily. Here’s a quick preview of what you’ll find in the book:

  • Introducing App Search: For too long, Spotlight search results have been the private kingdom of system apps. iOS 9 changes that with Core Spotlight – discover how to make your apps searchable.
  • Multitasking: Learn what changes you need to make to your apps to fully support the new multitasking capability of iOS 9.
  • UIStackView and Auto Layout Changes: Stack views will be the answer to 90% of your layout questions in iOS 9 – you’ll wonder how you ever survived without them. Get the fast-track to layout nirvana!
  • Testing: In addition to unit tests, Xcode 7 allows you to test the UI of your app. Find out how to use this new tool to improve the reliability of your app.
  • App Thinning: Give your apps a diet! Discover how to ensure that users are downloading just the bits the app actually needs from the App Store.
  • And much more: Including what’s new in storyboards and Xcode, the new Contacts framework, and improvements to mapping!

This book is a result of the hard work of 9 members of the tutorial team, dividing and conquering the material. We went through the school of hard knocks, so you don’t have to!

iOS 9 by Tutorials will be released Wednesday, Oct 7. We can’t wait to show you the book, and we look forward to seeing you use these cool new iOS 9 APIs in your own apps.

[Order Now]

Fifth Course: watchOS 2 by Tutorials

watchOS 2 by Tutorials

This year at WWDC, Apple introduced watchOS 2, which signifies a huge change for Apple Watch developers. Now, you can make native apps that run directly on your watch.

The switch to watchOS 2 represents a significant switch in how Apple Watch development is done, making much of our previous book WatchKit by Tutorials obsolete.

But we knew you guys would want an up-to-date resource on how to make Apple Watch apps, so we decided to make a new book – watchOS 2 by Tutorials!

watchOS 2 by Tutorials contains 11 chapters from WatchKit by Tutorials heavily revised and updated for watchOS 2, along with 17 brand new chapters covering new functionality in watchOS 2, such as:

  • Pickers: Learn how to interact directly with the Digital Crown using the new Picker interface object.
  • Complications: Learn how to put the most important details of your app front and center, directly on the user’s chosen watch face with custom complications.
  • Watch Connectivity: As watch apps now run exclusively on the watch, there’s a whole new framework dedicated to device-to-device communication, and we’ve got it covered!
  • Animation: Learn how to take full advantage of the new animation API in watchOS 2 to add some extra juice to your watch apps.
  • Audio and Video: With watchOS 2, you can now play audio and video on the watch. Learn everything you need to know in this chapter.
  • And much more…: We’ve stepped things up a gear with this new book and introduced several “advanced” chapters on topics such as tables, layout, and animation!

The result is a whopping 28 chapters of content – the most comprehensive watchOS book on the market!

This book is not a free update since most of the book is completely new; it’s closer to a new book than an update. However, we are offering this book at 50% off for WatchKit by Tutorials PDF customers to thank you for your support – we’ll send you a coupon code on the release day.

watchOS 2 by Tutorials will be released Wednesday, Oct 14 – set a reminder on your watches! :]

[Order Now]

Sixth Course: Swift Apprentice

The Swift Apprentice

Last year, we wrote a book called Swift by Tutorials. This book was geared toward intermediate to advanced iOS developers who already knew Objective-C iOS development, but wanted to quickly transition to Swift.

Now that Swift is open source and growing in popularity, this restriction of prior iOS/Objective-C experience just doesn’t make sense. So we decided to rethink the book completely, and rewrite it from scratch – enter the Swift Apprentice!

The Swift Apprentice is a book geared toward complete beginners to Swift. The book focuses on the core language itself, and platform agnostic – for example, all examples in the book run in Playgrounds!

Here’s a sneak peak of what’s in the book:

  • Coding Essentials & Playground Basics: We start you off right at the beginning so you can get up to speed with programming basics and learn how to work with Playgrounds in Xcode.
  • Structures: The Swift standard library is filled with structs – learn about this fundamental building block in Swift with topics such as properties, methods, and value semantics.
  • Collections: Why have only one of a thing when you could have many? Learn about the Swift collection types – sets, dictionaries, and arrays – including what they’re good for, how to use them, and when to use each.
  • Error Handling: Swift has native error handling build right into the language. Learn how to signal errors to callers, as well as how to handle errors from upstream to keep your apps safe and crash-proof.
  • Functional Programming: Swift is a multi-paradigm language and is a great place to try your hand with functional techniques. Learn the basics of methods such as map in addition to the theory behind things like first-class functions and currying.
  • And much more!: We’ll take you through the fundamental topics such as optionals, methods, properties, and enumerations while still keeping the big-picture in mind with generics and protocol-oriented programming.

Swift Apprentice is a completely new book, in a very different style from Swift by Tutorials. However, since there’s some overlap in the topics covered between these two books, we’re offering a 50% off discount for Swift by Tutorials customers to thank you for your support – we’ll send you a coupon code on the release day.

The Swift Apprentice will be released Wednesday, Oct 21 – get your Playgrounds ready! :]

[Order Now]

Seventh Course: 2D iOS & tvOS Games by Tutorials

2D iOS & tvOS Games by Tutorials

As a gamer, to me the biggest and most exciting changes released in iOS 9 this year was the new GameplayKit APIs. These are a set of APIs that make it easy to add pathfinding, AI, and other cool features into your games.

Then there’s the elephant in the room – tvOS, which now allows us to create games for the living room!

These changes were so significant that rather than trying to give them a token coverage in an update to iOS Games by Tutorials, we decided it would be better to revamp the book completely. Enter 2D iOS & tvOS Games by Tutorials!

2D iOS & tvOS Games by Tutorials teaches you everything you need to know about SpriteKit, GameplayKit, and related APIs like Game Center and ReplayKit. The book contains the classic games Zombie Conga, Cat Nap, and Circuit Racer (with plenty of updates along the way), but also introduces three new games to highlight the power of GameplayKit:

  • Drop Charge: Escape from an exploding alien spaceship, learning about the scene editor, juice, and GamePlayKit state machines along the way!
  • Dino Defense: Protect your village from an onslaught of dinosaurs in this tower defense game with GamePlayKit pathfinding and entity/component system!
  • Delver: Try to find your way through a procedurally-generated dungeon before you are destroyed by hordes of monsters!

This book is not a free update since over half of the book is completely new; it’s closer to a new book than an update. However, we are offering this book at 50% off for iOS Games by Tutorials PDF customers to thank you for your support – we’ll send you a coupon code on the release day.

2D iOS & tvOS Games by Tutorials will be released Wednesday, Oct 28 – get ready to game on! :]

[Order Now]

Eighth Course: iOS 9 Tutorial Month

That all sounds great,” you may think, “but what about video tutorials and written tutorials?”

Don’t worry, we’ve got you covered as well :]

For the next month, we will be releasing a new book every Wednesday, a new video tutorial series every Thursday, and a new written tutorial every other day of the week!

iOS 9 Tutorial Month

Here’s the release schedule for your convenience:

  • Week of 9/16: iOS Apprentice Fourth Edition, Beginning Swift 2 Video Tutorial Series
  • Week of 9/23: iOS Animations by Tutorials Second Edition, Intermediate Swift 2 Video Tutorial Series
  • Week of 9/30: Core Data by Tutorials Second Edition, iOS 9 101 Video Tutorial Series
  • Week of 10/7: iOS 9 by Tutorials, Custom Controls Video Tutorial Series
  • Week of 10/14: watchOS 2 by Tutorials, Unit Testing Video Tutorial Series
  • Week of 10/21: Swift Apprentice, Auto Layout in iOS 9 Video Tutorial Series
  • Week of 10/28: 2D iOS Games by Tutorials, Table Views in iOS 9 Video Tutorial Series

Be sure to check back every day for a new free tutorial, book, or video tutorial series.

Dessert: iOS 9 Feast Giveaway

iOS 9 Feast Giveaway!

Last but not least, we have a particularly sweet ending to the feast this year.

I asked the Tutorial Team what their favorite iOS tools were, and then asked the teams behind these tools if they’d like to join the Feast on an invite-only basis.

Tons of folks were kind enough to donate copies of their tools to join in the celebration – making the most epic collection of iOS dev tools ever!

The grand prize winner will receive a massive prize pack of 44 prizes split into 13 categories:

Version Control Tools

  1. Tower 2 ($69 value): Version control with Git – made easy. In a beautiful, efficient, and powerful app.
  2. Gitbox ($15 value): Version control as easy as Mail: One-click commit, push and pull.

Continuous Integration

  1. Bitrise Lifetime Atlantis Subscription ($1545/year value): iOS Continuous Integration and Delivery for your whole team, with dozens of integrations for your favorite services.

App Localization

  1. Applanga 6 Month Pro Subscription ($330 value): Everything you need to make mobile app localization fast and easy.

iOS Controls

  1. ShinobiCharts ($395 value): Bring your app’s data to life with these professional chart components.
  2. ShinobiToolkit ($395 value): An excellent collection of UI controls to enhance your apps with features like Grids, Calendars, Carousels and Gauges.
  3. ShinobiForms ($199 value): Tools for building user input forms quickly and easily.

Other Development Tools

  1. Hopper ($89 value): A reverse engineering tool for OS X and Linux, that lets you disassemble, decompile and debug your 32/64bits Intel Mac, Linux, Windows and iOS executables.
  2. Reveal ($89 value) – A powerful runtime view debugging tool with advanced visualisations, comprehensive inspectors and the ability to modify applications on the fly.
  3. Paw (HTTP & REST Client) ($30 value): A handy app to test HTTP calls and RESTful APIs. It lets you send HTTP requests (like cURL), and generates NSURLConnection or AFNetworking code.
  4. Dash ($20 value): Instant offline access to documentation sets, and extremely handy snippet manager.

Design Tools

  1. Paint Code 2 ($100 value): PaintCode is a vector drawing app that generates Core Graphics code in real time.
  2. Principle for Mac ($99 value): Principle makes it easy to create animated and interactive user interface designs!
  3. Zeplin 6-month Subscription ($90 value): A tool that makes handing off designs from designers to developers much easier. Generate styleguides, and resources, automatically!
  4. Affinity Photo ($50 value) – Photo editing software that offers sophisticated tools for enhancing, editing and retouching your images in an incredibly intuitive interface.
  5. Affinity Designer ($50 value) – The fastest, smoothest, most precise vector graphic design software available; great for creating graphics for marketing materials, websites, icons, UI design or even cool concept art.
  6. AppCooker ($30 value): Design apps like a chef – right on your iPad!
  7. Pixelmator ($30 value) – An inspiring, easy-to-use, beautifully designed image editor that lets you enhance photos, sketch, draw and paint, add text and shapes, apply dazzling effects, and more!
  8. Acorn 5 ($25 value): An easy to use Mac image editor, designed for humans. With a ton of new features and refinements, you will make beautiful images in Acorn!
  9. Astropad for iPad ($20 value): Turn your iPad into a graphics tablet!
  10. Astropad for iPhone ($5 value): Turn your iPhone into a graphics tablet!
  11. Promotee ($5 value): Make your app’s promo art shine using this tool to create slick framed product shots.

Productivity Tools

  1. Monodraw ($20 value): A neat tool for creating diagrams, layouts, and flow charts – in ASCII art! :]
  2. Reflector 2 ($15 value): Easily mirror your iPad, iPhone, or Android devices wherever you want it – your Mac, Apple TV, Google Cast, or even live on YouTube!
  3. Soulver ($12 value): A handy app to help you play around with numbers, more conveniently than a traditional calculator.

Blogging Tools

  1. WordPress.com Premium 1-year subscription ($99 value): Create a beautiful website to promote your app with the same awesome software we use for our blog.

Game Tools

  1. Particle Designer 2 ($80 value): Create amazing particle systems for your games with a visual editor designed specifically for Mac OS X.
  2. Glyph Designer 2 1-year Subscription ($53 value): Design beautiful fonts for your iOS games.
  3. TexturePacker ($49 value): The sprite sheet creator that turns chaos into order!
  4. PhysicsEditor ($49 value): Edit your physics shapes with ease!
  5. SpriteIlluminator ($49 value): Create and edit normal maps and add dynamic light to your 2D games.

Conference tickets

  1. 360iDev ($799 value): A free ticket to 360iDev 2016 – an awesome 4-day event for app developers!
  2. Swift Summit ($799 value): A free ticket to your choice of 2016 Swift Summit: A gathering of the world’s top Swift developers, bloggers, book authors and teachers.
  3. RWDevCon ($899 value): A free ticket to our official raywenderlich.com conference: Come meet the team for some great hands-on tutorials, inspiration, and fun!

Books

  1. Swift Apprentice PDF & Print Versions ($108 value): A book for complete beginners to Apple’s brand new programming language – Swift 2.
  2. iOS Apprentice Fourth Edition PDF & Print Versions ($108 value): Learn how to make iPhone and iPad apps from the ground up, with a series of epic-length tutorials for beginners!
  3. iOS 9 by Tutorials PDF & Print Versions ($108 value): Learn about the new APIs in iOS 9 such as Core Spotlight, Multitasking, UIStackView, and App Thinning.
  4. watchOS 2 by Tutorials PDF & Print Versions ($108 value): Learn about WatchKit UI controls and layout, Glances, notifications, deep linking with Handoff, and more!
  5. Core Data by Tutorials Second Edition PDF & Print Versions ($108 value): Take control of your data in iOS apps using Core Data, Apple’s powerful object graph and persistence framework.
  6. iOS Animations by Tutorials Second Edition PDF & Print Versions ($108 value): Learn how to make iOS Animations in Swift 2 through a series of hands-on tutorials and challenges.
  7. 2D iOS & tvOS Games by Tutorials PDF & Print Versions ($108 value): Learn how to make your own iOS and tvOS games using Swift 2 and Apple’s game frameworks, Sprite Kit and GameplayKit.

Video Tutorials

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

Bonus Loot

  1. raywenderlich.com T-shirt ($25 value): Sport a stylish gray t-shirt with a “Eat, Drink, Swift” design!
  2. Plus… cold hard cash for a new iPhone 6S and an Apple TV! ($350 value)

In total, the grand prize winner will receive $8,000 in value!

Aww Yeah!

Do you wanna be this guy? Make your first entry into the contest by clicking the button below!


Huge thanks to all of our sponsors and friends who helped make this massive giveaway possible. Don’t thank us – thank them for putting the community first!

Please be sure to check out their pages – these are the tools and conferences we know and love, and they are must haves for serious iOS developers.

Note: To be eligible to win the grand prize, you must be based in either Europe or the US. If you’re in another country, don’t worry – you are eligible for the other 150+ prizes listed below! :]

Bonus Prizes

We want to give as many people as possible a chance to win. So in addition to the grand prize winner, we’ll be giving out a bunch of bonus prizes to over 150 random retweeters!

  • 15 people will win a free raywenderlich.com PDF & Print book of their choice, and “Eat, Drink, Swift” t-shirt. ($133 value)
  • 15 people will win a copy of AppCooker. ($30 value)
  • 15 people will win a copy of Paw (HTTP & REST Client). ($30 value)
  • 15 people will win a copy of Monodraw. ($20 value)
  • 15 people will win a copy of Reflector 2. ($15 value)
  • 15 people will win a copy of Gitbox. ($15 value)
  • 7 people will win a 6-month subscription to Zeplin. ($90 value)
  • 7 people will win a copy of Soulver. ($12 value)
  • 7 people will win a copy of Promottee. ($5 value)
  • 4 people will win a 6-month subscription for Galileo from Bitrise. ($ 174 value)
  • 3 people will win a master bundle from Code+Web that includes TexturePacker, PhysicsEditor, and SpriteIlluminator. ($70 value)
  • 3 people will win a copy of Tower 2. ($69 value)
  • 3 people will win a copy of Paintcode. ($100 value)
  • 3 people will win a copy of Reveal ($89 value)
  • 3 people will win a copy of Hopper. ($89 value)
  • 3 people will win a copy of Particle Designer 2.0 ($80 value)
  • 3 people will win a 1-year subscription to Glyph 2. ($53 value)
  • 3 people will win a copy of Pixelmator. ($30 value)
  • 3 people will win a copy of Dash. ($19 value)
  • 2 people will win a 1-year subscription for Galileo from Bitrise. ($348 value)
  • 1 person will win a copy of Astropad for iPhone. ($5 value)
  • 1 person will win a copy of Astropad for iPad. ($20 value)
  • 1 person will win a copy of Acorn. ($25 value)
  • 1 person will win a copy of Affinity Photo. ($50 value)
  • 1 person will win a copy of Affinity Designer. ($50 value)
  • 1 person will win a 1-year subscription to WordPress.com Premium. ($99 value)
  • 1 person will win a copy of Principle for Mac. ($99 value)
  • 1 person will win a 6-month subscription to Applanga. ($330 value)
  • 1 person will win the ultimate bundle for iOS controls: ShinobiSuites for iOS, which includes ShinobiCharts, ShinobiToolkit, and ShinobiForms. ($995 value)
  • 1 person will win a 1-year subscription for Atlantis from Bitrise. ($1548 value)

That’s a lot of winners – over 150 – so you have a lot of chances to win. This makes for over $17,000 in value of awesome loot to win!

To be eligible for this epic giveaway, all you have to do is send one or more tweets during the iOS 9 Feast with the #ios9feast hashtag.

You can retweet posts with this hashtag (including this one!) or just send general comments. It’s OK to submit as many tweets as you like (as long as you aren’t spamming of course!) We will choose random winners from all of the tweets marked with the #ios9feast hashtag, and they’ll get the epic loot!

Want to make your first entry? Just tweet this post with the #ios9feast hashtag by clicking the button below!


The random drawing will be in 7 weeks, when the iOS 9 Feast is complete. So make your entries early and often! :]

Where To Go From Here?

If WWDC this year was like Christmas for iOS devs, then this has gotta be our Thanksgiving :]

To sum it all up, here’s what you need to know:

  • Want some iOS 9 tutorials right now? Retweet this post – if it reaches 100 tweets, we’ll send out the new tutorials right away!
  • Want tons of new tutorials? Come back here every Monday-Friday for the next month for a new tutorial, book, or video tutorial series on iOS 9, watchOS 2, and Swift 2!
  • Want to meet the team and fellow readers in-person? Sign up for RWDevCon: The Tutorial Conference for some hands-on iOS 9, Swift 2, tvOS, and watchOS 2 tutorials – before tickets sell out!
  • Want to get mad loot? Send one or more tweets during the next month with the #ios9feast hashtag!
  • Want to learn about iOS 9, watchOS 2, and Swift 2? Check out our new official store – the new books and bundles are up!

The Tutorial Team and I hope you enjoy this feast, and that you’re fat and happy by the end!

Stay tuned for a bunch of great iOS 9 and Swift 2 tutorials, and if you have any questions or comments about the iOS 9 Feast, please join the forum discussion below!

The post Introducing the iOS 9 Feast! appeared first on Ray Wenderlich.

UIStackView Tutorial: Introducing Stack Views

$
0
0
Note from Ray: Congratulations, you did it! By helping to spread the word about the iOS 9 Feast, you unlocked the first tutorial of the feast. This is an abbreviated version of a chapter from iOS 9 by Tutorials to give you a sneak peek of what’s inside the book. We hope you enjoy!
UIStackView Tutorial

You’ll wonder how you ever survived before Stack Views!

We’ve all been there. There’s a new requirement and you need to add or remove a view at runtime, and also need to reposition adjacent views.

What approach do you take? Do you add outlets to constraints in your storyboard so that you can activate or deactivate certain ones? Or do you use a third party library? Or depending on the complexity maybe you do everything in code.

Maybe this time around your view hierarchy didn’t have to change at runtime, but you still had to figure out how to squeeze this one new view into your storyboard.

Did you ever end up just clearing all constraints and re-adding them from scratch because it was easier than performing painstaking constraints-surgery?

With the introduction of UIStackView, the above tasks become trivial. Stack views provide a way to lay out a series of views horizontally or vertically. By configuring a few simple properties such as alignment, distribution, and spacing, you can define how the contained views adjust themselves to the available space.

Note: This UIStackView tutorial assumes basic familiarity with Auto Layout. If you’re new to Auto Layout get check out the Auto Layout Tutorial Part 1 tutorial.

Getting started

In this UIStackView tutorial, you’ll work on an app called Vacation Spots. It’s a simple app that shows you a list of places to get away from it all.

But don’t pack your bags just yet, because there are a few issues you’ll fix by using stack views, and in a much simpler way than if you were using Auto Layout alone.

Start by downloading the starter project for this tutorial and run it on the iPhone 6 Simulator. You’ll see a list of places you can go on vacation.

01-table-view-is-now-correct_750x1334 bordered

Go to the info view for London by tapping on the London cell.

At first glance, the view may seem okay, but it has a few issues.

  1. Look at the row of buttons at the bottom of the view. They are currently positioned with a fixed amount of space between themselves, so they don’t adapt to the screen width. To see the problem in full glory, temporarily rotate the simulator to landscape orientation by pressing Command-left.

02-issues-visible-in-landscape-view_1334x750

  1. Tap on the Hide button next to WEATHER. It successfully hides the text, but it doesn’t reposition the section below it, leaving a block of blank space.

03-hide-weather-issue_750x1334

  1. The ordering of the sections can be improved. It would be more logical if the what to see section was positioned right after the why visit section, instead of having the weather section in between them.
  2. The bottom row of buttons is a bit too close to the bottom edge of the view in landscape mode. It would be better if you could decrease the spacing between the different sections – but only in landscape mode.

Now that you have an idea of the improvements you’ll be making, it’s time to dive into the project.

Open Main.storyboard and take a look at the Spot Info View Controller scene. And boom! Have some color with your stack view.

04-colorful-scene-in-storyboard_504x636

These labels and buttons have various background colors set that will be cleared at runtime. In the storyboard, they’re simply visual aids to help show how changing various properties of a stack view will affect the frames of its embedded views.

You don’t need to do this now, but if at any point you’d actually like to see the background colors while running the app, you can temporarily comment out the following lines in viewDidLoad() inside SpotInfoViewController.

// Clear background colors from labels and buttons
for view in backgroundColoredViews {
  view.backgroundColor = UIColor.clearColor()
}

Also, any outlet-connected labels have placeholder text that’s set to the name of the outlet variable to which they are connected. This makes it a bit easier to tell which labels will have their text updated at runtime. For example, the label with text <whyVisitLabel> is connected to:

@IBOutlet weak var whyVisitLabel: UILabel!

Another thing to note is that the scenes in the storyboard are not the default 600 x 600 squares that you get when using size classes.

Size classes are still enabled, but the size of the initial Navigation Controller has been set to iPhone 4-inch under the Simulated Metrics section in the Attributes inspector. This just makes it a bit easier to work with the storyboard; the simulated metrics property has no effect at runtime — the view will resize for different devices.

05-simulated-metrics-iphone-4-inch_639x173

Your first stack view

The first thing you’ll fix by using a stack view is the spacing between the bottom row of buttons. A stack view can distribute its views along its axis in various ways, and one of the ways is with an equal amount of spacing between each view.

Fortunately, embedding existing views into a new stack view is not rocket science. First, select all of the buttons at the bottom of the Spot Info View Controller scene by clicking on one, then Command-click on the other two:

06-select-bottom-row-of-buttons_420x80

If the outline view isn’t already open, go ahead and open it by using the Show Document Outline button at the bottom left of the storyboard canvas:

07-document-outline-button_120x40

Verify that all 3 buttons are selected by checking them in the outline view:

08-verify-button-selection_360x90

In case they aren’t all selected, you can also Command-click on each button in the outline view to select them.

Once selected, click on the new Stack button in the Auto Layout toolbar at the bottom right of the storyboard canvas:

09-stack_button_outlined_148x52

The buttons will become embedded in a new stack view:

10-bottom-row-is-now-in-stack-view_640x100

The buttons are now flush with each other – you’ll that fix shortly.

While the stack view takes care of positioning the buttons, you still need to add Auto Layout constraints to position the stack view itself.

When you embed a view in a stack view, any constraints to other views are removed. For example, prior to embedding the buttons in a stack view, the top of the Submit Rating button had a vertical spacing constraint connecting it to the bottom of the Rating: label:

11-prior-constraint_420x90

Click on the Submit Rating button to see that it no longer has any constraints attached to it:

12-no-more-constraints_400x80

Another way to verify that the constraints are gone is by looking at the Size inspector (⌥⌘5):

13-check-size-inspector_640x80

In order to add constraints to position the stack view itself, you’ll first need to select it. Selecting a stack view in the storyboard can get tricky if its views completely fill the stack view.

One simple way is to select the stack view in the outline view:

14-stack-view-document-outline-selection_660x80

Another trick is to hold Shift and Right-click on any of the views in the stack view, or Control-Shift-click if you’re using a trackpad. You’ll get a context menu that shows the view hierarchy at the location you clicked, and you simply select the stack view by clicking on it in the menu.

For now, select the stack view using the Shift-Right-click method:

15-select-stack-view-in-view-hierarchy-menu_400x280

Now, click the Pin button on the Auto Layout toolbar to add constraints to it:

16-pin-button_142x57

First add a check to Constrain to margins. Then add the following constraints to the edges of your stack view:

Top: 20, Leading: 0, Trailing: 0, Bottom: 0

Double-check the numbers for the top, leading, trailing, and bottom constraints and make sure that the I-beams are selected. Then click on Add 4 Constraints:

17-bottom-stack-view-constraints_264x364

Now the stack view is the correct size, but it has stretched the first button to fill in any extra space:

18-first-button-is-stretched_400x80

The property that determines how a stack view lays out its views along its axis is its distribution property. Currently, it’s set to Fill, which means the contained views will completely fill the stack view along its axis. To accomplish this, the stack view will only expand one of its views to fill that extra space; specifically, it expands the view with the lowest horizontal content hugging priority, or if all of the priorities are equal, it expands the first view.

However, you’re not looking for the buttons to fill the stack view completely – you want them to be equally spaced.

Make sure the stack view is still selected, and go to the Attributes inspector. Change the Distribution from Fill to Equal Spacing:

19-change-distribution-to-equal-spacing_640x148

Now build and run, tap on any cell, and rotate the simulator (⌘→). You’ll see that the bottom buttons now space themselves equally!

20-now-buttons-are-equally-spaced_1334x750

In order to solve this problem without a stack view, you would have had to use spacer views, one between each pair of buttons. You’d have to add equal width constraints to all of the spacer views as well as lots of additional constraints to position the spacer views correctly.

It would have looked something like the following. For visibility in the screenshot, the spacer views have been given a light gray background:

21-alternate-solution-1_346x76

This isn’t too much of an issue if you only have to do this once in the storyboard, but many views are dynamic. It’s not a straightforward task to add a new button or to hide or remove an existing button at runtime because of the adjacent spacer views and constraints.

In order to hide a view within a stack view, all you have to do is set the contained view’s hidden property to true and the stack view handles the rest. This is how you’ll fix the spacing under the WEATHER label when the user hides the text below it. You’ll do that a bit later in the tutorial once you’ve added the weather section labels into a stack view.

Converting the sections

You will convert all of the other sections in SpotInfoViewController to use stack views as well. This will enable you to easily complete the remaining tasks. You’ll convert the rating section next.

Rating section

Right above the stack view that you just created, select the RATING label and the stars label next to it:

22-select-rating-label-and-stars-label_640x74

Then click on the Stack button to embed them in a stack view:

23-after-clicking-stack-button_640x74

Now click on the Pin button. Place a checkmark in Constrain to margins and add the following three constraints:

Top: 20, Leading: 0, Bottom: 20

24-add-second-stack-view-constraints_264x171

Now go to the Attributes inspector and set the spacing to 8:

25-set-spacing-to-8_259x87

It’s possible you may see a Misplaced Views warning and see something like this in which the stars label has stretched beyond the bounds of the view:

26-stars-label-weirdly-stretched_640x85

Sometimes Xcode may temporarily show a warning or position the stack view incorrectly, but the warning will disappear as you make other updates. You can usually safely ignore these.

However, to fix it immediately, you can persuade the stack view to re-layout either by moving its frame by one point and back or temporarily changing one of its layout properties.

To demonstrate this, change the Alignment from Fill to Top and then back to Fill. You’ll now see the stars label positioned correctly:

27-change-alignment-to-top-and-back_640x85

Build and run to verify that everything looks exactly the same as before.

Unembedding a stack view

Before you go too far, it’s good to have some basic “first aid” training. Sometimes you may find yourself with an extra stack view that you no longer need, perhaps because of experimentation, refactoring or just by accident.

Fortunately, there is an easy way to unembed views from a stack view.

First, you’d select the stack view you want to remove. Then hold down the Option key and click on the Stack button. The click Unembed on the context menu that appears:

28-how-to-unembed_186x71

Another way to do this is to select the stack view and then choose Editor \ Unembed from the menu.

Your first vertical stack view

Now, you’ll create your first vertical stack view. Select the WHY VISIT label and the <whyVisitLabel> below it:

29-select-why-visit-labels_640x90

Xcode will correctly infer that this should be a vertical stack view based on the position of the labels. Click the Stack button to embed both of these in a stack view:

30-embed-why-visit-labels_640x90

The lower label previously had a constraint pinning it to the right margin of the view, but that constraint was removed when it was embedded in the stack view. Currently, the stack view has no constraints, so it adopts the intrinsic width of its largest view.

With the stack view selected, click on the Pin button. Checkmark Constrain to margins, and set the Top, Leading and Trailing constraints to 0.

Then, click on the dropdown to the right of the bottom constraint and select WEATHER (current distance = 20):

31-dont-select-nearest-neighbor-constraint_463x417

By default, constraints are shown to the nearest neighbor, which for the bottom constraint is the Hide button at a distance of 15. You actually needed the constraint to be to the WEATHER label below it.

Finally, click Add 4 Constraints. You should now see the following:

32-why-visit-stack-view-stretched_640x90

You now have an expanded stack view with its right edges pinned to the right margin of the view. However, the bottom label is still the same width. You’ll fix this by updating the stack view’s alignment property.

Alignment property

The alignment property determines how a stack view lays out its views perpendicular to its axis. For a vertical stack view, the possible values are Fill, Leading, Center and Trailing.

The possible alignment values for a horizontal stack view differ slightly:

33-horizontal-and-vertical-alignment_594x171

It has .Top instead of .Leading and has .Bottom instead of .Trailing. There are also two more properties that are valid only in the horizontal direction, .FirstBaseline and .LastBaseline.

Select each value to see how it affects the placement of the labels for the vertical stack view:

Fill:

34-alignment-fill_640x64

Leading:

35-alignment-leading_640x64

Center:

36-alignment-center_640x64

Trailing:

37-alignment-trailing_640x64

When you’re done testing each value, set the Alignment to Fill:

38-now-select-alignment-fill_640x64

Then build and run to verify that everything looks good and that there are no regressions.

Specifying Fill means you want all the views to completely fill the stack view perpendicular to its axis. This causes the WHY VISIT label to expand itself to the right edge as well.

But what if you only wanted the bottom label to expand itself to the edge?

For now, it doesn’t matter since both labels will have a clear background at runtime, but it will matter when you’re converting the weather section.

You’ll learn how to accomplish that with the use of an additional stack view.

Convert the “what to see” section

This section is very similar to the previous one, so the instructions here are brief.

  1. First, select the WHAT TO SEE label and the <whatToSeeLabel> below it.
  2. Click on the Stack button.
  3. Click on the Pin button.
  4. Checkmark Constrain to margins, and add the following four constraints:
Top: 20, Leading: 0, Trailing: 0, Bottom: 20
  1. Set the stack view’s Alignment to Fill.

Your storyboard should now look like this:

39-after-what-to-see-section_640x308

Build and run to verify that everything still looks the same.

This leaves you with just the weather section left.

Convert the weather section

The weather section is more complex than the others due to the inclusion of the Hide button.

One approach you could take would be to create a nested stack view by embedding the WEATHER label and the Hide button into a horizontal stack view, and then embedding that horizontal stack view and the <weatherInfoLabel> into a vertical stack view.

It would look something like this:

40-weather-stack-in-stack_640x92

Notice that the WEATHER label has expanded to be equal to the height of the Hide button. This isn’t ideal since this will cause there to be extra space between the baseline of the WEATHER label and the text below it.

Remember that alignment specifies positioning perpendicular to the stack view. So, you could set the alignment to Bottom:

41-weather-stack-in-stack-alignment-bottom_640x92

But you really don’t want the height of the Hide button to dictate the height of the stack view.

The actual approach you’ll take is to have the Hide button not be in the stack view for the weather section, or any other stack view for that matter.

It will remain a subview of the top-level view, and you’ll add a constraint from it to the WEATHER label — which will be in a stack view. That’s right, you’ll add a constraint from a button outside of a stack view to a label within a stack view!

Select the WEATHER label and the <weatherInfoLabel> below it:

42-select-weather-and-info-label_640x92

Click on the Stack button:

43-weather-click-stack-button_640x92

Click on the Pin button, checkmark Constrain to margins and add the following four constraints:

Top: 20, Leading: 0, Trailing: 0, Bottom: 20

Set the stack view’s Alignment to Fill:

44-weather-alignment-fill_640x92

You need a constraint between the Hide button’s left edge and the WEATHER label’s right edge, so having the WEATHER label fill the stack view won’t work.

However, you do want the bottom <weatherInfoLabel> to fill the stack view.

You can accomplish this by embedding just the WEATHER label into a vertical stack view. Remember that the alignment of a vertical stack view can be set to .Leading, and if the stack view is stretched beyond its intrinsic width, its contained views will remain aligned to its leading side.

Select the WEATHER label using the document outline, or by using the Control-Shift-click method:

45-select-just-the-weather-label_640x92

Then click on the Stack button:

46-weather-in-horizontal-stack_640x92

Set Alignment to Leading, and make sure Axis is set to Vertical:

47-vertical-and-leading_640x92

Perfect! You’ve got the outer stack view stretching the inner stack view to fill the width, but the inner stack view allows the label to keep its original width!

Build and run. Why on earth is the Hide button hanging out in the middle of the text?

48-hide-label-incorrect-position_750x573

It’s because when you embedded the WEATHER label in a stack view, any constraints between it and the Hide button were removed.

To add new constraints Control-drag from the Hide button to the WEATHER label:

49-drag-to-weather-label_380x94

Hold down Shift to select multiple options, and select Horizontal Spacing and Baseline. Then click on Add Constraints:

50-add-multiple-constraints_380x224

Build and run. The Hide button should now be positioned correctly, and since the label that is being set to hidden is embedded in a stack view, pressing Hide hides the label, and adjusts the views below it — all without having to manually adjust any constraints.

51-hide-button-works_750x732

Now that all the sections are in unique stack views, you’re set to embed them all into an outer stack view, which will make the final two tasks trivial.

Top-level stack view

Command-click to select all five top-level stack views in the outline view:

52-select-all-stack-views-in-outline_640x260

Then click on the Stack button:

53-stack-all-the-views_640x185

Click the Pin button, checkmark Constrain to margins add constraints of 0 to all edges. Then set Spacing to 20 and Alignment to Fill. Your storyboard scene should now look like this:

54-set-the-spacing-to-20-and-alignment-to-fill_640x300

Build and run:

55-hide-button-lost-again_750x487

Whoops! Looks like the hide button lost its constraints again when the WEATHER stack view was embedded in the outer stack view. No problem, just add constraints to it again in the same way you did before.

Control-drag from the Hide button to the WEATHER label, hold down Shift, select both Horizontal Spacing and Baseline. Then click on Add Constraints:

56-add-constraints-to-button-again_380x223

Build and run. The Hide button is now positioned correctly.

Repositioning views

Now that all of the sections are in a top-level stack view, you’ll modify the position of the what to see section so that it’s positioned above the weather section.

Select the middle stack view from the outline view and drag it between the first and second view.

Note: Keep the pointer slightly to the left of the stack views that you’re dragging it between so that it remains a subview of the outer stack view. The little blue circle should be positioned at the left edge between the two stack views and not at the right edge:

57-drag-and-drop-to-reposition-section_639x130

And now the weather section is third from the top, but since the Hide button isn’t part of the stack view, it won’t be moved, so its frame will now be misplaced.

Click on the Hide button to select it:

58-hide-button-not-moved_640x130

Then click on the Resolve Auto Layout Issues triangle shaped button in the Auto Layout toolbar and under the Selected Views section, click on Update Frames:

59-resolve-auto-layout-issues_356x269

The Hide button will now be back in the correct position:

60-hide-button-back-to-correct-position_640x130

Granted, repositioning the view with Auto Layout and re-adding constraints would not have been the most difficult thing you’ve ever done, but didn’t this feel oh-so-much nicer?

Size class based configuration

Finally, you can turn your attention to the one remaining task on your list. In landscape mode, vertical space is at a premium, so you want to bring the sections of the stack view closer together. To do this, you’ll use size classes to set the spacing of the top-level stack view to 10 instead of 20 when the vertical size class is compact.

Select the top-level stack view and click on the little + button next to Spacing:

61-select-plus-button_260x120

Choose Any Width > Compact Height:

62-anywidth-compact-height_403x108

And set the Spacing to 10 in the new wAny hC field:

63-set-spacing-to-10_260x160

Build and run. The spacing in portrait mode should remain unchanged. Rotate the simulator (⌘←) and note that the spacing between the sections has decreased and the buttons now have ample space from the bottom of the view:

64-spacing-in-iphone-landscape_1334x750

If you didn’t add a top-level stack view, you still could have used size classes to set the vertical spacing to 10 on each of the four constraints that separate the five sections, but isn’t it so much better to set it in just a single place?

You have better things to do with your time, like animation!

Animation

Currently, it’s a bit jarring when hiding and showing the weather details. You’ll add some animation to smooth the transition.

Stack views are fully compatible with the UIView animation engine. This means that animating the appearance/disappearance of an arranged subview, is as simple as toggling its hidden property inside an animation block.

It’s time to write some code! Open SpotInfoViewController.swift and take a look at updateWeatherInfoViews(hideWeatherInfo:animated:).

You’ll see this line at the end of the method:

weatherInfoLabel.hidden = shouldHideWeatherInfo

Replace it with the following:

if animated {
  UIView.animateWithDuration(0.3) {
    self.weatherInfoLabel.hidden = shouldHideWeatherInfo
  }
} else {
  weatherInfoLabel.hidden = shouldHideWeatherInfo
}

Build and run, and tap the Hide or Show button. Doesn’t the animated version feel much nicer?

In addition to animating the hidden property on views contained within the stack view, you can also animate properties on the stack view itself, such as alignment, distribution, spacing and even the axis.

Where to go from here?

You can download the completed project here.

In this UIStackView tutorial, you learned a lot about stack views as well as the various properties that a stack view uses to position its subviews. Stack views are highly configurable, and there may be more than one way achieve the same result.

The best way to build on what you’ve learned is to experiment with various properties yourself. Instead of setting a property and moving on, see how playing with the other properties affects the layout of views within the stack view.

This tutorial was an abbreviated version of Chapter 6, “UIStackView and Auto Layout changes” and Chapter 7, “Intermediate UIStackView” from iOS 9 by Tutorials. If you’d like to learn more about UIStackView and other new features in iOS 9 please check out the book!

In the meantime, if you have any questions or comments about this tutorial or Stack Views in general, please join the forum discussion below!

The post UIStackView Tutorial: Introducing Stack Views appeared first on Ray Wenderlich.

Beginning tvOS Development with TVML Tutorial

$
0
0
Note from Ray: Congratulations, you did it! By helping to spread the word about the iOS 9 Feast, you unlocked the second tutorial of the feast. This is a brand new tutorial – we hope you enjoy!

Learn how to make your first tvOS app!

Last Wednesday Apple announced the new Apple-TV – along with what we’ve all been dreaming of, the ability to write our own apps for it!

I and the rest of the Tutorial Team have been digging into the tvOS SDK to prepare some great tvOS tutorials for you. To get you started, Chris Wagner wrote a post giving a broad overview of tvOS, and I’ve been working on this tutorial, designed to be your first steps in tvOS development.

In this tutorial, you’ll make your first tvOS app using TVML – Apple’s Television Markup Language. Believe it or not, you’ll use JavaScript to manage your app’s logic, and create TVML templates to present your UI.

By the end of the tutorial, you should have a basic grasp of managing tvOS apps using TVML and TVJS. Let’s get started!

Note: This tutorial requires Xcode 7.1 or later – you can download it here. It’s also recommended to have some basic Javascript knowledge, although you can still follow along with the tutorial even if you are new to Javascript as everything is step-by-step.

Choose Your Adventure

Apple has provided developers two ways to develop tvOS apps:

  1. TVML Apps: The first uses an entirely new process utilizing TVML, TVJS and TVMLKit. I’ll explain what these abbreviations mean and how this works in a moment.
  2. Custom Apps: The second uses familiar iOS frameworks and concepts you know and love like Storyboards, UIKit, and Auto Layout.

Both ways are a completely valid way to make apps; it depends what you’re trying to do.

In this tutorial, your goal is to create this simple tvOS that streams RWDevCon conference videos:

rwdevcon

Although you could create this app using either method, it is much easier to do so as a TVML app, so that is what you will be doing in this tutorial. To learn why, let me tell you a little bit more about how this works! :]

What is TVML?

As mentioned, the first method of making apps is via TVML, TVJS, and TVMLKit. If these abbreviations sound foreign to you, don’t fret because they should. Here’s what they are:

  • TVML is a form of XML and stands for “Television Markup Language”.
  • TVJS is set of JavaScript APIs which provide you with the means to display apps created with TVML.
  • TVMLKit is the glue between TVML, JavaScript, and your native tvOS application.

If you’re a native iOS developer the thought of these might make you wince a little bit. But keep an open mind, there is some great power to all of this.

Here’s a very typical use-case for apps on Apple TV. Consider the following: you have content on a server and you want to display that content to users. Your content is organized in a predictable manner and navigating it should be intuitive and familiar. You want your tvOS app to feel at home with other apps. You’re not interested in pushing the envelope on cutting edge user experiences and designs.

TVML architecture

This is exactly the situation we have in this tutorial. We already have a RWDevCon website that hosts the conference videos, so it would be quite easy to host some TVML templates there. We don’t have crazy requirements for the UI, so we can easily make use of some of Apple’s pre-made templates.

TVML templates

In short:

  • Make a TVML App if you primarily provide menus of content, especially if you already have a server set up.
  • Make a Custom App if you’re aiming to provide a fully immersive experience in your app, where your users will be spending more time interacting with your interface than passively watching or listening to content.

Now that you have a high-level understanding of how TVML works and why you’re using it in this tutorial, the best way to understand it further is to try it out yourself. Let’s start coding!

Getting Started

First make sure you have Xcode 7.1 or later installed and open on your machine.

Then go to File\New\Project and select the tvOS\Application\Single View Application template, and click Next:

Selecting the tvOS template in Xcode

For the Product Name enter RWDevCon, for the Language select Swift, make sure both checkboxes are unchecked, and click Next:

002_RWDevCon

Choose a directory to save your project and click Save. Xcode will create a empty project for you with a Storyboard (which you would use if you were creating a tvOS Custom App).

However, you won’t need that because you are are making a TVMP app, which uses TVML files to display the UI rather than a Storyboard. So delete Main.storyboard and ViewController.swift from your project and select Move to Trash.

Next, head into the Info.plist and remove the Main storyboard file base name key. Finally add a new value App Transport Security Settings(case sensitive), and as its child, add Allow Arbitrary Loads, and set that value to YES.

Setting app transport security settings in Info.plist

Note: Adding this key to your Info.plist is necessary because as of iOS 9, your app will prevent linking to non-HTTPS servers to encourage best practices. In this tutorial, you’ll be testing against a local server without HTTPS enabled, so you’ll disable the default behavior.

Loading your TVML

The life cycle of the tvOS app starts with the app delegate. Here, you will set up the TVApplicationController to pass control and the application context to the main JavaScript files.

Open AppDelegate.swift and do the following:

  • Delete all the methods
  • Import TVMLKit
  • Have your app delegate conform to TVApplicationControllerDelegate

At this point your file should look like the following:

import UIKit
import TVMLKit
 
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, TVApplicationControllerDelegate {
 
  var window: UIWindow?
 
}

Next, add the following variables to the class:

var appController: TVApplicationController?
static let TVBaseURL = "http://localhost:9001/"
static let TVBootURL = "\(AppDelegate.TVBaseURL)js/application.js"

TVApplicationController is a class in TVMLKit that handles communicating with your server. TVBaseURL and TVBootURL contains the paths for your server and JavaScript code, which you will be running on your localhost later.

Next add the following method to the class:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
  window = UIWindow(frame: UIScreen.mainScreen().bounds)
 
  // 1
  let appControllerContext = TVApplicationControllerContext()
 
  // 2
  guard let javaScriptURL = NSURL(string: AppDelegate.TVBootURL) else {
    fatalError("unable to create NSURL")
  }
  appControllerContext.javaScriptApplicationURL = javaScriptURL
  appControllerContext.launchOptions["BASEURL"] = AppDelegate.TVBaseURL
 
  // 3
  appController = TVApplicationController(context: appControllerContext, window: window, delegate: self)
  return true
}

This code is relatively straight forward:

  1. Here you create a TVApplicationControllerContext, which you will use to initialize your TVApplicationController. Think of this as a simple object you fill with information such as the URL of your server.
  2. You fill the context with two bits of information: the path to your main Javascript file, and the root directory of your server.
  3. This starts up the TVApplicationController with the context you configured. At this point, Apple’s code takes over – it will pull down your root Javascript file and begin executing it.

And with that, it’s time to take a break from Xcode. Next, you’re going to write JavaScript!

The JavaScript

In the client-server tvOS application, your JavaScript code is typically contained in the server your app connects to. For the purposes of this tutorial, you’ll set up a simple server on your Mac.

Note: From now on, we’ll be working with JavaScript code. Personally, I stay away from using Xcode because of the indentation behaviours associated with working on blank Xcode files. Use an IDE of your choice. If you need a recommendation, I suggest Sublime Text 2 which you can download from here.

Client Code

For the sake of convenience, let’s put the JavaScript code on your Desktop. In your Desktop directory, create a new folder and name it client. Within the client directory, create a new folder and name it js. This folder will serve as the container for your JavaScript files.

With the IDE of your choice, create a new JavaScript file, name it application.js and save it to your js directory. Add the following to application.js

App.onLaunch = function(options) {
  // 1
  var alert = createAlert("Hello World", ""); //leaving 2nd parameter with an empty string
  navigationDocument.presentModal(alert);
}
 
// 2
var createAlert = function(title, description) {
  var alertString = `<?xml version="1.0" encoding="UTF-8" ?>
    <document>
      <alertTemplate>
        <title>${title}</title>
        <description>${description}</description>
      </alertTemplate>
    </document>`
    var parser = new DOMParser();
    var alertDoc = parser.parseFromString(alertString, "application/xml");
    return alertDoc
}

App.onLaunch is the method that handles the entry point of the JavaScript. The TVApplicationController that was initialized in AppDelegate.swift will pass on its TVApplicationControllerContext here. Later, you’ll make use of context’s contents, but for now, you’re just going to create a simple alert to display on screen.

  1. Using createAlert defined below, we get a TVML document for us to present. The navigationDocument is analogous to a UINavigationController in iOS; It serves as the stack that can push, pop, and present TVML documents.
  2. createAlert is a function that returns a TVML document. You can consider it analogous to a UIAlertController in iOS.

At the time of writing, Apple has 18 templates provided for us to use in our TVML apps – you can see the full list and specification in the Apple TV Markup Language Reference.

The alertTemplate used here is one of the 18, and its main purpose is to display important information, such as a message telling the user to perform an action before continuing. Finally, you’re almost ready for your first build and run!

Setting up the Server

Open the Terminal app and enter the following:

cd ~/Desktop/client
python -m SimpleHTTPServer 9001

This starts up a simple Python-based web server in your client directory. Now you’re cleared for takeoff!

Go back to your Xcode project and build and run. You should be greeted with your first tvOS TVML app!

Simulator Screen Shot Sep 12, 2015, 6.40.48 PM

I don’t know about you, but when I first got this working I felt like this guy:

awyeah

Before moving forward, I’d like to spend time to appreciate the work you’ve done so far.

  1. You created a TVApplicationController. This manages the JavaScript code.
  2. You created and attached a TVApplicationControllerContext to the TVApplicationController. The context had launchOptions that was populated with our BASEURL which contained the URL to the server. This context is also where the app finds out which server to connect to.
  3. Control is passed to the JavaScript code. App.onLaunch kicks in and you returned a TVML alert template to present “Hello World” to the screen.

Note that even though you are running on your local web server, you could have put this on a live web server instead – perhaps hooked up to a database. Cool, eh?

Crafting the TVML

As I’ve pointed out before, createAlert is a function that returns a TVML document. There are many more properties we can manipulate in a TVML document, and as an experiment, you’ll add a button to the current alertTemplate. Head back to your JavaScript code, and take a look at your current implementation of createAlert. Add a button to the template:

var alertString = `<?xml version="1.0" encoding="UTF-8" ?>
  <document>
    <alertTemplate>
      <title>${title}</title>
      <description>${description}</description>
      <button>
        <text>OK</text>
      </button>
    </alertTemplate>
  </document>`

Take a moment to appreciate the intricacies:

  1. A TVML document starts off by enclosing its contents with document/
  2. Next, you define the template. For the purposes of our createAlert function, we use the alertTemplate.
  3. Within the template, you decorate it further with a button, a title, and a description, following the Apple TV Markup Language Reference.

Save your file, and build and run. You should see a button associated with your alert view. Voila, TVML made easy!

Simulator Screen Shot Sep 12, 2015, 7.28.59 PM

Note: The amount of elements you can put within a template vary depending on the specific template. For instance, a loadingTemplate does not allow any buttons. Furthermore, you can customize the font, color, and several other attributes of various items, but that is beyond the scope of this tutorial. A full list of each template’s capabilities can be found in the Apple TV Markup Language Reference.

Fleshing out the JavaScript Client

So far, you’ve got something going, and you’re well on our way to our goal. In this section, you’ll spend time abstracting the logic into different classes for better reusability.

Create a new JavaScript file in your client\js folder named Presenter.js. In this file, you’ll declare the class Presenter that will handle the navigation stack. This class will be in charge of popping and pushing documents, and do event handling. Add the following to Presenter.js:

var Presenter = {
  // 1
  makeDocument: function(resource) {
    if (!Presenter.parser) {
      Presenter.parser = new DOMParser();
    }
    var doc = Presenter.parser.parseFromString(resource, "application/xml");
    return doc;
  },
  // 2
  modalDialogPresenter: function(xml) {
    navigationDocument.presentModal(xml);
  },
 
  // 3
  pushDocument: function(xml) {
    navigationDocument.pushDocument(xml);
  },
}

Let’s review this section by section:

  1. Remember that DOMParser is the class that can convert a TVML string into an object-oriented representation; you used this earlier in createAlert. In DOMParser you only want to create a DOMParser once and reuse it multiple times, so you only create it if you haven’t already. You then add the same lines you added earlier to parse a TVML string and return the document.
  2. The modalDialogPresenter method takes a TVML document and presents it modally on screen
  3. The pushDocument method pushes a TVML document onto the navigation stack.

Later in the tutorial, you’ll have the Presenter class manage cell selection as well. For now, let’s refactor the current JavaScript code to take Presenter into account. Replace the current implementation of App.onLaunch with the following:

App.onLaunch = function(options) {
  // 1
  var javascriptFiles = [
    `${options.BASEURL}js/Presenter.js`
  ];
  // 2
  evaluateScripts(javascriptFiles, function(success) {
    if(success) {
      var alert = createAlert("Hello World!", "");
      Presenter.modalDialogPresenter(alert);
    } else {
      // 3 Handle the error CHALLENGE!//inside else statement of evaluateScripts. 
    }
  });
}

The code is relatively straightforward:

  1. Create a new array of JavaScript files. Recall earlier we passed in a BASEURL in the launchOptions property of the TVApplicationControllerContext. Now we will use it to create a path to the Presenter.js file.
  2. evaluateScripts will load the JavaScript files
  3. Here, you should handle the error. More on this in a second.

First, build and run to make sure that your code still works – now refactored to use your new Presenter class:

Simulator Screen Shot Sep 12, 2015, 7.28.59 PM

Then see if you can solve the challenge indicated by the comment in section 3. If for some reason evaluateScripts fails – perhaps because you mistyped the path to the JavaScript file(s) – you want to display an alert message. Hint: you cannot use the Presenter class to do the presenting, since you’ve failed to load it.

You should be able to do this based on what you’ve learned so far. If you get stuck, check the solution below!

Solution Inside: Solution to Challenge SelectShow>

Building the Catalog Template

The catalogTemplate is another one of the 18 templates that are available for developers to use. The purpose of the template is to display information about groups of like products, which is perfect for showcasing your favorite RWDevCon videos! The catalogTemplate has many elements of interest:

tvOS_rwdevcon_diagram

Compound and Simple Elements

The banner element is used to display information along the top of the template app page. It itself is a Compound Element, meaning it is composed of several Simple Elements.

For instance, the obvious use case for the banner is to add a title element, but it can also have a background element. For the purposes of our tutorial, we’ll keep the customizations as little as possible. At the end of the tutorial, there will be a link for further reading regarding other elements.

Let’s try this out. Navigate to your client directory, and create 2 new folders as siblings to the js folder, and name them images and templates respectively. Your client folder should now look like this:

Screen Shot 2015-09-13 at 12.53.23 PM

You’ll need images to populate the cells in our template. I’ve prepared the images for you: download them, unzip the file, and move the images to the images folder you’ve just created.

Now, you’re going to display the images on screen! Create a new JavaScript file, name it RWDevConTemplate.xml.js, and save it in the templates folder.

Add the following to RWDevConTemplate.xml.js:

var Template = function() { return `<?xml version="1.0" encoding="UTF-8" ?>
  <document>
    <catalogTemplate>
      <banner>
        <title>RWDevConHighlights</title>
      </banner>
    </catalogTemplate>
  </document>`
}

For now, we’ll attempt to display the banner of the template. Before we can use this code, since this isn’t currently exposed to the other JavaScript files, we need a way to let the other files know of its existence. A great time to create our last JavaScript file: ResourceLoader.js!

ResourceLoader

Create a new JavaScript file, name it ResourceLoader.js, and save it in the js folder, along with your application.js and Presenter.js files. Add the following to the file:

function ResourceLoader(baseurl) {
  this.BASEURL = baseurl;
}
 
ResourceLoader.prototype.loadResource = function(resource, callback) {
  var self = this;
  evaluateScripts([resource], function(success) {
    if(success) {
      var resource = Template.call(self);
      callback.call(self, resource);
    } else {
      var title = "Resource Loader Error",
          description = `Error loading resource '${resource}'. \n\n Try again later.`,
          alert = createAlert(title, description);
      navigationDocument.presentModal(alert);
    }
  }); 
}

Don’t worry too much about how this works; just know you can use this to load other template files.

Try it out by replacing your “Hello World” alert with our newly created RWDevConTemplate as the main screen. Open application.js and make the following changes to the file:

// 1
var resourceLoader;
 
App.onLaunch = function(options) {
  // 2
  var javascriptFiles = [
    `${options.BASEURL}js/ResourceLoader.js`, 
    `${options.BASEURL}js/Presenter.js`
  ];
 
  evaluateScripts(javascriptFiles, function(success) {
    if(success) {
      // 3
      resourceLoader = new ResourceLoader(options.BASEURL);
      resourceLoader.loadResource(`${options.BASEURL}templates/RWDevConTemplate.xml.js`, function(resource) {
        var doc = Presenter.makeDocument(resource);
        Presenter.pushDocument(doc);
      });
    } else {
      var errorDoc = createAlert("Evaluate Scripts Error", "Error attempting to evaluate external JavaScript files.");
      navigationDocument.presentModal(errorDoc);
    }
  });
}
 
// Leave createAlert alone

You’ve made 3 changes here:

  1. Declared a resourceLoader variable.
  2. Added ResourceLoader.js to the list of files we want to expose.
  3. Used the resourceLoader to load the TVML template, and used the Presenter to present it on screen.

Build and run. You should be greeted with the following screen:

Simulator Screen Shot Sep 13, 2015, 2.37.07 PM

Congratulations, you are now able to load TVML from a file, rather than hard-coding it into your Javascript! Cue the return of my friend:

awyeah

Craft Some More TVML

Believe it or not, but you’re almost done. One of the most beautiful things about TVML tvOS apps is that it’s very easy to add UI elements. What you’re about to add to your RWDevConTemplate may seem a lot, but it’s really a fraction of what you would have to do using UIKit frameworks.

Modify the RWDevConTemplate.xml.js file with the following:

var Template = function() { return `<?xml version="1.0" encoding="UTF-8" ?>
  <document>
    <catalogTemplate> 
      <banner> 
        <title>RWDevConHighlights</title>
      </banner>
      //add stuff here
      //1.
      <list> 
        <section> 
          //2.
	  <listItemLockup> 
	    <title>Inspiration Videos</title>
	    <decorationLabel>13</decorationLabel>
	  </listItemLockup>
        </section>
      </list>
    </catalogTemplate>
  </document>`
}
  1. You’ve defined the list area, which encompasses the rest of the screen’s contents
  2. The listItemLockup represents a section cell. Each cell is defined by a listItemLockup tag. You’ve declared the title to be “Inspiration Videos”, and added a number next to it, to indicate the number of items you’re going to display for this section.

Build and run. You should see the following screen on the simulator:

Simulator Screen Shot Sep 13, 2015, 3.21.33 PM

Not bad for just a little markup!

Completing the Template

Finally, we’re ready to create our cells that will represent each video. Add the following to RWDevConTemplate.xml.js:

//This file outlines the catalogTemplate.
var Template = function() { return `<?xml version="1.0" encoding="UTF-8" ?>
  <document>
    <catalogTemplate> 
      <banner> 
        <title>RWDevConHighlights</title>
      </banner>
      <list> 
        <section> 
	  <listItemLockup> 
	    <title>Inspiration Videos</title>
	    <decorationLabel>13</decorationLabel>
            //1. add from here
	    <relatedContent> 
	      <grid>
	        <section> 
                  //2
		  <lockup videoURL="http://www.rwdevcon.com/videos/Ray-Wenderlich-Teamwork.mp4">
		    <img src="${this.BASEURL}images/ray.png" width="500" height="308" />
		  </lockup>
		  <lockup videoURL="http://www.rwdevcon.com/videos/Ryan-Nystrom-Contributing.mp4">
		    <img src="${this.BASEURL}images/ryan.png" width="500" height="308" />
		  </lockup>									
	          <lockup videoURL="http://www.rwdevcon.com/videos/Matthijs-Hollemans-Math-Isnt-Scary.mp4">
		    <img src="${this.BASEURL}images/matthijs.png" width="500" height="308" />
		  </lockup>									
		  <lockup videoURL="http://www.rwdevcon.com/videos/Vicki-Wenderlich-Identity.mp4">
		    <img src="${this.BASEURL}images/vicki.png" width="500" height="308" />
		  </lockup>									
	          <lockup videoURL="http://www.rwdevcon.com/videos/Alexis-Gallagher-Identity.mp4">
		    <img src="${this.BASEURL}images/alexis.png" width="500" height="308" />
	          </lockup>									
		  <lockup videoURL="http://www.rwdevcon.com/videos/Marin-Todorov-RW-Folklore.mp4">
		    <img src="${this.BASEURL}images/marin.png" width="500" height="308" />
		  </lockup>									
		  <lockup videoURL="http://www.rwdevcon.com/videos/Chris-Wagner-Craftsmanship.mp4">
		    <img src="${this.BASEURL}images/chris.png" width="500" height="308" />
	          </lockup>									
		  <lockup videoURL="http://www.rwdevcon.com/videos/Cesare-Rocchi-Cognition.mp4">
		    <img src="${this.BASEURL}images/cesare.png" width="500" height="308" />
		  </lockup>									
		  <lockup videoURL="http://www.rwdevcon.com/videos/Ellen-Shapiro-Starting-Over.mp4">
		    <img src="${this.BASEURL}images/ellen.png" width="500" height="308" />
		  </lockup>									
		  <lockup videoURL="http://www.rwdevcon.com/videos/Jake-Gundersen-Opportunity.mp4">
		    <img src="${this.BASEURL}images/jake.png" width="500" height="308" />
		  </lockup>									
		  <lockup videoURL="http://www.rwdevcon.com/videos/Kim-Pedersen-Finishing.mp4">
		    <img src="${this.BASEURL}images/kim.png" width="500" height="308" />
		  </lockup>									
	          <lockup videoURL="http://www.rwdevcon.com/videos/Tammy-Coron-Possible.mp4">
		    <img src="${this.BASEURL}images/tammy.png" width="500" height="308" />
		  </lockup>									
		  <lockup videoURL="http://www.rwdevcon.com/videos/Saul-Mora-NSBrief.mp4">
		    <img src="${this.BASEURL}images/saul.png" width="500" height="308" />
		  </lockup>		
		</section>
	      </grid>
	    </relatedContent>
	  </listItemLockup>
        </section>
      </list>
    </catalogTemplate>
  </document>`
}
  1. You’ve added the relatedContent tag. This refers to the following area:
    rwdevcon
  2. Each lockup tag represents a cell in the grid We’ve included a videoURL property for each lockup. This will be necessary to stream the videos from the RWDevCon website.

Build and run. You’ve brought your app to life!

Simulator Screen Shot Sep 13, 2015, 3.46.05 PM

Now that we’ve got many different cells to play around with, let’s bring out the remote controller in the simulator (if you haven’t already). With the Simulator window active, click Hardware\Show Apple TV Remote. You can move around the cells by simply holding the option key and moving your cursor on the remote window.

Playing Video

So far, we’ve got the page populated, and it looks great. Once again, think about the many things you would’ve done to get this layout to work with iOS frameworks. Apple really did a good job abstracting all the details by providing us with these fantastic templates to work with.

Let’s move on to implement the remaining two features for this app: cell selection, and media playback.

Selection Events

You may have noticed already, but pressing the enter key or clicking the Apple TV Remote gives the pressed down animation, but nothing else happens. Now you’re going to implement the necessary code to implement cell selection.

You’re going to have Presenter handle this. Add the following method to the Presenter class:

load: function(event) {
  //1
  var self = this,
  ele = event.target,
  videoURL = ele.getAttribute("videoURL")
  if(videoURL) {
    //2
    var player = new Player();
    var playlist = new Playlist();
    var mediaItem = new MediaItem("video", videoURL);
 
    player.playlist = playlist;
    player.playlist.push(mediaItem);
    player.present();
  }
},
  1. The load method is responsible for cell selection. It is analogous to an @IBAction, where the event argument is similar to the sender argument. Each event has a target. For our purposes, the target refers to each lockup element. Remember, each lockup element represents our cells that display the video thumbnail, and they all have a videoURL property.
  2. Displaying a media player is simple. The class Player of the TVJS framework provides all the media playback functionality. All you need is to add a playlist, and a mediaItem into the playlist. Finally, the player.present() will put the video on screen

Now that you’ve got the implemented the logic to respond to selection events, it’s time to actually hook it up to each cell! For the last time, head back to the application.js file, and add the following line in the App.onLaunch method:

App.onLaunch = function(options) {
  //...
  //inside resourceLoader.loadResource...
  var doc = Presenter.makeDocument(resource);
  doc.addEventListener("select", Presenter.load.bind(Presenter)); //add this line
  Presenter.pushDocument(doc);
  //...
}

The addEventListener method is analogous to hooking a button to an @IBAction. Build and run. Choose a video to play. You should be greeted by the media player:

rwdevcon2

You can download the completed tutorial project here: client and RWDevCon

Where to Go From Here?

You’ve covered a lot of ground today. You’ve learned the basic architecture of a tvOS client-server app. You’ve learned how to manage TVML, use TVJS, and use TVMLKit to connect to a server. For some of you, this is the first time you’ve handled XML and JavaScript files. You have a lot to be proud of!

Before you go, here are some informative links for further exploration:

  • tvOS Documentation: Apple’s official tvOS documentation.
  • RWDevCon: If you’d like to learn more about tvOS, you should come to our upcoming conference; we’ll be having a ton of hands-on tvOS tutorials there and will get you up-to-speed.

Are you excited about the future of tvOS? Please join us in the forum discussion below!

The post Beginning tvOS Development with TVML Tutorial appeared first on Ray Wenderlich.

New Video Tutorial Series: Beginning Swift 2

$
0
0
A Swift 2 update for the iOS 9 Feast!

A Swift 2 update for the iOS 9 Feast!

As part of this year’s iOS 9 Feast, we are releasing a new video tutorial series every Thursday.

This week’s video tutorial series is an update to our popular Beginning Swift tutorial series by Greg Heo – for Swift 2!

In this update, Greg has refactored the materials to use playgrounds. That means you can learn the Swift 2 language without having to worry about platform-specific stuff, and then make the move onto iOS or OS X development when you’re ready.

This series takes you through the building blocks of Swift 2, including variables, optionals, functionals and structs – along with some relevant new Swift 2 features like the new guard and repeat/while syntax.

All 12 parts of the series are available today. You can check them out here:

Since this series is freshly updated, there’s never been a better time to get up-to-speed with Swift 2 than right now.

So what are you waiting for – check out the videos and dive into Swift 2! And be sure to come back next Thursday for another new video tutorial series :]

The post New Video Tutorial Series: Beginning Swift 2 appeared first on Ray Wenderlich.

Learn To Code iOS Apps With Swift Tutorial 5: Making it Beautiful

$
0
0
Learn to Code iOS Apps in this Swift Tutorial - for complete beginners to programming!

Learn to Code iOS Apps in this Swift Tutorial – for complete beginners to programming!

Update note: This tutorial was updated for iOS 9 and Swift 2 by Brian Moakley. Original post by Mike Jaoudi and Ry Bristow.

Congratulations, you made it to the final part of our Learn to Code iOS Apps with Swift tutorial series!

In the first part of the series, you learned the basics of programming with Swift. You learned about variables, if/else statements, loops, optionals, and more.

In the second part of the series, you put your new Swift skills to the test by making a simple number guessing game.

In the third part of the series, you created a simple command-line app to record the names and ages of people.

In the fourth part of the series, you created your first simple iPhone app.

In this fifth and final part of the series, how about you take the game from last time and make it look a little more visually appealing?

This part of the series will teach you how to use images for the background of different objects on the screen to spice it up a bit. Also, you will learn how to implement background music and sound effects. Let’s get started!

Getting Started

You’ll start from the project where you left it off last time, so download a copy if you don’t have it already.

I recommend that you make a copy of the project folder before you begin. This way, you will still have your original version of the app before you change what the interface looks like. This is not only good because you can compare your two finished versions, but it also allows you to have the original, working version if you mess up something while trying to change the interface.

Screen Shot 2014-07-28 at 3.56.23 PM

Then, you’ll want to download the Tap Me Resources, which is basically a collection of the images and sounds that you will need for this project. After you download it, you should open up the folder and select all of the items inside. Drag these items over to the Supporting Files folder in your Document Outline.

Make sure Copy items if needed is selected so that the project will still work on another computer or if you move/delete the resources file from your downloads folder.

Screen Shot 2015-09-09 at 6.09.15 PM

Setting A Button’s Background Image

Rather than just having your button’s background be a solid color, it looks a lot better when you create an image in a photo editing program. To set the background image, you have to do it based on what state the button is in. Make sure the state of the button is set to default in the Attributes Inspector. This is the state of the button when nothing is happening to it.

Screen Shot 2015-09-09 at 6.10.44 PM

Then, find the box that mentions the Background, and set it to button_tap_deselected.png

Screen Shot 2015-09-09 at 6.13.28 PM

In your previous version of the app, you had the background of the button set to be white. Change it back to the default of no color so it doesn’t show behind the image.

Screen Shot 2015-09-09 at 6.15.03 PM

1Screen Shot 2014-07-18 at 12.47.27 PM

Uh oh! The image is hard to read since the button title is still “Tap Me!”. Since the words are a part of the image, you can go ahead and get rid of the title.

Screen Shot 2015-09-09 at 6.16.06 PM

1Screen Shot 2014-07-18 at 12.49.25 PM

Much better! Now, the button is legible and looks a whole lot better than it did in your previous version of the app. Rather than a boring white rectangle with some text in it, you now have a 3-dimensional-looking button with colors and better looking text.

Your next step is to set the background image for the same button when it is in the highlighted state. This is the state of the button when it is being clicked by the user. It should have the Background field set to button_tap_selected.png.

Screen Shot 2015-09-09 at 6.17.32 PM

You may notice your button looks a little bit squished at this point. This is because you have hardcoded width and height constraints that are smaller than the image itself.

Luckily, there is an easy way to fix this. All views have something called an intrinsic content size, which you can think of as an automatic constraint that is set to the size of the element being presented. In the case of an image, it will be the size of the image itself.

So rather than having hardcoded width and height constraints, you can rely on the intrinsic content size of the image to size the image view appropriately.

Let’s try this out. In the document navigator, find the width and height constraints for the button and hit delete to remove them:

DeleteConstraints

Then, update all the frames in your view controller to match their constraints by clicking on the triangle icon in the bottom right and selecting All Views\Update Frames.

Screen Shot 2015-09-09 at 6.20.38 PM

Build and run, and enjoy your big button!

BigButton

Adding Images to the Screen

Sometimes, you may want to add images to the screen that do not act as buttons. In this case, you can use a UIImageView. Find Image View in the Object Library and drag one onto the screen.

You will be using this Image View object to create a border, so you will want to position and resize it so that it stretches from the left side of the screen to the right side of the screen and touches the top part of the screen. Do the same with another Image View object for the bottom border.

Screen Shot 2014-07-18 at 1.35.13 PM

Move your labels a bit to make room. The easiest way to do this is to just update their constraints using the Edit button in the size inspector. Select the Timer Label, and in the Size Inspector in the Constraints section, click the Edit button in the Top Space to: Top Layout Guide constraint.

UpdateConstraint

Now, set the constraints for the top Image View. Click the Pin button. First, make sure to uncheck the Constrain to margins checkbox. Next, click the left, top, and right T-bars . Make sure each has a value of 0. Finally, check the Height constraint. Make sure it has a value of 22. When done, click the button that reads, Add 4 Constraints.

Screen Shot 2015-09-10 at 9.44.58 AM

If you see the orange lines, make sure to update the frames as described earlier in the tutorial.

Do the same to the bottom Image View. Try setting the constraints based on the previous instructions. If you get stuck, check the spoiler.

Solution Inside SelectShow>

Select the top Image View and in the Inspector, set the Image to chekecker_top.png. Set the Mode to Aspect Fill.

Screen Shot 2015-09-10 at 10.10.29 AM

Do the same for the bottom Image View except set the Image to checker_bottom.png.

Run the app again and enjoy your beautiful borders!

Borders

Programmatically Setting the Background Color

You don’t always have to go through Storyboard to change the way your app looks. Let’s change the background color to purple to test this out. Try adding this line inside of viewDidLoad() in ViewController.swift:

view.backgroundColor = UIColor.purpleColor()

What this line of code does is it takes the backgroundColor attribute of the view and sets it to the UIColor object returned by the method purpleColor().

Now run the app and check out what it looks like.

Screen Shot 2014-07-18 at 2.01.48 PM

Although this shows proof of concept, it still doesn’t look that great. However, lucky for you, you can also set the background of the view to an image. Let’s do this in the program again. Replace the line where you set the background color to purple with the following:

view.backgroundColor = UIColor(patternImage: UIImage(named: "bg_tile.png")!)

This line tiles the image to fill the background of the view. Run the app to see what it looks like.

Screen Shot 2014-07-18 at 2.02.48 PM

While you’re at it, go ahead and programmatically set the background of both labels as well. To do this, type in the following two lines of code.

scoreLabel.backgroundColor = UIColor(patternImage: UIImage(named: "field_score.png")!)
timerLabel.backgroundColor = UIColor(patternImage: UIImage(named: "field_time.png")!)

Run the app and see what it looks like now.

Screen Shot 2014-07-18 at 2.03.48 PM

Positioning and Sizing Labels

There are a couple things that could use some improvement here. One thing is that the positioning and sizes of the labels are off. scoreLabel is obviously too high up and its size and shape do not fit its image.

To fix this, select the top label and use the Pin button to add constraints to set its width to 133 and height to 46:

Screen Shot 2015-09-10 at 10.30.59 AM

Then select the bottom label, find its current height constraint in the Project Navigator, and hit delete to remove it:

RemoveScoreCosntraint

Then use the Pin button to add constraints to set its width to 146 and height to 102:

Screen Shot 2015-09-10 at 10.40.00 AM

Finally, clear your selection, click the third button, and choose All Views in View Controller\Update Frames to apply the constraints.

One final tweak. The background that you are using for the labels makes it nearly impossible to read black text on. To solve this, change the text color to a light blue that goes well with the rest of the interface. Use these values for the best results. Make sure you do this for both timeLabel and scoreLabel.

Screen Shot 2015-09-10 at 10.42.50 AM

Also set the alignment of each label to center justified.

Now, run the app to see how much easier it is to read the newly colored text!

Screen Shot 2014-08-10 at 11.29.56 AM

Adding Sound

Music and sound effects are great ways to add character to your app. That’s the last thing this app is missing!

But first, you’ll need some sounds. Download these sounds, unzip the file, and the three sound files into your project.

The three sound files are: background music, a beep for every time the player taps the button, and a beep for every second that passes on the countdown clock, just to make the player sweat a little!

The sound playback will be handled from the view controller code, so open up ViewController.swift. Near the top of your file, you’ll notice this line

import UIKit

You will also need to use an import statement for the AVFoundation framework, which is the Apple framework responsible for playing sound and video. Add the following statement immediately following the previous import statement mentioned.

import AVFoundation

Just as importing UIKit lets you use things like UIButton and UILabel, importing AVFoundation lets you use the very useful AVAudioPlayer class. Next, you’ll need an instance variable for each of the three sounds. Add a line for each instance variable just after the declaration of other instance variables inside the class body.

var buttonBeep : AVAudioPlayer?
var secondBeep : AVAudioPlayer?
var backgroundMusic : AVAudioPlayer?

Since the AVAudioPlayer may not able available, the instance variables are declared as optionals.

Next, you will need to add this helper method above the viewDidLoad method.

  func setupAudioPlayerWithFile(file:NSString, type:NSString) -> AVAudioPlayer?  {
    //1
    let path = NSBundle.mainBundle().pathForResource(file as String, ofType: type as String)
    let url = NSURL.fileURLWithPath(path!)
 
    //2
    var audioPlayer:AVAudioPlayer?
 
    // 3
    do {
      try audioPlayer = AVAudioPlayer(contentsOfURL: url)
    } catch {
      print("Player not available")
    }
 
    return audioPlayer
  }

This method will return an AVAudioPlayer object (declared by the ->), and takes two arguments: a file name and type. Let’s look at what it does by section.

  1. You need to know the full path to the sound file, and NSBundle.mainBundle() will tell you where in the project to look. AVAudioPlayer needs to know the path in the form of a URL, so the full path is converted to URL format.
  2. You’ll notice that audioPlayer is an optional. There may be a condition where an AVAudioPlayer may not be created depending on the device that is trying to instantiate it
  3. This is where you try to create the AVAudioPlayer. Since creating the object may throw an error, you start the block with the do keyword. Next, you try to create the player. If the player is unable to be created, you then catch error. In this case, an error is just being printed to the console but in a real application, you would place your error handling in that block. This error handling code is new in Swift 2.0.
  4. If all goes well, the AVAudioPlayer object will be returned!

Now that you have a handy method that will set up AVAudioPlayer objects, it’s time to use it! Add this code to the viewDidLoad() method, at the top of the method before setupGame():

if let buttonBeep = self.setupAudioPlayerWithFile("ButtonTap", type:"wav") {
  self.buttonBeep = buttonBeep
}
if let secondBeep = self.setupAudioPlayerWithFile("SecondBeep", type:"wav") {
  self.secondBeep = secondBeep
}
if let backgroundMusic = self.setupAudioPlayerWithFile("HallOfTheMountainKing", type:"mp3") {
  self.backgroundMusic = backgroundMusic
}

Here you create each of the players. If the players are able to be created, the objects will be assigned to instance variables.

At this point in viewDidLoad, you’ll have all three sounds ready to be called in your code!

The first sound, buttonBeep, should play when the button is pressed. Update the buttonPressed method to play the sound by adding this line at the end of its method body:

buttonBeep?.play()

By adding a question mark after the variable name, you are trying to call a method on an optional. If there is an object, then the method will be called. Otherwise, the code will be ignored.

There are two other sounds to add. The secondBeep sound should be played every second when the timer ticks down. Add the call to play that sound in subtractTime() method by adding this line right before the if statement.

secondBeep?.play()

You’re almost done!

The final step is to add the background music. To play the music every time a new game is started, add the play code to the setupGame() method. Add these lines to the very bottom of the method body:

backgroundMusic?.volume = 0.3
backgroundMusic?.play()

You can adjust the volume of the background music so the beeps can still be heard. Changing the volume attribute of the backgroundMusic is a good way to do this. It can be set from 0 (off) to 1.0 (full volume), but 0.3 is a good starting point.

Now run the app for a final time and experience the glory of your fully featured app!

FinalGame

Where To Go From Here?

Congratulations! You have just made your first iPhone app, and taken it from having very basic functionality, to being a polished looking and sounding app. Here is a copy of the finished project for you to compare to your finished project.

There are lots of things that you can modify in your app, such as adding or changing some of the graphics, adding different levels, or even modifying the sound effects – the sky is the limit!

From here, you might want to go through the iOS Apprentice series, which goes much more into depth about making iOS apps. It’s also for complete beginners, and you can get the first part for free by signing up for our newsletter.

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

The post Learn To Code iOS Apps With Swift Tutorial 5: Making it Beautiful appeared first on Ray Wenderlich.

Learn to Code iOS Apps with Swift Series Updated for iOS 9 and Swift 2

$
0
0
A free Swift 2 update for the iOS 9 Feast!

A free Swift 2 update for the iOS 9 Feast!

This is just a heads up that Brian Moakely has updated our popular Learn to Code iOS Apps with Swift series for iOS 9 and Swift 2.

This is a series for complete beginners to Swift and iOS development – along with programming in general. You can check out all five parts here:

  1. Learn to Code iOS Apps with Swift Tutorial 1: Welcome to Programming
  2. Learn to Code iOS Apps with Swift Tutorial 2: Your First Project
  3. Learn to Code iOS Apps with Swift Tutorial 3: Arrays, Objects, and Classes
  4. Learn To Code iOS Apps With Swift Tutorial 4: Your First App
  5. Learn To Code iOS Apps With Swift Tutorial 5: Making it Beautiful

Brian and I hope you enjoy this series – this is the first of many updates to come during the iOS 9 Feast!

The post Learn to Code iOS Apps with Swift Series Updated for iOS 9 and Swift 2 appeared first on Ray Wenderlich.

Swift 2 Tutorial: A Quick Start

$
0
0
Get started quickly with this Swift 2 tutorial!

Get started quickly with this Swift 2 tutorial!

Update 9/21/15: Series updated for Xcode 7.0.

Swift is Apple’s brand new programming language. Swift 1 was released last year at WWDC 2014, and just recently Swift 2 was released as part of Xcode 7.

Along with the language, Apple released an excellent Swift reference guide that I highly recommend.

However, the reference guide is long! So if you don’t have a lot of time and just want to learn Swift quickly, this Swift 2 tutorial is for you.

This Swift 2 tutorial will take around 15 minutes and will give you a quick tour of the Swift language, including variables, control flow, classes, best practices, and more.

You’ll even make a handy tip calculator along the way!

For this Swift 2 tutorial, make sure you have the very latest public copy of Xcode (Xcode 7.0 at the time of writing this Swift 2 tutorial). Swift is changing quickly and we are doing our best to update this tutorial as each beta comes out; the code may not work on older versions of Xcode or Pre-Release versions of Xcode.

Note: This tutorial is best if you are already an experienced programmer and want a “quick start” to Swift. If you are brand new to programming and want something a bit slower-paced, you should check out this tutorial series instead.

Introduction to Playgrounds

Start up Xcode 7, and go to File\New\File. Select iOS\Source\Playground, and click Next.

Creating a new playground

Name the file SwiftTutorial.playground, click Create, and save the file somewhere convenient. Delete everything from your file so you start with a clean slate.

A playground is a new type of file that allows you to test out Swift code, and see the results of each line in the sidebar. For example, add the following lines to your playground:

let swiftTeam = 13
let iOSTeam = 54
let otherTeams = 48
let totalTeam = swiftTeam + iOSTeam + otherTeams

As you type these lines, you will see the result of each line on the sidebar. Handy, eh?

Playgrounds are a great way to learn about Swift (like you’re doing in this Swift 2 tutorial), to experiment with new APIs, to prototype code or algorithms, or to visualize your drawing code. In the rest of this Swift 2 tutorial, you will be working in this playground.

Note: At this point, I also recommend you drag your playground file (SwiftTutorial.playground) to your OS X Dock.

This way, you can use this file as a quick scratchpad whenever you want to test out some Swift code. Of course, for this to work you must have your playground somewhere you aren’t likely to move it from.

Variables vs. Constants in Swift

Try adding the following line to the bottom of your playground:

totalTeam += 1

You’ll notice an error when you add this line. This is because totalTeam is a constant, meaning its value can never change. You declare constants with the keyword let.

You want totalTeam to be a variable instead — a value that can change — so you need to declare it with a different keyword: var.

To do this, replace the line that initializes totalTeam with the following:

var totalTeam = swiftTeam + iOSTeam + otherTeams

Now it works! You may think to yourself, “why not just declare everything with var, since it’s less restrictive?”

Well, declaring things with let whenever possible is best practice, because that will allow the compiler to perform optimizations that it wouldn’t be able to do otherwise. So remember: prefer let!

Note: For more best practices like this, check out our official Swift style guide.

Explicit vs. Inferred Typing

So far, you haven’t explicitly set any types for these constants and variables, because the compiler had enough information to infer it automatically.

For example, because you set swiftTeam to 13, the compiler knows 13 is an Int, so it set the type of swiftTeam to an Int for you automatically.

However, you can set the type explicitly if you want. Try this out by replacing the line that sets swiftTeam to the following:

let swiftTeam: Int = 13

You may wonder if you should set types explicitly, or let the compiler infer the types for you. We believe it’s better practice to let the compiler infer types automatically where possible, because then you get one of the main advantages of Swift: concise and easy to read code.

Because of this, switch the line back to inferred typing:

let swiftTeam = 13

Basic Types and Control Flow in Swift

So far, you’ve seen an example of Int, which is the Swift type that is used for integer values, but there’s a bunch more.

Try out using some basic types by pasting the lines in each section below at the bottom of your playground.

Floats and Doubles

let priceInferred = 19.99
let priceExplicit: Double = 19.99

There are two types for decimal point values like this: Float and Double. Double has more precision, and is the default for inferring decimal values. That means priceInferred is a Double too.

Bools

let onSaleInferred = true
let onSaleExplicit: Bool = false

Note that in Swift you use true/false for boolean values (unlike the convention of using YES/NO in Objective-C).

Strings

let nameInferred = "Whoopie Cushion"
let nameExplicit: String = "Whoopie Cushion"

Strings are as you’d expect, except note that you no longer use the @ sign like you do in Objective-C. That might take your muscle memory a bit to get used to! :]

If statements and string interpolation

if onSaleInferred {
  print("\(nameInferred) on sale for \(priceInferred)!")
} else {
  print("\(nameInferred) at regular price: \(priceInferred)!")
}

This is an example of an if statement, just like you’d expect in different languages. The parentheses around the condition are optional, and braces are required even for 1-line statements – w00t!

This also shows an example of a new technique called string interpolation. Whenever you want to substitute something in a string in Swift, simply use this syntax: \(your expression).

At this point, you can see the result of the print in the sidebar, but it may be difficult to read due to the limited space. To see the output, move your mouse over that line and click the eyeball that appears:

001_Eyeball

Here is the playground file up to this point in the tutorial.

Classes and Methods

One of the most common things you’ll be doing in Swift development is creating classes and methods, so let’s jump in right away!

First, delete everything in your playground file so you’re at a clean start.

Next, you’ll create a tip calculator class that will help you figure out what you should tip at a restaurant. You’ll add the code one small piece at a time, with explanations here each step along the way.

// 1
class TipCalculator {
}

To create a class, simply enter the class keyword and the name of your class. You then put two curly braces for the class body.

If you were subclassing another class, you would put a : and then the name of the class you are subclassing. Note that you do not necessarily need to subclass anything (unlike in Objective-C, where you must subclass NSObject or something that derives from NSObject).

Add this code inside the curly braces:

  // 2
  let total: Double
  let taxPct: Double
  let subtotal: Double

You’ll notice some errors after you add these but don’t worry, you will fix them soon.

This is how you create properties on a class – the same way as creating variables or constants. Here you create three constant properties – one for the bill’s total (post-tax), one for the tax percentage that was applied to the bill, and one for the bill’s subtotal (pre-tax).

Note that any properties you declare must be set to an initial value when you declare them, or in your initializer – that’s why you’re currently getting errors. If you don’t want to set your properties to an initial value, you’ll have to declare them as optional (more on that in a future tutorial).

Note: According to the Emily Post Etipedia, tips should be pre-tax. That is why this class calculates the pre-tax amount before applying the tip!

Add this code after the previous block (inside the curly braces):

  // 3
  init(total: Double, taxPct: Double) {
    self.total = total
    self.taxPct = taxPct
    subtotal = total / (taxPct + 1)
  }

This creates an initializer for the class that takes two parameters. Initializers are always named init in Swift – you can have more than one if you want, but they need to take different parameters.

Note that I have given the parameters of this method and the properties of this class the same names. Because of this, I need to distinguish between the two by putting the self prefix before the property names.

Note that since there is no name conflict for the subtotal property, you don’t need to add the self keyword, because the compiler can automatically infer that. Pretty cool, huh?

Note: In case you’re wondering, here’s where the subtotal = total / (tipPct + 1) calculation comes from:
(subtotal * taxPct) + subtotal = total
subtotal * (taxPct + 1) = total
subtotal = total / (taxPct + 1)

Thanks to @chewbone for pointing this out!

Add this code after the previous block (inside the curly braces):

  // 4
  func calcTipWithTipPct(tipPct: Double) -> Double {
    return subtotal * tipPct
  }

To declare a method, you use the func keyword. You then list the parameters (you must be explicit with the types), add the -> symbol, and finally list the return type.

This is a function that determines the amount to tip, which is as simple as multiplying the subtotal by the tip percentage.

Add this code after the previous block (inside the curly braces):

// 5
func printPossibleTips() {
  print("15%: \(calcTipWithTipPct(0.15))")
  print("18%: \(calcTipWithTipPct(0.18))")
  print("20%: \(calcTipWithTipPct(0.20))")
}

This is a new method that prints out three possible tips.

Note that when you call a method on an instance of a class, the first parameter does not need to be named (but the rest do).

Also, notice how string interpolation isn’t limited to printing out variables. You can have all kinds of complicated method calls and operations right inline if you like!

Add this code to the bottom of the playground (after the curly braces):

// 6
let tipCalc = TipCalculator(total: 33.25, taxPct: 0.06)
tipCalc.printPossibleTips()

Finally, you create an instance of the tip calculator and call the method to print the possible tips.

Here’s what your playground file should look like at this point:

// 1
class TipCalculator {
 
  // 2
  let total: Double
  let taxPct: Double
  let subtotal: Double
 
  // 3
  init(total: Double, taxPct: Double) {
    self.total = total
    self.taxPct = taxPct
    subtotal = total / (taxPct + 1)
  }
 
  // 4
  func calcTipWithTipPct(tipPct: Double) -> Double {
    return subtotal * tipPct
  }
 
  // 5
  func printPossibleTips() {
    print("15%: \(calcTipWithTipPct(0.15))")
    print("18%: \(calcTipWithTipPct(0.18))")
    print("20%: \(calcTipWithTipPct(0.20))")
  }
 
}
 
// 6
let tipCalc = TipCalculator(total: 33.25, taxPct: 0.06)
tipCalc.printPossibleTips()

Check your sidebar for the results:

002_Results

Arrays and For Loops

Currently there is some duplication in the above code, because you’re calling the calcTipWithTotal method several times with different tip percentages. You could reduce the duplication here by using an array.

Replace the contents of printPossibleTips() with the following:

let possibleTipsInferred = [0.15, 0.18, 0.20]
let possibleTipsExplicit:[Double] = [0.15, 0.18, 0.20]

This shows an example of creating an array of doubles, with both inferred and explicit typing (you create both just for demonstration purposes). Note that [Double] is just a shortcut for Array<Double>.

Ignore the warnings for now. Then add these lines underneath:

for possibleTip in possibleTipsInferred {
  print("\(possibleTip*100)%: \(calcTipWithTipPct(possibleTip))")
}

Enumerating through items in an array is similar to fast enumeration in Objective-C – note that there are no parentheses needed!

You could also have written this loop like this (but the current syntax is preferred style):

for i in 0..<possibleTipsInferred.count {
  let possibleTip = possibleTipsInferred[i]
  print("\(possibleTip*100)%: \(calcTipWithTipPct(possibleTip))")
}

The ..< operator is a non-inclusive range operator and doesn’t include the upper bound value. There’s also a ... operator which is inclusive.

Arrays have a count property for the number of items in the array. You can also look up a particular item in an array with the arrayName[index] syntax, like you see here.

Note: You will see a warning on the line for possibleTipsExplicit saying the variable isn’t used. It recommends you replace the variable name with _, which is the Swift 2 way to make an unnamed variable, so that it’s very clear that you don’t intend to use this for anything. Feel free to try that for practice, or just ignore the warning.

Viewing Print Output

Notice that with the new loop, you can no longer see the lines that are printed in the sidebar, but instead see the line “(3 times)”:

003_Sidebar

Don’t worry – you just need to bring up the Playground console to see the print results. Click the button in the bottom left of your playground that looks like an up arrow:

004_UpArrow

You should now be able to see the results of all of your print statements!

005_ConsoleOutput

Dictionaries

Let’s make one last change to your tip calculator. Instead of simply printing out the tips, you can return a dictionary with the results instead. This would make it easier to display the results in some sort of user interface for the app.

Delete the printPossibleTips() method and replace it with the following:

// 1
func returnPossibleTips() -> [Int: Double] {
 
  let possibleTipsInferred = [0.15, 0.18, 0.20]
 
  // 2
  var retval = [Int: Double]()
  for possibleTip in possibleTipsInferred {
    let intPct = Int(possibleTip*100)
    // 3
    retval[intPct] = calcTipWithTipPct(possibleTip)
  }
  return retval
 
}

You’ll get an error in your playground, but you’ll fix that in a moment.

First let’s go over the code section by section:

  1. Here you mark the method as returning a dictionary, where the key is an Int (the tip percentage as an int, like 15 or 20), and the value is a Double (the calculated tip). Note that [Int: Double] is just a shortcut for Dictionary<Int, Double>.
  2. This is how you create an empty dictionary. Note that since you are modifying this dictionary, you need to declare it as a variable (with var) rather than a constant (with let). Otherwise you will get a compile error.
  3. This is how you set an item in a dictionary. As you can see, it’s similar to the literal syntax in Objective-C.

Finally, modify the last line in your playground to call this method (this fixes the error):

tipCalc.returnPossibleTips()

Once the playground evaluates, you should see the results as a dictionary in the inspector (click the eyeball for an expanded view and use the down arrows to expand).

Final results

And that’s it – congratulations, you have a fully functional Tip Calculator in Swift!

Where To Go From Here?

Here is the final playground file with all the Swift code from this tutorial.

Want to learn more? Keep reading for the next part of this series, where you’ll learn how to create a user interface for this app, or check out our new Swift books!

I hope you’ve enjoyed this tutorial, and welcome to the world of Swift! :]

The post Swift 2 Tutorial: A Quick Start appeared first on Ray Wenderlich.


Swift 2 Tutorial Part 2: A Simple iOS App

$
0
0
Create a simple iOS app in this Swift 2 tutorial!

Create a simple iOS app in this Swift 2 tutorial!

Update 9/21/15: Series updated for Xcode 7.0.

Welcome back to our Swift 2 tutorial series!

In the first Swift 2 tutorial, you learned the basics of the Swift language, and created your very own tip calculator class.

In this second Swift 2 tutorial, you will learn how to make a simple iOS app. Specifically, you will create a user interface for your tip calculator class that you developed last time.

I will be writing this tutorial in a manner so that it is useful for both complete beginners to iOS, and seasoned iOS developers transitioning to Swift.

For this Swift 2 tutorial, make sure you have the very latest public copy of Xcode (Xcode 7.0 at the time of writing this Swift 2 tutorial). Swift is changing quickly and we are doing our best to update this tutorial as each beta comes out; the code may not work on older versions of Xcode or Pre-Release versions of Xcode.

Note: This tutorial is best if you are already an experienced programmer and want a “quick start” to Swift. If you are brand new to programming and want something a bit slower-paced, you should check out this tutorial series instead.

Getting Started

Start up Xcode and go to File\New\Project. Select iOS\Application\Single View Application, and click Next.

Creating a new Single View Application in Xcode

Enter TipCalculator for the Product Name, set the Language to Swift, and Devices to iPhone. Make sure Use Core Data and the other checkboxes are not checked, and click Next.

Creating a new project in Xcode

Choose a directory to save your project, and click Create.

Let’s see what Xcode has built for you. In the upper left corner of Xcode, select the iPhone 6S Simulator and click Play to test your app.

Choosing the iPhone 6S Simulator

You should then see a blank white screen appear:

008_Blank_Screen

Xcode has created a single blank screen in your app; in this tutorial you’ll fill it up!

Creating Your Model

First things first – before you create the user interface for your app, you should create your app’s model. A model is a class (or set of classes) that represents your class’s data, and operations that your app will perform on that data.

In this tutorial, your app’s model will simply be the TipCalculator class you created in the first Swift 2 tutorial, except you will rename it to TipCalculatorModel.

Let’s add this class to your project. To do this, go to File\New\File, select iOS\Source\Swift File, and click Next. Name the file TipCalculatorModel.swift, and click Create.

Note: You cannot call code from your app that resides in a Playground file. Playground files are just for testing and prototyping code; if you want to use code from a Playground in your app, you have to move it to a Swift file like you’re doing here.

Open TipCalculator.swift, and copy your TipCalculator class (just the class, not the testing lines at the bottom) from the previous tutorial into the file, and make the following changes:

  1. Rename the class to TipCalculatorModel
  2. Change total and taxPct from constants to variables (because the user will be changing these values as he/she runs the app)
  3. Because of this, you need to change subtotal to a computed property. Replace the subtotal property with the following:
var subtotal: Double {
  get {
    return total / (taxPct + 1)
  }
}

A computed property does not actually store a value. Instead, it is computed each time based on other values. Here, you calculate the subtotal each time it is accessed based on the current values of total and taxPct.

Note: You can also provide a setter for a computed property if you’d like, with syntax like this:
var subtotal: Double {
  get {
    return total / (taxPct + 1)
  }
  set(newSubtotal) { 
     //... 
  }
}

Your setter would update its backing properties (i.e. set total and taxPct based on newSubtotal), but that wouldn’t make sense for this app, so you’re not implementing it here.

  1. Delete the line that sets subtotal in init
  2. Delete any comments that are in the file

When you’re done, the file should look like this:

import Foundation
 
class TipCalculatorModel {
 
  var total: Double
  var taxPct: Double
  var subtotal: Double {
    get {
      return total / (taxPct + 1)
    }
  }
 
  init(total: Double, taxPct: Double) {
    self.total = total
    self.taxPct = taxPct
  }
 
  func calcTipWithTipPct(tipPct: Double) -> Double {
    return subtotal * tipPct
  }
 
  func returnPossibleTips() -> [Int: Double] {
 
    let possibleTipsInferred = [0.15, 0.18, 0.20]
 
    var retval = [Int: Double]()
    for possibleTip in possibleTipsInferred {
      let intPct = Int(possibleTip*100)
      retval[intPct] = calcTipWithTipPct(possibleTip)
    }
    return retval
 
  }
 
}

You have your app’s model ready to go – time for the views!

Introduction to Storyboards and Interface Builder

Note: If you are a seasoned iOS developer, this section and the next may be review. To speed things up, you might want to skip forward to the section titled A View Controller Tour. We’ll have a starter project waiting for you there with the user interface for the app pre-created.

You create the user interface for your iOS apps in something called a Storyboard. Xcode comes with a built-in tool called Interface Builder that allows you to edit Storyboards in a nice, visual way.

With Interface Builder, you can lay out all of your buttons, text fields, labels, and other controls in your app (called Views) as simply as dragging and dropping.

Go ahead and click on Main.storyboard in the left side of Xcode to reveal the Storyboard in Interface Builder.

009_InterfaceBuilder

There’s a lot of stuff to cover here, so let’s go over each section of the screen one at a time.

  1. On the far left is your Project Navigator, where your can see the files in your project.
  2. On the left of Interface Builder is your Document Outline, where you can see at a glance the views inside each “screen” of your app (view controllers). Be sure to click the “down” arrows next to each item to fully expand the document outline.

    Right now your app only has one view controller, with only one empty white view. You’ll be adding things into this soon.

  3. There’s an arrow to the left of your view controller. This indicates that this is the initial view controller, or the view controller that is first displayed when the app starts up. You can change this by dragging the arrow to a different view controller, or by clicking the “Is Initial View Controller” property on a different view controller in the Attributes Inspector (more on Inspectors later).
  4. On the bottom of the Interface Builder you’ll see something that says “w Any”, “h Any”. This means that you are editing the layout for your app in a way that should work on any sized user interface. You can do this through the power of something called Auto Layout. By clicking this area, you can switch to editing the layout for devices of specific size classes. You’ll learn about Adaptive UI and Auto Layout in a future tutorial.
  5. On the top of your view controller (if you don’t see these, click the view controller to reveal them) you’ll see three small icons, which represent the view controller itself and two other items: First Responder, and Exit. If you’ve been developing in Xcode for a while, you’ll notice that these have moved (they used to be below the view controller). You won’t be using these in this tutorial, so don’t worry about them for now.
  6. On the bottom right of Interface Builder are four icons related to Auto Layout. Again, you’ll learn more about these in a future tutorial.
  7. On the upper right of Interface Builder are the Inspectors for whatever you have selected in the Document Outline. If you do not see the inspectors, go to View\Utilities\Show Utilities.

    Note there are several tabs of inspectors. You’ll be using these a lot in this tutorial to configure the views you add to this project.

  8. On the bottom right of Interface Builder are the Libraries. This is a list of different types of views or view controllers you can add to your app. Soon you will be dragging items from your library into your view controller to lay out your app.

Creating your Views

Remember that your TipCalculatorModel class has two inputs: a total, and a tax percentage.

It would be nice if the user could type in the total with a numeric keyboard, so a text field is perfect for that. As for the tax percentage, that usually is restricted to a small range of values, so you’ll use a slider for that instead.

In addition to the text field and slider, you will need a label for each, a navigation bar to show the app’s name, a button to click to perform the tip calculation, and a text field to show the results.

Let’s build this user interface one piece at a time.

  1. Navigation bar. Rather than adding a navigation bar directly, select your view controller by selecting it in the document outline:

    010_SelectViewController

    Once it’s selected, go to Editor\Embed In\Navigation Controller. This will set up a Navigation Bar in your view controller. Double click the Navigation Bar (the one inside your view controller), and set the text to Tip Calculator.

    011_SetNavBar

  2. Labels. From the Object Library, drag a Label into your view controller.

    012_DragLabel

    Double click the label and set its text to Bill Total (Post-Tax):. Select the label, and in the Inspector‘s fifth tab (the Size Inspector), set X=33 and Y=81. Repeat this for another label, but set the text to Tax Percentage (0%):, X=20, and Y=120.

    013_AddLabels

  3. Text Field. From the Object Library, drag a Text Field into your view controller. In the Attributes Inspector, set Keyboard Type=Decimal Pad. In the Size Inspector, set X=192, Y=77, and Width=392.

    014_TextField

  4. Slider. From the Object Library, drag a Slider into your view controller. In the Attribute Inspector, set Minimum Value=0, Maximum Value=10, and Current Value=6. In the Size Inspector, set X=190, Y=116, and Width=396.

    015_Slider

  5. Button. From the Object Library, drag a Button into your view controller. Double click the Button, and set the text to Calculate. In the Size Inspector, set X=268 and Y=154.

    016_Button

  6. Text View. From the Object Library, drag a Text View into your View Controller. Double click the Text View, and delete the placeholder text. In the Attributes Inspector, make sure Editable and Selectable are not checked. In the Size Inspector, set X=16, Y=192, Width=568, and Height=400.

    017_TextView

  7. Tap Gesture Recognizer. From the Object Library, drag a Tap Gesture Recognizer onto your main view:

    018_GestureRecognizer

    This will be used to tell when the user taps the view to dismiss the keyboard.

  8. Auto Layout. Interface Builder can often do a great job setting up reasonable Auto Layout constraints for you automatically; and it definitely can in this case. To do this, first select the main View in the Document Outline, then click on the third button in the lower right of the Interface Builder (which looks like a Tie Fighter) and select All Views\Add Missing Constraints.

    019_AddMissingConstraints

Build and run on your iPhone 6S simulator, and you should see a basic user interface working already!

020_BasicUI

A View Controller Tour

Note: If you skipped ahead to this section, here is a zip of the project at this point.

So far you’ve created your app’s models and views – it’s time to move on to the view controller.

Open ViewController.swift. This is the Swift code for your single view controller (“screen”) in your app. It is responsible for managing the communication between your views and your model.

You will see that the class has the following code in it already:

// 1
import UIKit
 
// 2
class ViewController: UIViewController {
 
  // 3
  override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
  }
 
  // 4
  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
  }
 
}

There are some new elements of Swift here that you haven’t learned about yet, so let’s go over them one at a time.

  1. iOS is split up into multiple frameworks, each of which contain different sets of code. Before you can use code from a framework in your app, you have to import it like you see here. UIKit is the framework that contains the base class for view controllers, various controls like buttons and text fields, and much more.
  2. This is the first example you’ve seen of a class that subclasses another class. Here, you are declaring a new class ViewController that subclasses Apple’s UIViewController.
Note: Experienced iOS developers – note that you do not have to put a class prefix on your class names like you did in Objective-C to avoid namespace collisions (i.e. you don’t have to name this RWTViewController). This is because Swift has namespace support, and the classes you create in your project are in their own namespace.

To see what I mean, replace the class declaration with the following:

class UIViewController {
}
 
class ViewController: UIKit.UIViewController {

Here UIKit.UIViewController refers to the UIViewController class in the UIKit namespace. Likewise, TipCalculator.UIViewController would refer to the the UIViewController class in your project.

Remember to remove this test code and revert to the previous declaration of ViewController when you’re done.

  1. This method is called with the root view of this view controller is first accessed. Whenever you override a method in Swift, you need to mark it with the override keyword. This is to help you avoid a situation where you override a method by mistake.
  2. This method is called when the device is running low on memory. It’s a good place to clean up any resources you can spare.

Connecting your View Controller to your Views

Now that you have a good understanding of your view controller class, let’s add some properties for its subviews, and hook them up in interface builder.

To do this, add these following properties to your ViewController class (right before viewDidLoad):

@IBOutlet var totalTextField : UITextField!
@IBOutlet var taxPctSlider : UISlider!
@IBOutlet var taxPctLabel : UILabel!
@IBOutlet var resultsTextView : UITextView!

Here you are declaring four variables just as you learned in the first Swift 2 tutorial – a UITextField, a UISlider, a UILabel, and a UITextView.

There’s only two differences:

  1. You’re prefixing these variables with the @IBOutlet keyword. Interface Builder scans your code looking for any properties in your view controller prefixed with this keyword. It exposes any properties it discovers so you can connect them to views.
  2. You’re marking the variables with an exclamation mark (!). This indicates the variables are optional values, but they are implicitly unwrapped. This is a fancy way of saying you can write code assuming that they are set, and your app will crash if they are not set.

    Implicitly unwrapped optionals are a convenient way to create variables you know for sure will be set up before you use them (like user interface elements created in the Storyboard), so you don’t have to unwrap the optionals every time you want to use them.

Let’s try connecting these properties to the user interface elements.

Open Main.storyboard and select your View Controller in the Document Outline. Open the Connections Inspector (6th tab), and you will see all of the properties you created listed in the Outlets section.

021_ConnectionsInspector

You’ll notice a small circle to the right of resultsTextView. Control-drag from that button down to the text view below the Calculate button, and release to connect your Swift property to this view.

022_ConnectTextView

Now repeat this for the other three properties, connecting each one to the appropriate UI element.

Note: There’s another, even easier way to connect views to properties on your view controller.

While you have Main.storyboard open, you would open your Assistant Editor (View\Assistant Editor\Show Assistant Editor) and make sure the assistant editor is set to display your view controller’s Swift code.

Then, you would control-drag from your view into the Assistant Editor, right before viewDidLoad. In the popup that appears, you would enter a name for a property to create, and click click Connect.

This would create the property for you in your view controller and connect it in Interface Builder, in a single step. Convenient, eh?

Both ways work; you can choose whichever you prefer for our projects.

Connecting Actions to your View Controller

Just like you connected views to properties on your view controller, you want to connect certain actions from your views (such as a button click) to methods on your view controller.

To do this, open ViewController.swift and add these three new methods anywhere in your class:

@IBAction func calculateTapped(sender : AnyObject) {
}
@IBAction func taxPercentageChanged(sender : AnyObject) {
}
@IBAction func viewTapped(sender : AnyObject) {
}

When you declare callbacks for actions from views, they always need to have this same signature – a function with no return value, that takes a single parameter of type AnyObject as a parameter, which represents a class of any type.

Note: AnyObject is the equivalent of id in Objective-C. To learn more about AnyObject, check out our Swift Language FAQ.

To make Interface Builder notice your new methods, you need to mark these methods with the @IBAction keyword (just as you marked properties with the @IBOutlet keyword).

Next, switch back to Main.storyboard and make sure that your view controller is selected in the Document Outline. Make sure the Connections Inspector is open (6th tab) and you will see your new methods listed in a the Received Actions section.

023_NewMethods

Find the circle to the right of calculateTapped:, and drag a line from that circle up to the Calculate button.

In the popup that appears, choose Touch Up Inside:

024_TouchUpInside

This is effectively saying “when the user releases their finger from the screen when over the button, call my method calculateTapped:“.

Now repeat this for the other two methods:

  • Drag from taxPercentageChanged: to your slider, and connect it to the Value Changed action, which is called every time the user moves the slider.
  • Drag from viewTapped: to the Tap Gesture Recognizer in the document outline. There are no actions to choose from for gesture recognizers; your method will simply be called with the recognizer is triggered.
Note: Just like with properties, there’s a shortcut for connecting actions to methods using Interface Builder as well.

You would simply control-drag from something that has an action (like a button) into the Swift code for your view controller in the Assistant Editor. In the popup that appears, you would select Action and give the name of your method.

This would create a method stub in your Swift file and connect the action to your method in one step. Again, both ways work so it’s just a matter of what is convenient to you!

Connecting Your View Controller to your Model

You’re almost done – all you have to do now is hook your view controller to your model.

Open ViewController.swift and add a property for the model to your class and a method to refresh the UI:

let tipCalc = TipCalculatorModel(total: 33.25, taxPct: 0.06)
 
func refreshUI() {
  // 1
  totalTextField.text = String(format: "%0.2f", tipCalc.total)
  // 2
  taxPctSlider.value = Float(tipCalc.taxPct) * 100.0
  // 3
  taxPctLabel.text = "Tax Percentage (\(Int(taxPctSlider.value))%)"
  // 4
  resultsTextView.text = ""
}

Let’s go over refreshUI() one line at a time:

  1. In Swift you must be explicit when converting one type to another. Here you convert tipCalc.total from a Double to a String.
  2. You want the tax percentage to be displayed as an Integer (i.e. 0%-10%) rather than a decimal (like 0.06). So here you multiply the value by 100.

    Note: The cast is necessary because the taxPctSlider.value property is a Float.

  3. Here you use string interpolation to update the label based on the tax percentage.
  4. You clear the results text view until the user taps the calculate button.

Next, add a call to refreshUI() at the bottom of viewDidLoad:

refreshUI()

Also implement taxPercentageChanged and viewTapped as follows:

@IBAction func taxPercentageChanged(sender : AnyObject) {
  tipCalc.taxPct = Double(taxPctSlider.value) / 100.0
  refreshUI()
}
@IBAction func viewTapped(sender : AnyObject) {
  totalTextField.resignFirstResponder()
}

taxPercentageChanged simply reverses the “multiply by 100” behavior, while viewTapped calls resignFirstResponder on the totalTextField when the view is tapped (which has the effect of dismissing the keyboard).

One method left. Implement calculateTapped() as follows:

@IBAction func calculateTapped(sender : AnyObject) {
  // 1
  tipCalc.total = Double((totalTextField.text! as NSString).doubleValue)
  // 2
  let possibleTips = tipCalc.returnPossibleTips()
  var results = ""
  // 3
  for (tipPct, tipValue) in possibleTips {
    // 4
    results += "\(tipPct)%: \(tipValue)\n"
  }
  // 5
  resultsTextView.text = results
}

Let’s go over this line by line:

  1. Here you need to convert a String to a Double. This is a bit of a hack to do this; hopefully there will be an easier way in a future update to Swift.
Note: Here’s how this works, in case you’re wondering.

At the time of writing this tutorial, Swift’s String class does not have access to every method that NSString has (NSString is the string class in the Foundation framework). In particular, Swift’s String class does not have a method to convert to the string to a double; however NSString does.

You can call (xxx as NSString)() on a Swift String to convert it to an NSString. Then, you can call any method that is available on NSString, such as a method to convert to a double.

To learn more about the methods available on NSString, check out the NSString Class Reference.

  1. Here you call the returnPossibleTips method on your tipCalc model, which returns a dictionary of possible tip percentages mapped to tip values.
  2. This is how you enumerate through both keys and values of a dictionary at the same time in Swift. Handy, eh?
  3. Here you use string interpolation to build up the string to put in the results text filed. \n is the newline character.
  4. Finally you set the results text to the string you have been building.

And that’s it! Build and run, and enjoy your hand-made tip calculator!

025_Complete

Note: @BBK on the forums asked how you would sort the results by tip percentage. I thought that was a great question, so included the answer here.

Simply replace the for loop in section 3 with the following:

var keys = Array(possibleTips.keys)
keys.sortInPlace()
for tipPct in keys {
  let tipValue = possibleTips[tipPct]!
  let prettyTipValue = String(format:"%.2f", tipValue)
  results += "\(tipPct)%: \(prettyTipValue)\n"
}

You can get the keys in a dictionary (in this case, the tip percentages) with keys. They are not guaranteed to be in any order, so you have to sort them using sortInPlace() which by default sorts by using the < operator (so numerical order). Once you have the sorted keys, you can loop through them and pull out each item in the dictionary with the dictionary[key] syntax.

As @Solidath points out: “One important addition is that, the possibleTips[] dictionary access returns type Double?, not simply Double. That is because any Dictionary access (subscripting or using updateValue(forKey:) method) returns nil when the key is absent. In our case, we are sure that the key will have a value. For this, we put an exclamation mark “!” at the very end of the tipValue assignment, which is called forced unwrapping.”

Also note you truncate the tip value to two percentage points, using an initializer on String that accepts a format string (like stringWithFormat in Objective-C). %.2f is a format string that formats a float value as a String, with 2 decimal places.

I hope this helps! :]

Where To Go From Here?

Here is the final Xcode project with all the code from this Swift 2 tutorial.

Want to learn more? Keep reading for the next part of this series, where you’ll learn about tuples, protocols, and table views – or check out our new Swift books!

Thanks for reading this tutorial, and if you have any comments or questions please join in the forum discussion below!

The post Swift 2 Tutorial Part 2: A Simple iOS App appeared first on Ray Wenderlich.

Swift 2 Tutorial Part 3: Tuples, Protocols, Delegates, and Table Views

$
0
0
Create a simple iOS app in this Swift 2 tutorial!

Create a simple iOS app in this Swift 2 tutorial!

Update 9/21/15: Series updated for Xcode 7.0.

Welcome back to our Swift 2 tutorial series!

In the first Swift 2 tutorial, you learned the basics of the Swift language, and created your very own tip calculator class.

In the second Swift 2 tutorial, you created a simple user interface for the tip calculator.

In this third Swift 2 tutorial, you will learn about a new data type introduced in Swift: tuples.

You will also learn about protocols and delegates, table views, and how to prototype your user interfaces in Playgrounds.

This tutorial picks up where the second Swift 2 tutorial left off. If you don’t have it already, be sure to download the sample project where you left it off last time.

Getting Started

So far, your Tip Calculator gives a proposed tip for each tip percentage. However, once you select the tip you want to pay, you have to add the tip to the bill total in your head – which kind of defeats the point!

It would be nice if your calcTipWithTipPct() method returned two values: the tip amount, and the bill total with tip applied.

In Objective-C, if you want to make a method return two values, you either have to make an Objective-C object with two properties for the return values, or you have to return a dictionary containing the two values. In Swift, there’s an alternative way: Tuples.

Let’s play around with Tuples a bit so you can get a feel for how they work. Create a new Playground in Xcode (or if you followed my advice in the first Swift 2 tutorial, simply click on the Playground you have saved to your dock). Delete everything from your Playground so you start from a clean slate.

Unnamed Tuples

Let’s start by creating something called an Unnamed Tuple. Enter the following into your playground:

let tipAndTotal = (4.00, 25.19)

Here you group two Doubles (tip and total) into a single Tuple value. This uses inferred syntax since the compiler is able to automatically determine the type based on the initial value that you’re setting it to. Alternatively you could have written the line explicitly like this:

let tipAndTotal:(Double, Double) = (4.00, 25.19)

To access the individual elements of your tuple, you have two options: accessing by index, or decomposing by name. Add the following to the playground to try the first:

tipAndTotal.0
tipAndTotal.1

You should see 4.0 and 25.19 in the sidebar of your playground. Accessing by index works in a pinch, but isn’t as clean as decomposing by name. Add the following to your playground to try the latter:

let (theTipAmt, theTotal) = tipAndTotal
theTipAmt
theTotal

This syntax allows you to make a new constant that refers to each element in the tuple, with a particular name.

Named Tuples

Unnamed Tuples work, but as you saw takes some extra code to access each item by name.

It is often even more convenient to use Named Tuples instead, where you name your tuples at declaration time. Add the following lines to your playground to try:

let tipAndTotalNamed = (tipAmt:4.00, total:25.19)
tipAndTotalNamed.tipAmt
tipAndTotalNamed.total

As you can see this is a lot more convenient, and this is what we’ll be using for the rest of this tutorial.

Finally I’d like to point out that again you are using inferred syntax for the declaration of tipAndTotalNamed. If you wanted to use explicit syntax, it would look like this:

let tipAndTotalNamed:(tipAmt:Double, total:Double) = (4.00, 25.19)

Note that when you use explicit syntax, naming the variables on the right hand side is optional.

Returning Tuples

Now that you understand the basics of Tuples, let’s see how you can use them in your tip calculator to return two values.

Add the following code to your playground:

let total = 21.19
let taxPct = 0.06
let subtotal = total / (taxPct + 1)
func calcTipWithTipPct(tipPct:Double) -> (tipAmt:Double, total:Double) {
  let tipAmt = subtotal * tipPct
  let finalTotal = total + tipAmt
  return (tipAmt, finalTotal)
}
calcTipWithTipPct(0.20)

This is the same calcTipWithTipPct() method you’ve been working with, except instead of returning a Double, it returns (tipAmt:Double, total:Double).

Here is the Playground file up to this point. Now, delete everything from your playground to start at a fresh slate.

A Full Prototype

At this point, you’re ready to take what you’ve learned and integrate it into your TipCalculatorModel class.

But before you start modifying your TipCalculator Xcode project, let’s try out the changes in this playground!

Copy your TipCalculatorModel class from your TipCalculator project into this playground. Then, modify the calcTipWithTipPct the same way you did earlier. Finally, modify returnPossibleTips to return a dictionary of Ints to Tuples instead of Ints to Doubles.

See if you can figure this out on your own; it’s good practice. But if you get stuck, check out the spoiler below!

Solution Inside: TipCalculatorModel - Modified SelectShow>

Here is the Playground file up to this point.

At this point, save your file and start up a new empty Playground. We’ll be returning to this Playground later.

Protocols

The next step is to prototype a table view for your app. But before you do that, you need to understand the concepts of protocols and delegates. Let’s start with protocols.

A protocol is a list of methods that specify a “contract” or “interface”. Add these lines to your Playground to see what I mean:

protocol Speaker {
  func Speak()
}

This protocol declares a single method called Speak.

Any class that conforms to this protocol must implement this method. Try this by adding two classes that conform to your protocol:

class Vicki: Speaker {
  func Speak() {
    print("Hello, I am Vicki!")
  }
}
 
class Ray: Speaker {
  func Speak() {
    print("Yo, I am Ray!")
  }
}

To mark a class as conforming to a protocol, you must put a colon after the class name, and then list the protocol (after the name of the class it inherits from, if any). These classes do not inherit from any other class, so you can just list the name of the protocol directly.

Also notice that if you do not include the Speak function, you will get a compiler error.

Now try this for a class that does inherit from another class:

class Animal {
}
class Dog : Animal, Speaker {
  func Speak() {
    print("Woof!")
  }
}

In this example, Dog inherits from Animal, so when declaring Dog you put a :, then the class it inherits from, then list any protocols. You can only inherit from 1 class in Swift, but you can conform to any number of protocols.

Optional Protocols

You can mark methods in a protocol as being optional. To try this, replace the Speaker protocol with the following:

@objc protocol Speaker {
  func Speak()
  optional func TellJoke()
}

If you get an error, make sure to add this line to the top of your playground:

import Foundation

If you want to have a protocol with optional methods, you must prefix the protocol with the @objc tag (even if your class is not interoperating with objective-C). Then, you prefix any method that can be optional with the optional tag.

Now that you marked the protocol with @objc, you must annotate all the methods that implement that protocol with @objc as well to satisfy the compiler. Modify your playground to look like this:

import Foundation
 
@objc protocol Speaker {
  func Speak()
  optional func TellJoke()
}
 
class Vicki: Speaker {
  @objc func Speak() {
    print("Hello, I am Vicki!")
  }
}
 
class Ray: Speaker {
  @objc func Speak() {
    print("Yo, I am Ray!")
  }
}
 
class Animal {
}
class Dog : Animal, Speaker {
  @objc func Speak() {
    print("Woof!")
  }
}

Note there is currently no compiler error even though none of your classes implement TellJoke(), because the new function is optional.

In this example, Ray or Vicki can tell a joke, but sadly not a Dog. So implement this method only on those two classes:

class Vicki: Speaker {
  @objc func Speak() {
    print("Hello, I am Vicki!")
  }
  @objc func TellJoke() {
    print("Q: What did Sushi A say to Sushi B?")
  }
}
 
class Ray: Speaker {
  @objc func Speak() {
    print("Yo, I am Ray!")
  }
  @objc func TellJoke() {
    print("Q: Whats the object-oriented way to become wealthy?")
  }
  func WriteTutorial() {
    print("I'm on it!")
  }
}

Note that when you’re implementing a protocol, of course your class can have more methods than just the ones in the protocol if you want. Here the Ray class has an extra method.

Oh, and can you guess the answer to these jokes?

Solution Inside SelectShow>

Using Protocols

Now that you’ve created a protocol and a few classes that have implemented them, let’s try using them. Add the following lines to your playground:

var speaker:Speaker
speaker = Ray()
speaker.Speak()
// speaker.WriteTutorial() // error!
(speaker as! Ray).WriteTutorial()
speaker = Vicki()
speaker.Speak()

Note that rather than declaring speaker as Ray, you declare it as speaker. This means you can only call methods on speaker that exist in the Speaker protocol, so calling WriteTutorial would be an error even though speaker is actually of type Ray. You can call WriteTutorial if you cast speaker back to Ray temporarily though, as you see here.

Also note that you can set speaker to Vicki as well, since Vicki also conforms to Speaker.

Now add these lines to experiment with the optional method:

speaker.TellJoke?()
speaker = Dog()
speaker.TellJoke?()

Remember that TellJoke is an optional method, so before you call it you should check if it exists.

These lines use use a technique called optional chaining to do this. If you put a ? mark after the method name, it will check if it exists before calling it. If it does not exist, it will behave as if you’ve called a method that returns nil.

Optional chaining is a useful technique anytime you want to test if an optional value exists before using it, as an alternative to the if let (optional binding) syntax, which you will learn about and use quite frequently in other tutorials and books on this site.

Delegates

A delegate is simply a variable that conforms to a protocol, which a class typically uses to notify of events or perform various sub-tasks. Think of it like a boss giving his minion status updates, or asking him/her to do something!

To see what I mean, add a new DateSimulator class to your playground, that allows two classes that conform to Speaker to go on a date:

class DateSimulator {
 
  let a:Speaker
  let b:Speaker
 
  init(a:Speaker, b:Speaker) {
    self.a = a
    self.b = b
  }
 
  func simulate() {
    println("Off to dinner...")
    a.Speak()
    b.Speak()
    println("Walking back home...")
    a.TellJoke?()
    b.TellJoke?()
  }
}
 
let sim = DateSimulator(a:Vicki(), b:Ray())
sim.simulate()

Imagine you want to be able to notify another class when the date begins or ends. This could be useful if you wanted to make a status indicator in your app appear or disappear when this occurs, for example.

To do this, first create a protocol with the events you want to notify, like so (add this before DateSimulator):

protocol DateSimulatorDelegate {
  func dateSimulatorDidStart(sim:DateSimulator, a:Speaker, b:Speaker)
  func dateSimulatorDidEnd(sim:DateSimulator, a: Speaker, b:Speaker)
}

Then create a class that conforms to this protocol (add this right after the DateSimulatorDelegate):

class LoggingDateSimulator:DateSimulatorDelegate {
  func dateSimulatorDidStart(sim:DateSimulator, a:Speaker, b:Speaker) {
    print("Date started!")
  }
  func dateSimulatorDidEnd(sim:DateSimulator, a: Speaker, b: Speaker)  {
    print("Date ended!")
  }
}

For simplicity, you’ll simply log out these events.

Then, add a new property to DateSimulator that takes a class that conforms to this protocol:

var delegate:DateSimulatorDelegate?

This is an example of a delegate. Again, a delegate is just some class that implements a protocol, that you might want to notify about events, or have it do certain tasks on your behalf.

Note that you are making it optional here, as the DateSimulator should be able to work fine, whether or not the delegate is set.

Right before the line sim.simulate(), set this variable to your LoggingDateSimulator:

sim.delegate = LoggingDateSimulator()

Finally, modify your simulate() function to call the delegate appropriately at the beginning and end of the method.

Try to do this part yourself, as it’s good practice! Note that you should check if delegate is set before using it – I recommend you try out optional chaining to solve this.

Solution Inside: Solution: Complete DateSimulator Class SelectShow>

Here is the playground file up to this point.

Now, save your file and return back to the playground file you saved earlier in this tutorial with your new and improved TipCalculatorModel class in it. It’s time to put this into a table view!

Table Views, Delegates, and Data Sources

Now that you understand the concepts of protocols and delegates, you are ready to use table views in your app.

It turns out table views have a property called delegate – you can set it to a class that conforms to UITableViewDelegate. This is a protocol with a bunch of optional methods to let you know about events like when a row is selected, or when the table view enters edit mode.

Table views also have another property called dataSource – you can set it to a class that conforms to UITableViewDataSource. The difference is instead of notifying this class about events, the table view asks it for data – like how many rows to display, and what should be displayed in each row.

The delegate is optional, but the dataSource is required. So let’s try this out by creating a data source for your tip calculator.

One of the cool things about playgrounds is you can actually prototype and visualize views (like UITableView there as well! This is a great way to make sure it’s working before integrating it into your main project.

Again, make sure you’re in the playground with your new and improved TipCalculatorModel class. Then add this code to the bottom of the file:

// 1
import UIKit
// 2
class TestDataSource : NSObject {
 
  // 3
  let tipCalc = TipCalculatorModel(total: 33.25, taxPct: 0.06)
  var possibleTips = Dictionary<Int, (tipAmt:Double, total:Double)>()
  var sortedKeys:[Int] = []
 
  // 4
  override init() {
    possibleTips = tipCalc.returnPossibleTips()
    sortedKeys = Array(possibleTips.keys).sort()
    super.init()
  }
 
}

Let’s go over this section by section.

  1. In order to use UIKit classes like UITableView, you first need to import the UIKit framework. If you get an error on this line, bring up the File Inspector (View\Utilities\Show File Inspector) and set the Platform to iOS.
  2. One of the requirements of implementing UITableViewDataSource is that your class extends NSObject (either directly or through intermediate classes).
  3. Here you initialize the tip calculator, and make an empty array for the possible tips and sorted keys. Note that you are keeping possibleTips and sortedKeys as variables (not constants) because in the actual app you’ll want these to be able to change over time.
  4. In init, you set up the two variables with initial values. Note that you need to mark this initializer with override because you are overriding the init method from NSObject.

Now that you have a base, let’s make the class conform to UITableViewDataSource. To do this, first add the data source to the end of the class declaration:

class TestDataSource: NSObject, UITableViewDataSource {

Then add this two new method:

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

This is one of the two required methods you must implement to conform to UITableViewDataSource. It asks you how many rows are in each section of the table view. This table view will only have 1 section, so you return the number of values in sortedKeys (i.e. the the number of possible tip percentages).

Next, add the other required method:

// 1
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
  // 2
  let cell = UITableViewCell(style: UITableViewCellStyle.Value2, reuseIdentifier: nil)
 
  // 3
  let tipPct = sortedKeys[indexPath.row]
  // 4
  let tipAmt = possibleTips[tipPct]!.tipAmt
  let total = possibleTips[tipPct]!.total
 
  // 5
  cell.textLabel?.text = "\(tipPct)%:"
  cell.detailTextLabel?.text = String(format:"Tip: $%0.2f, Total: $%0.2f", tipAmt, total)
  return cell
}

Let’s go over this section by section:

  1. This method is called for each row in your table view. You need to return the view that represents this row, which is a subclass of UITableViewCell.
  2. You can create table view cells with a built-in style, or create your own custom subclasses for your own style. Here you are creating a table view cell with a default style – UITableViewCellStyle.Value2 in particular. Note that inferred typing allows you to shorten this to just .Value2 if you want, but I’m keeping the long form here for clarity.
  3. One of the parameters to this method is indexPath, which is a simple collection of the section and row for this table view cell. Since there’s just one section, you use the row to pull out the appropriate tip percentage to display from sortedKeys.
  4. Next you want to make a variable for each element in the Tuple for that tip percentage. Remember from the previous tutorial that when you access an item in a dictionary you get an optional value, since it is possible that there is nothing in the dictionary for that particular key. However, you are sure there is something for that key in this case so use the ! for forced unwrapping.
  5. Finally, the built-in UITableViewCell has two properties for its sublabels: textLable and detailTextLabel. Here you set these and return the cell.

Finally, test your table view by adding the following code to the bottom of your playground:

let testDataSource = TestDataSource()
let tableView = UITableView(frame:CGRect(x: 0, y: 0, width: 320, height: 320), style:.Plain)
tableView.dataSource = testDataSource
tableView.reloadData()

This creates a table view of a hardcoded size, and sets its data source to your new class. It then calls reloadData() to refresh the table view.

Move your mouse over to the sidebar of the playground, to the final line, and click on the eyeball next to UITableView. You should see a neat preview showing your table view with your tip calculator results!

001_Results

Here is the playground file up to this point.

You’re done prototyping the new and improved TipCalculatorModel and your new table view. It’s time to integrate this code back into your main project!

Finishing Touches

Open your TipCalculator project, and copy the new and improved TipCalculatorModel overtop your existing implementation. Be sure not to copy the test lines at the end.

Next, open Main.storyboard, select your Text View (the results area) and delete it. From the Object Library, drag a Table View (not a Table View Controller) into your view controller. Set X=0, Y=192, Width=600, Height=408.

027_Adding_Table_View

Re-set up Auto Layout by clicking the main view to select it, then click the fourth button in the bottom right of Interface Builder (that looks like a Tie Fighter) and click All Views\Clear Constraints and then again with All Views\Add Missing Constraints to View Controller.

Finally, select your table view, and select the sixth Inspector (the Connections Inspector). You’ll see an entry for dataSource – drag the button to the right of that over to your view controller in the Document Outline.

028_Drag_Delegate

Now repeat that same process for the delegate: drag the button to the right of that over to your view controller in the Document Outline.

Now your view controller is set as both the data source and the delegate of the view controller – similar to how you set the data source of the table view to your test class programmatically earlier.

Finally, make sure your Assistant Editor is open and showing ViewController.swift. Control-drag from the table view down below your final outlet.

029_Drag_Outlet

A popup will appear – enter tableView for the name, and click Connect. Now you can refer to your table view in code.

030_Connect_Outlet

Now for the code modifications. Open ViewController.swift, and mark your class as conforming to UITableViewDataSource:

class ViewController: UIKit.UIViewController, UITableViewDataSource {

Then, add two new variables below tipCalc:

var possibleTips = Dictionary<Int, (tipAmt:Double, total:Double)>()
var sortedKeys:[Int] = []

Replace calculateTapped() with the following:

@IBAction func calculateTapped(sender : AnyObject) {
  tipCalc.total = Double((totalTextField.text! as NSString).doubleValue)
  possibleTips = tipCalc.returnPossibleTips()
  sortedKeys = Array(possibleTips.keys).sort()
  tableView.reloadData()
}

This sets up possibleTips and sortedKeys and triggers a reload of the table view.

Delete the line that sets the resultsTextView in refreshUI().

Copy your two table view methods from your playground into your class, and finally delete all comments from the class.

I’ve attached a spoiler below with the completed class, in case you want to check your work.

Solution Inside: Completed ViewController.swift SelectShow>

Build and run, and enjoy the new look of your tip calculator!

031_TipCalculator

Where To Go From Here?

Here is the finished Xcode project from this tutorial series so far.

Congratulations, you have learned a lot in this tutorial! You have learned about Tuples, Protocols and Delegates, and Table Views, and have upgraded the look and functionality of your Tip Calculator class.

Stay tuned for a bunch more Swift 2 tutorials. We’ll be showing you how you can work with table views, Sprite Kit, some iOS 8 APIs, and much more!

In the meantime, if you want to learn more here are some great resources to check out:

Thanks for reading this tutorial, and if you have any comments or questions please join in the forum discussion below!

The post Swift 2 Tutorial Part 3: Tuples, Protocols, Delegates, and Table Views appeared first on Ray Wenderlich.

Swift Quick Start Tutorial Series Updated for Swift 2

$
0
0
A Swift 2 update for the iOS 9 Feast!

A Swift 2 update for the iOS 9 Feast!

In today’s update for the iOS 9 Feast, I have updated our popular “Swift Quick Start” series for Swift 2 and Xcode 7.

This series is meant to be an quick start for experienced Objective-C developers looking to get a taste of Swift. You can check out all three parts here:

In addition, I have updated our Swift Cheat Sheet and Quick Reference to Swift 2.

Again this is just the start of many updates and new tutorials during the iOS 9 Feast – stay tuned for much more!

The post Swift Quick Start Tutorial Series Updated for Swift 2 appeared first on Ray Wenderlich.

iOS Apprentice Fourth Edition Print Version Pictures!

$
0
0

iOS Apprentice Fourth Edition - Updated for iOS 9 & Swift 2!

I recently got my print copy of the iOS Apprentice Fourth Edition by Matthijs Hollemans in the mail.

The iOS Apprentice is our beginner’s guide to iOS development – and the new Fourth Edition is fully up-to-date for iOS 9 and Swift 2.

I thought some of you might be curious about how the print version looks, so I thought I’d post a few pictures for you!

The book turned out great. It’s definitely one of our biggest, weighing in at 788 pages – not to mention our downloadable bonus chapters!

Here’s a look at the book from it’s side, so you can get an idea of its size:

SideView

The book teaches you how to program 4 complete apps from scratch, even if you are a complete beginner to programming. It’s full of step-by-step instructions, illustrations, and screenshots:

InsideView

This marks the fourth version of the iOS Apprentice I have sitting on my bookshelf. It’s almost taking up an entire row now! :]

Want a copy of your own?

  • If you are an existing iOS Apprentice PDF customer: You are eligible for a 50% discount on the new print version; I sent an email last week with a discount code. The discount expires this Wednesday, so if you want a copy grab it while you still can!
  • If you don’t have the iOS Apprentice yet: Order your copy and get ready for some great iOS 9 and Swift 2 learning!

Matthijs and I hope you enjoy the new Fourth Edition!

The post iOS Apprentice Fourth Edition Print Version Pictures! appeared first on Ray Wenderlich.

Storyboards Tutorial in iOS 9: Part 1

$
0
0

Square Image

Update 9/22/15: This tutorial was updated to iOS 9, Xcode 7, and Swift 2 by Caroline Begbie. Original post by Tutorial Team member Matthijs Hollemans.

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

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

Beginning Storyboard

You may not know exactly yet what the app does but you can clearly see which scenes it has and how they are related.

Storyboards have a number of advantages:

  • You can visually lay out all your view controllers in “scenes” and describe the connections between them. With a storyboard you have a better conceptual overview of all the scenes in your app.
  • Storyboards can describe the transitions between the various scenes. These transitions are called “segues” and you create them by connecting your view controllers right in the storyboard. Thanks to segues you need less code to take care of your UI.
  • Storyboards make working with table views a lot easier with prototype cells and static cells features. You can design your table views almost completely in the storyboard editor, cutting down on the amount of code you have to write.
  • Storyboards make it easier to use Auto Layout, a feature that allows you to define mathematical relationships between elements that define their position and sizing. This powerful feature makes it much easier to handle devices of varying screen sizes and dimensions. In this tutorial you will use Auto Layout a little, but it is outside the scope of this tutorial. You can read more about it in our Auto Layout Tutorial or watch the video series.

In this storyboards tutorial you’re going to build a simple app that lets you create a list of players and games, and rate their skill levels. In the process, you’ll learn the most common tasks that you’ll be using in storyboards.

Getting Started

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

XcodeProject

Fill in the template options as follows:

  • Product Name: Ratings
  • Organization Name: fill this in however you like
  • Organization Identifier: the identifier that you use for your apps
  • Language: Swift
  • Devices: iPhone
  • Use Core Data: not checked
  • Include Unit Tests and UI Tests: not checked

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

Main Window

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

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

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

Main Storyboard

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

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

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

Note: You’ll notice that the default scene size is a square. Xcode 7 enables Auto Layout and Size Classes by default for storyboards. Auto Layout and Size Classes allow you to make flexible user interfaces that can easily resize, which is useful for supporting the various sizes of iPhones and iPads. To learn more about size classes, check out our Adaptive Layout video tutorial series.

In this tutorial you will take the optional step of resizing the scenes in your storyboard so that you can more easily visualise what the final screen will look like.

Before you get to exploring, resize the scene to simulate an iPhone 6/6s.

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

Document Outline Icon

In the Attributes Inspector under Simulated Metrics, change Size to iPhone 4.7 inch

Simulated Metrics

The scene in the storyboard will now show as the size of the iPhone 6 or 6s, which are 4.7 inch iPhones.

“Inferred” is the default setting for Simulated Metrics in storyboards. Simulated Metrics are a visual design aid inside the storyboard that shows what your screen will end up looking like. Just remember that they aren’t used during runtime.

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

Drag Controls

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

Document Outline

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

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

The Dock

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

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

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

Simulator Testing

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

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

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

The secret is in the Info.plist file. Click on Info.plist in the Project Navigator and you’ll see this:

Info.plist

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

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

Project Settings

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

Just Add It To My Tab

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

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

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

For convenience, again change the Simulated Metrics to show the scene as an iPhone. As you did before, select Tab Bar Controller in the Document Outline, and on the Attributes Inspector, change Size to iPhone 4.7 inch. This will also change the two embedded view controllers to simulate the iPhone 6 or 6s in the storyboard.

Tab Bar Controller

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

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

Container Relationship

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

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

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

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

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

Initial View Controller

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

Is Initial View Controller

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

App with Tabs

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

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

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

Adding a Table View Controller

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

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

Table View Controller

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

Navigation Controller

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

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

Relationship

Notice that embedding the Table View Controller gave it a navigation bar. Interface Builder automatically put it there because this scene will now be displayed inside the Navigation Controller’s frame. It’s not a real UINavigationBar object, but a simulated one. Simulated Metrics will infer the context around the scene and show a navigation bar when it’s inside a Navigation Controller, a tab bar when it’s inside a Tab Bar Controller, and so on.

The new controllers are currently square shaped. When you embed them inside the Tab Bar Controller as you will in a moment, they will change their simulated size to match the parent scenes.

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

Embed VC

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

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

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

Drag tab items

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

SimulatorFirstTabWithTableView

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

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

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

Tab Bar Players

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

A well-designed app should also put some pictures on these tabs. The resources for this tutorial contains a subfolder named Images. Drag that folder into the Assets.xcassets subfolder in the project.

Back in Main.storyboard, in the Attributes inspector for the Players Tab Bar Item, choose the Players.png image.

Players Image

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

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

Navigation Item

Notice that the Scene title in the Document Outline now changes to Players

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

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

App With Tab Bar Images

Prototype Cells

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

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

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

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

Set the Accessory attribute to Disclosure Indicator and in the Identifier field type PlayerCell. All prototype cells should have a reuse identifier so that you can refer to them in code.

Cell Setup

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

Add a new file to the project. Choose the Cocoa Touch Class template under iOS/Source. Name the class PlayersViewController and make it a subclass of UITableViewController. Uncheck Also create XIB file. Choose the Swift language and hit Next followed by Create.

Players View Controller

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

Players VC Class

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

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

Replace the code in Player.swift with:

import UIKit
 
struct Player {
  var name: String?
  var game: String?
  var rating: Int
 
  init(name: String?, game: String?, rating: Int) {
    self.name = name
    self.game = game
    self.rating = rating
  }
}

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

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

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

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

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

var players:[Player] = playersData

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

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

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

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

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

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

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

App With Players

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

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

Designing Your Own Prototype Cells

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

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

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

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

Select both the Name and Game labels in the Document Outline using Command+click, and choose Editor\Embed In\Stack View.

Note: Stack views are new in iOS 9 and are brilliant for easily laying out collections of views. You can find out more about stack views in our new book iOS 9 by Tutorials.

Drag an Image View into the cell and place it on the right, next to the disclosure indicator. In the Size Inspector, make it 81 points wide and 35 points high. Set its Mode to Center (under View in the Attributes inspector) so that whatever image you put into this view is not stretched.

Command + click the Stack View and Image View in the Document Outline to select both of them. Choose Editor\Embed in\Stack View. Xcode will create a new horizontal stack view containing these two controls.

Stack View

Select this new horizontal stack view, and in the Attributes Inspector, change the Alignment to Centre and the Distribution to Equal Spacing.

Now for some simple auto layout for this control. At the bottom right of the storyboard, click the Pin icon:

Pin Icon

Change the top constraints to Top: 0, Right: 20, Bottom: 0 and Left: 20. Make sure that the four red pointers to the values are highlighted as in the picture. Click Add 4 Constraints at the bottom of the popover window.

Constraints

If your stack view has orange constraints, it is misplaced. To fix this, select the horizontal stack view and choose Editor\Resolve Auto Layout Issues\Update Frames (in the Selected Views section of the menu). The stack view should position itself correctly and the orange constraint errors go away.

To position the image view within the stack view, select the image view in the Document Outline and choose Editor\Resolve Auto Layout Issues\Add Missing Constraints (in the Selected Views section of the menu).

The final design for the prototype cell looks something like this:

Final Cell

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

Tags are used here for simplicity. Later in this tutorial you’ll create a custom class that inherits from UITableViewCell and contains properties corresponding to the labels on your cell view.

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

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

func imageForRating(rating:Int) -> UIImage? {
  let imageName = "\(rating)Stars"
  return UIImage(named: imageName)
}

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

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

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

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

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

Wrong Cell Height

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

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

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

RightHeight

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

Proper Row Height

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

Using a Subclass for the Cell

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

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

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

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

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

Add this property just below the IBOutlets:

var player: Player! {
  didSet {
    gameLabel.text = player.game
    nameLabel.text = player.name
    ratingImageView.image = imageForRating(player.rating)
  }
}

Whenever the player property is set, it will update the IBOutlets with the correct information.

Move the method imageForRating(_:) from PlayersViewController to the PlayerCell class to keep the cell details all in the same class.

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

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

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

Name Label

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

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

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

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

That’s more like it. You now cast the object that you receive from dequeueReusableCellWithIdentifier to a PlayerCell, and then you can simply pass the correct player to the cell. Setting the player variable in PlayerCell will automatically propagate the values into the labels and image view, and the cell will use the IBOutlets that you wired up in the storyboard. Isn’t it great how using prototype cells makes table views a whole lot less messy?

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

Where To Go From Here?

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

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

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

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

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

Viewing all 4370 articles
Browse latest View live


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