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

Git Tutorial – Git Fu With The Command Line

$
0
0

There are many different GUIs for Git these days: GitHub for Mac, Tower, SourceTree, Xcode and more. While these options are fine for most situations, many experienced developers would tell you that the Command Line Interface (CLI) is the best option and should be the primary tool you use. git-logo

While “best” is an imprecise, subjective term, the Git CLI is certainly the most powerful and versatile way to use Git, as the GUI options usually just run the CLI commands under the hood. Anything a Git GUI can do, the command line can do — probably better.

This Git tutorial introduces you to a few ways to use the command line more effectively with Git.

In particular, you’ll learn how to make the command line a friendlier place by adding autocompletion, and how to make the command line prompt provide you with help and Git guidance.

Note: It’s often been the case that graphical Git clients have simply executed Git commands under-the-hood. However, an open source, portable, pure C implementation of the Git core methods is now available in libgit2, and is being used by industry heavyweights, such as Microsoft, to power their Git tools

Getting Started

If you’re new to Git or just need to brush up, here are two links to help you get up to speed.

Also, before continuing, make sure that you’ve installed Xcode’s Command Line Tools (CLT). To find out what you have, open a terminal window and at the prompt enter

xcode-select -p

If you see no error message, you’re OK.

If the tools are not there, type the line below into Terminal, and then follow the instructions in the resulting dialog.

xcode-select --install

Why You Care About Fancy Git Commands

…but might not realize it yet.

To start, take a quick look at some of the most common issues people have with Git repositories, or repos for short. Almost all Git questions on Stack Overflow involve the CLI.

From the volume of CLI related questions, it’s safe to draw the conclusion the majority of developers predominantly use the CLI to handle their Git repositories.

One reason for it’s popularity is because it provides the extra power necessary when your needs have outgrown even the most complete GUI, and your repo requires some low level, fine-grained TLC.

more-power

Anything a GUI can do, the CLI can do (and often better).

Even if your Git GUI of choice is capable of handling your exact situation, you’re likely to have a session of tinkering with menu options and checkboxes to figure out how to address your specific issues. All the while, the GUI will simply be executing CLI commands in the background, so you might as well do it for yourself. If for nothing more than to gain a solid understanding of what’s happening under-the-hood.

One more reason to love Git’s CLI is that it’s been around longer, and has a much larger community, than any Git GUI. Subsequently, there are more people out there who can answer your questions about the Git CLI.

Another shortcoming of Git GUIs shows up when you start using a standard branching model, because these tools often don’t have built-in support for the popular models. However, Atlassian’s SourceTree supports the popular Git-flow model, and it happens to have a pretty useful overview of the different classes of branching models, also known as work-flows.

But what if I want a cool graph of my commits? Can the non-graphical CLI provide that?”

Yes, yes it can. Follow along and you’ll learn how to make it happen.

Cool History Graphs

It turns out the Git CLI can produce useful, almost pretty, commit-history graphs for you. It even lets you filter for the commits you actually want to see.

First, you need a repo with something worth looking at, and for this tutorial you’ll find it inside the git-extras repository.

You’re just going to use this repo as an example to illustrate some CLI usage, but the commands here are quite useful and you may want to install them to enhance Git’s CLI further.

Look at that, one more reason to love the Git CLI — the ability to extend Git via the command line is yet another reason why the Git CLI holds an edge over any Git GUI.

Now use one of Git’s most basic commands, git clone to make a copy of this repo on your local machine. First open a terminal window and navigate to the folder where you want to store the repo, and then type the commands below:

git clone git@github.com:visionmedia/git-extras.git
cd git-extras

If you get any errors from the clone command above, you can replace that line by:

git clone https://github.com/visionmedia/git-extras.git

Note: If you do see an error here, it’s likely because you’ve not setup your SSH keys with GitHub. You can find out more about how to do that and why it’s important here

Make sure you’re in the git-extras directory by entering pwd on the command line. Now, take a look at a graph of commits by entering the following command:

git log --graph --pretty=oneline --abbrev-commit

And you should see something like this.

*  3b3efd7 Merge pull request #219 from jhoffmann/patch-1
|\ 
| * 3c6a084 Update Readme.md
* |  47bb6e0 Merge pull request #222 from jsipprell/pull/filenames-containing-spaces
|\ \ 
| * | 1479b96 git effort: handle filenames containing whitespace cleanly
| |/ 
* |  039bb5c Merge pull request #223 from mwoc/master
|\ \ 
| * | 0687de7 Use two-space indents for log entry output, so it again is debian changelog compatible (as before commit 1235e4a5)
| |/ 
* |  a87403b Merge pull request #229 from yggdr/master
|\ \ 
| * | e4290df invoke bash via /usr/bin/env for portability
* | |  45b3515 Merge pull request #231 from petersohn/master
|\ \ \ 
| |/ / 
|/| |  
| * | 698d027 Make git-obliterate work if there are whitespaces in filename
|/ / 
* | d437418 Release 1.9.1
* |  ef00c0c Merge pull request #225 from pmalek/master
|\ \ 
| |/ 
             -- And it continues!
:

Hit the spacebar a few times; you’ll see pages and pages of commits and a graphical representation of the branches and merges over time. When you’ve soaked in the graph, hit q to quit.

That’s probably a lot more commits than you want to dig through. But you can limit the scope in various ways — for instance, by date.

Enter the command below:

git log --graph --pretty=short --abbrev-commit --since=April

This shows just the commits since April, and it also grabs some useful info about each commit by asking for a short format instead of oneline.

Now you see a much shorter graph like this one.

* commit 3b3efd7
| Merge: 47bb6e0 3c6a084
| Author: hemanth.hm 
| 
|   Merge pull request #219 from jhoffmann/patch-1
|  
*  commit 47bb6e0
|\ Merge: 039bb5c 1479b96
| | Author: hemanth.hm 
| | 
| |   Merge pull request #222 from jsipprell/pull/filenames-containing-spaces
| |  
| * commit 1479b96
|  Author: Jesse Sipprell 
|  
|    git effort: handle filenames containing whitespace cleanly
|  
*  commit 039bb5c
|\ Merge: a87403b 0687de7
| | Author: hemanth.hm 
| | 
| |   Merge pull request #223 from mwoc/master
| |  
| * commit 0687de7
|  Author: Maarten Winter 
|  
|    Use two-space indents for log entry output, so it again is debian changelog compatible (as before commit 1235e4a5)
|  
*  commit a87403b
|\ Merge: 45b3515 e4290df
| | Author: hemanth.hm 
| | 
| |   Merge pull request #229 from yggdr/master
| |  
| * commit e4290df
| | Author: Konstantin Schukraft 
| | 
| |   invoke bash via /usr/bin/env for portability
| |   
* |  commit 45b3515
|\ \ Merge: d437418 698d027
| |/ Author: hemanth.hm 
|/|  
| |    Merge pull request #231 from petersohn/master
| |  
| * commit 698d027
|/ Author: eszabpt 
|  
|    Make git-obliterate work if there are whitespaces in filename
| 
* commit d437418
| Author: TJ Holowaychuk 
| 
|   Release 1.9.1
| 
* commit ef00c0c
| Merge: e91da7c 4145f22
| Author: TJ Holowaychuk 
| 
|   Merge pull request #225 from pmalek/master
| 
* commit 4145f22
| Author: Patryk Małek 
| 
|   Fixed git-changelog errors when multiple files match change|history
| 
* commit de6463f
 Author: Patryk Małek 
 
   Fixed git-changelog errors on first usage
(END)

Don’t forget to hit q to exit.

Next, filter your graph to show only commits by a specific user. Graph all the commits by Patryk Małek since April, and list a bunch more info on each commit by entering the following command:

git log --graph --pretty=fuller --abbrev-commit --since=April --author="Patryk Małek"

Now you have a shorter, much more useful list of commits with quite a lot of detail.

* commit 4145f22
| Author:   Patryk Małek 
| AuthorDate: Mon Jun 16 16:32:47 2014 +0200
| Commit:   Patryk Małek 
| CommitDate: Mon Jun 16 16:32:47 2014 +0200
| 
|   Fixed git-changelog errors when multiple files match change|history
| 
* commit de6463f
 Author:   Patryk Małek 
 AuthorDate: Mon Jun 16 16:27:57 2014 +0200
 Commit:   Patryk Małek 
 CommitDate: Mon Jun 16 16:27:57 2014 +0200
 
   Fixed git-changelog errors on first usage

Maybe you’d like a list all of the accepted pull-requests since June? Just enter the following:

git log --grep="pull request" --since=21june

Since GitHub automatically adds a useful message each time an owner of a repo accepts a pull request, you see something like this:

commit 3b3efd74831639a7eeac37add0a1332a0ca9e847
Merge: 47bb6e0 3c6a084
Author: hemanth.hm 
Date:  Sun Jul 6 12:37:41 2014 +0530
 
  Merge pull request #219 from jhoffmann/patch-1
 
  Update Readme.md
 
commit 47bb6e0f7423304caf214998e44e717400b30bad
Merge: 039bb5c 1479b96
Author: hemanth.hm 
Date:  Sun Jul 6 12:36:08 2014 +0530
 
  Merge pull request #222 from jsipprell/pull/filenames-containing-spaces
 
  git-effort handles filenames with whitespace.
 
commit 039bb5c318f329d62cff86d3a11b4c516586b963
Merge: a87403b 0687de7
Author: hemanth.hm 
Date:  Sun Jul 6 12:34:21 2014 +0530g
 
  Merge pull request #223 from mwoc/master
 
  Restoring debian changelog compatibility.
 
commit a87403b57f3c72034be2abc066d40425e8a9a7ba
Merge: 45b3515 e4290df
Author: hemanth.hm 
Date:  Sun Jul 6 11:55:00 2014 +0530
 
  Merge pull request #229 from yggdr/master
 
  /usr/bin/env for portability.
 
commit 45b3515ff811e603c2c9278553af26c7c996c117
Merge: d437418 698d027
Author: hemanth.hm 
Date:  Sun Jul 6 11:52:58 2014 +0530
 
  Merge pull request #231 from petersohn/master
 
  git-obliterate now supports whitespaces in filename.
 
commit ef00c0c2c6d146081347dd75d27ee6a9facb4ee9
Merge: e91da7c 4145f22
Author: TJ Holowaychuk 
Date:  Sat Jun 21 21:53:16 2014 -0700
 
  Merge pull request #225 from pmalek/master
 
  Fixed git-changelog errors on first usage
(END)

Note: Pull requests are not really a feature of Git, but are part of a work-flow made available by Git repository hosting services such as GitHub and Bitbucket.

Even the Best Tools Aren’t Without Fault

OK, the Git CLI is cool and powerful, but you might feel that:

  • There’s a bunch of typing, especially if you’re using a formal branching strategy.
  • It’s easy to misspell parameters, options, names of branches, remotes, files and commit hashes.
  • Here’s the clincher: It’s easy to complete hours of work, only to find that you’ve been working on and committing to — and possibly even force-pushing — #gasp — the WRONG BRANCH.
  • All in all, the CLI involves a lot more stuff to remember than just sticking with a GUI.

Stay with me; you’ll see the true value of the CLI in a few moments.

Those are fair points. Any type of GUI that’s outstandingly effective uses menus to organize the functionality servicing the myriad of use cases. Why do GUIs use menus?

Run an Internet search for ‘recognition vs. recall‘ and you’ll see a ton of results that talk about how much faster and more efficiently your brain recognizes something than it recalls something.

For example, pretend you’re trying to remember the name of that one actor who played a supporting role in your favorite movie of 2014, without peeking at your phone. Unfortunately, you just can’t seem to remember.

You could probably pick his name out of a cast list, because your marvelous brain will recognize the name even though it couldn’t recall it.

That’s precisely why GUIs use menus. Users can easily scan menus and recognize the item they want. You can actually use the same idea on the command line.

If you’ve used the command line to navigate around your file system, you probably use a combination of recall and recognition to navigate.

Imagine that you’re typing cd ~/D[tab][tab] (recalling the first letter), and you’ll see a list of items in your home folder that start with the letter D. Then recognizing the name from that list, you type a few more characters, and then [tab] to finish out the directory name.

Everything seems a little easier now, doesn’t it?

Meet your new friend autocompletion, who will help you by offering your brain something to recognize, rather than recall. It’s the next really cool Git CLI tip you’re going to learn all about.

Autocompletion – It’s Not Just For Navigation Anymore

If you’re an experienced terminal user, you probably have a totally awesome shell that you absolutely love, and it’s probably bash since that’s the default shell on OS X. If you use another totally awesome shell, this next section may or may not be relevant, since it’s based on scripts that aim at bash.

Now for the fun stuff! You’re going to install Git bash-completion, aka Git-flow-completion. This provides autocompletion of Git commands, parameters, options, branch names, filenames, remotes — and did I mention branch names??

This is amazingly helpful if you use feature branches. For example, I regularly use branch names that are more than 20 or 30 characters long, because the teams I work with use user-stories for the feature-branch names.

With autocompletion, you’ll prevent brain strain by using command line to help you recognize even the longest, most difficult-to-remember names.

Next up – Homebrew, the power tool that makes installing autocompletion (and more) a breeze.

Homebrew Installation

There are several ways to install Git bash-completion. Since you’re probably a Mac user, this tutorial will use Homebrew for the installation.

What is Homebrew? Are we making beer now?

Well, I’m glad you asked, and no you’re not going to learn how to make a refreshingly crisp ale in this tutorial.

Homebrew is a totally awesome package-manager, written in Ruby and utilising Git. In Homebrew’s own words it “… installs the stuff you need that Apple didn’t.”

Note: As with any software installation, it’s always good to backup your system and data before proceeding.

First check to see if Homebrew is already on your Mac by entering brew -v in the command-line.

  • If you see something like Homebrew 0.9.5, then you already have Homebrew.
  • However, if you see Command not found, then you don’t have Homebrew installed. You’re going to change that right now.

Installing Homebrew is stunningly easy. Enter the following into your command line:

ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)"

This will download and run a Ruby script.

Note: If you’re running Snow Leopard or later, by default you should have a fairly modern and stable version of Ruby on your machine. However, it’s recommended that you run the latest versions of Mac OS X and Ruby.

If you’re curious about what Homebrew’s installed, look in the directory /usr/local/Cellar/.

Updating Homebrew and Playing Doctor

Now that you have Homebrew installed, make sure all of the brew formulae are up to date as there are continual updates, pretty much every day. To bring it up to speed, just enter brew update at the prompt and give it a minute or so, as there are many formulae out there.

Optionally, you can use Homebrew to clean up your environment by entering brew doctor.

For this tutorial, it’s not mandatory and can feel a bit squirrelly because it will tell you about any oddities it finds in your system environment and tell you how to fix them. However, the good doctor’s output can be very helpful when you’re looking for a clue about why an installation went awry.

You’re almost there! Now that you have installed and updated Homebrew, you’re going to install the magical autocomplete tool. Enter the following command at your prompt:

brew install git bash-completion

You’re not quite finished yet. Next, you need to change your bash profile so that bash-completion loads whenever you open the terminal. Follow these instructions.

  1. Open a terminal window, and navigate to your home folder: cd ~
  2. Check to see if the file .bash_profile exists in your home folder: ls .bash_profile
  3. If the file is missing, create it: touch .bash_profile
  4. Open the file in your favorite text editor: open .bash_profile
  5. At the end of the file (unless you have a reason to put it elsewhere), enter the following:
  6. if [ -f `brew --prefix`/etc/bash_completion ]; then
      . `brew --prefix`/etc/bash_completion
    fi
  7. Close your editor and the terminal window.

Test It Out!

Open a new terminal window. Just like in bash, autocompletion happens when you type the [tab] key. So, start typing git [tab][tab] and be sure to type a space after ‘git’ before hitting the tab button. You should see the output below.

 ~ $ git 
add                      column                   get-tar-commit-id        pull                     shortlog 
am                       commit                   grep                     push                     show 
annotate                 config                   gui                      rebase                   show-branch 
apply                    credential               help                     reflog                   stage 
archive                  credential-osxkeychain   imap-send                release                  start 
bisect                   deliver                  init                     relink                   stash 
blame                    describe                 instaweb                 remote                   status 
branch                   diff                     log                      repack                   submodule 
bundle                   difftool                 loggraph                 replace                  subtree 
checkout                 fetch                    merge                    report                   svn 
cherry                   filter-branch            mergetool                request-pull             tag 
cherry-pick              finish                   mv                       reset                    whatchanged 
citool                   format-patch             name-rev                 revert                   
clean                    fsck                     notes                    rm                       
clone                    gc                       p4                       send-email               
 ~ $ git

Sweet! A list of all the Git commands pops up, and you can continue typing where you left off.
Rage Comic Doctor is In

Note: If you get error messages instead of the cool list above, then run brew doctor, as mentioned earlier. Fixing the issues the good doctor finds should solve your problems. You’ll know everything is fixed when brew doctor gives you the message “Ready to Brew.”

A conflict with the Git installed by Xcode is a common issue. Try overwriting that Git using brew git install followed by brew link git.

If there are problems, brew doctor will provide you with instructions to fix them.

Now navigate to a Git repository (Navigate to the git-extras folder you installed earlier if you don’t have any repos of your own).

Type git bra[tab], and you’ll see that autocompletion recognizes this as git branch. Continue typing ma[tab], and autocompletion extends this to git branch master. YAY!

[ctrl]-c out of that and try a different command. Type git log --gr[tab][tab] and you see the two available flags. Continue typing a[tab][return].

Nice! You have a graph of your most recent commits! Now use autocomplete to run the following verbose command quickly, typing only as much as is necessary to trigger autocomplete:

log --graph --pretty=oneline --decorate --abbrev-commit

Very cool.

Wait, Wait! Wasn’t there something about remembering what branch I checked out locally?

Yes, thanks for reminding me. Is it even possible for a command-line environment to keep the user informed in real time? Well, what about the prompt?

The prompt is a truly excellent way to keep you informed about the state of the local repo that’s in your current working directory, especially if you have multiple terminals open inside multiple repos.

A Branch in Your Prompt

Before continuing, are you curious to see what your current prompt really is?

In your terminal window, enter echo $PS1, and you’ll see the prompt’s definition. The default prompt for bash is ‘\s-\v\$ ’

When you installed the completion script, you also installed the bash-prompt script as well. So now it’s pretty easy to set up a custom prompt to show your repository’s active branch.

In your terminal window, enter the following. (Note that there is no space on either side of the “=” sign, and that there are two underscores at the beginning of __git_ps1.)

PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '

Now you should have a prompt that looks something like this.

[jeff.wolski@Jeff-Wolskis-MacBook-Pro git-extras (master)]$

Well, the branch is there, but this prompt is not as useful as it could be. Enter each line below (one at a time) into your terminal command line, and observe what happens to the prompt.

Start with just the branch name in the prompt using the function __git_ps1.

PS1='$(__git_ps1 "%s")'

The "%s" is a placeholder for the value returned from the function.
You need some space between the prompt and the cursor, so add a space after the function call.

PS1='$(__git_ps1 "%s") '

Now add a $ near the end.

PS1='$(__git_ps1 "%s") \$ '

How about some parenthesis around the branch name?

PS1='$(__git_ps1 "(%s)") \$ '

Some people like to see the present working directory, so add \w to the beginning of the prompt.

PS1='\w $(__git_ps1 "(%s)") \$ '

But a nicer format might be to use \W instead (it’s much less verbose).

PS1='\W $(__git_ps1 "(%s)") \$ '

Many people switch between users and like to the current one to be in the prompt. Add \u to the beginning of the prompt now.

PS1='\u \W $(__git_ps1 "(%s)") \$ '

If you appreciate a reminder of what machine you’re on, add the machine name to the prompt with \h.

PS1='\u@\h \W $(__git_ps1 "(%s)") \$ '

Perhaps you need a timestamp for each command as you look back in your terminal history? Put a date function into your prompt with:

PS1='$(date +%k:%M:%S) \W $(__git_ps1 "(%s)") \$ '

Now close the terminal window you’ve been using and then open a new one. You’ll discover the prompt you just created is no longer there!

If you create a prompt you’d like to be the default for all your terminal windows, type it into the .bashrc file in your home directory — create the file with touch .bashrc if it does not yet exist. The bash shell reads the ~\.bashrc file whenever it starts up.

Where To Go From Here

Congratulations! You’ve set up Git completion on your machine, which should save plenty of brain-power, time and typing. By completing this Git tutorial, you also learned how to create a customized prompt with the branch name included.

Play around with different options for a custom prompt until you find one that’s right for you. You can find more bash prompt options here.

Also, Homebrew is a fantastic tool you can use to install any number of other command line enhancements. Learn more about Homebrew to discover other ways it might enrich the quality of your life :].

Finally, check out How To Use Git Source Control with Xcode in iOS 7, if you haven’t already.

Thanks for working through this Git tutorial! If you have questions, comments or just want to share your discoveries, leave your notes in the comments below.

Git Tutorial – Git Fu With The Command Line is a post from: Ray Wenderlich

The post Git Tutorial – Git Fu With The Command Line appeared first on Ray Wenderlich.


Swift: The raywenderlich.com Podcast Episode 10

$
0
0
Episode 9: CloudKit

Episode 10: Swift

In this episode, we take a deep dive into Swift with special guest Colin Eberhardt, co-author of our upcoming book Swift by Tutorials.

We also talk about Apple’s new announcements: the Apple Watch, iPhone 6 and iPhone 6 Plus, and Apple Pay.

[Subscribe in iTunes] [RSS Feed]

Here’s what is covered in this episode:

  • News: Apple Watch, iPhone 6 and iPhone 6 Plus, and Apple Pay
  • Tech Talk: Swift – What are its coolest features? Is it ready for prime time? And much more!

Links and References

News

Tech Talk: Swift

Contact Us

Where To Go From Here?

We hope you enjoyed this podcast! This marks the end of Season 1 – stay tuned for a new format and surprises in Season 2, which will start in October.

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

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

Swift: The raywenderlich.com Podcast Episode 10 is a post from: Ray Wenderlich

The post Swift: The raywenderlich.com Podcast Episode 10 appeared first on Ray Wenderlich.

Unity New GUI Tutorial – Part 1

$
0
0

Unity New GUI Tutorial

You will love getting gooey with Unity’s new GUI!

There’s no denying that Unity is an awesome game engine. By catering to the needs of the independent developer while also providing features of premium AAA engines, it’s no surprise that Unity is a now mainstay in game development.

Unfortunately, every Achilles has his heel and for Unity, that was the old GUI system.

The old GUI system was a painful system that required you to write all your GUI code in onGUI. It was very programmer-centric which goes against the visual centric nature of Unity itself, and not mention slow and inefficient.

There were third party tools such as NGUI that aimed to solve this problem, but it’s a little frustrating to have to pay more money for something that should be included with the base package.

Well, the folks over at Unity Technologies have listened. After two years of development, they have provided a solution that will erase those past pains. With the release of Unity 4.6, you have access to an entirely new GUI system, and you’re going to learn all about it this tutorial, right here, right now.

In this three-part series, you’re going to add new GUI to the game created in our previous tutorial series – How to Make a Game Like Jetpack Joyride in Unity 2D.

Note: If you haven’t completed the original tutorial, it’s okay, but it wouldn’t hurt to go back through it. If you start there, when you get to the end of this series, you’ll have a fairly functional game, rather than just a project with a simple menu scene. You’ll also see how you can migrate from the old GUI system to the new one, and that’s just priceless.

As you work through this tutorial, you’ll add a classic main menu scene to the game.

Unity 4.6 New GUI

However, simply adding few buttons isn’t sufficient for you to master new GUI system. To add a little spice and satisfy your users’ cravings for engaging UI, you’ll

  • Animate the buttons
  • Create a settings dialog that slides into the scene
  • Use more new GUI controls like Text, Slider, Panel, Mask and so on.

If you want a sneak peak, just download and run the final project to see what you’ll learn from this tutorial. :]

Getting Started

To start, you’ll need some images for backgrounds, buttons and other UI elements, as well as a few fonts for the labels and text on the buttons. And no, you won’t have to draw anything yourself or scour the web for the right assets because I’ve prepared a special package that has everything you need.

You can download the package here: RocketMouse_GUI_Assets

This package contains background images, buttons, icons and other game art created by my lovely wife Svetlana.

You’ll also find two fonts from dafont.com. For those cool fonts, thank Rodrigo Fuenzalida (Titan One font) and Draghia Cornel (DCC Dreamer font)

As mentioned, you’re going to add a new scene to the Rocket Mouse project created in previous series, so start by downloading the final version of that project: RocketMouse_Final

This is all you need! Well, except love, if you take the Beatles song to heart :]

Creating MenuScene

Download and unpack the Rocket Mouse project using the link above. Open this project in Unity by selecting File\Open Project… within Unity and specifying the root folder of the project.

Note: Alternatively, open the Assets\Scenes folder within the project folder and double-click on RocketMouse.unity scene to open Unity.

After the project loads, you’ll see a comfortably familiar scene that looks as it did when you left off, or, a scene that is completely new to you — depending on whether you completed the original tutorial. In any case, keep calm and read on. :]

You’re going to spend most of your time working with a new scene that you’ll create now. Select File\New Scene in the menu to create a new empty scene.

It’s better to save the scene straight-away, so open the Save Scene dialog by choosing File\Save Scene. Then, enter MenuScene as the scene name and save it to the Scenes folder, right next to the RocketMouse scene.

rmouse_ui_3

Take a look at the project browser to confirm there’s two scenes in one folder.

rmouse_ui_4

Note: If you encounter any issues while opening the project, creating or saving the scene or adding assets, then go work through the original Rocket Mouse tutorial. There you’ll find detailed, step-by-step instructions — often in form of animated GIF images that are not included in this tutorial, for the sake of staying true to the DRY principle. :]

Importing Images and Fonts

First on your todo list is to add assets to the scene, so unpack the assets package. There you’ll find two folders: Menu and Fonts.

Select both folders, and then drag them to the Assets folder in Unity’s project browser view.

Allow a few seconds for Unity to process the files. Then you should see a Fonts and Menu folder in the project browser as shown below.
rmouse_ui_5

Woo-hoo! You’ve finished the prework, and can now create your first UI element inside the new Unity GUI system.

Adding your First UI Element

The first element you’ll make is the background image for the menu scene.

Select GameObejct/UI/Image in the menu. This adds an object named Image to the scene. You should see it in the hierarchy as a child of Canvas. All elements must be placed on a Canvas, so if you don’t already have one, Unity will provide one for you.

To ensure you can see the image in the scene view, select Image in the hierarchy and set its Pos X and Pos Y to 0.

rmouse_ui_7

Note: I can already hear questions like, “What’s Pos X?”, “What’s the Rect Transform component and where is the familiar Transform component?”

As you work through this, you’ll find answers to your burning questions. It’s easier to learn about them in the context of other objects in the scene, so that you can observe behaviors with different settings.

Properties like Width and Height or Pos X shouldn’t require any explanation.

You’ll set the correct position and size in a moment. Right now, there is another interesting thing to muse upon. Look carefully in the hierarchy, and you’ll see there are three new objects in the scene.

You should see these:

  1. Image
  2. Canvas
  3. EventSystem

rmouse_ui_6

The Image is a non-interactive control that displays a Sprite texture and has many options to tweak.

For instance, you can apply a color to the image or place materials on it. You can even control the amount of the image that displays. Bring it to life with an animation “appear” such as a clockwise wipe.

The Canvas is a root object for all your UI elements, and as previously stated, it’s created automatically when you add your first UI element. It has multiple properties that allow you to control how your UI renders, and you’ll explore some of them during this tutorial.

The EventSystem is responsible for processing and handling input, raycasting and the events within a Unity scene. It’s required for the UI to work, so that’s why it was added automatically.

Setting up Menu Background Image

It’s time to get back to the Image, and the first thing to do is rename the Image to img_background.

Next, open the Menu folder in the project browser and find the menu_background image. Drag it to the Source Image field of the Image component in img_background in the Inspector.

rmouse_ui_8

Now you have a background image instead of the default white image. However, it doesn’t look like a good background because it’s too small and the aspect ratio is incorrect.

To fix, find the Set Native Size button in the Inspector and click it to set the size to 1024 x 577.

rmouse_ui_9

Now it looks like a proper background.

rmouse_ui_11

However, there are still few issues:

  1. The actual size of the image is 1136 x 640, which is just enough to cover the full screen of a 4-inch iPhone.
  2. Shrink your Scene view, and you’ll see the Canvas (the white rectangle) covers only the part of the image. If you switch to the Game view, you’ll see only a part of the background image, as if the camera is too close to the image to capture it completely.

rmouse_ui_10

Note: The original game was designed for iPhones with 3.5- and 4-inch displays. This is why all the game art supports 1136 x 640 and 960 x 640 resolutions. But soon you’ll see how the UI can adapt to different game resolutions.

The first issue is the result of the default Import Settings, and you’ll fix them in the next section. You’ll tackle the second issue by using a Reference Resolution Component.

Fixing the Image Import Settings

You need to allow slightly bigger images for your project, and prevent Unity from scaling them down.

Open the Menu folder in the project browser and select the menu_background image. In the Inspector, select Default tab and set Max Size to 2048 and click Apply.

rmouse_ui_12

Now select img_background in the hierarchy, and then click Set Native Size again. The width and height should change to correct values of 1136 and 640, respectively.

rmouse_ui_13

See? That was indeed an easy fix to make. Onto the next fix!

Using the Reference Resolution Component

When you have the correct background image in the scene, it’s time to adjust the way it displays.

First of all, know that the display is not the result of a bug. From Unity’s point of view, you have the Game view — or viewport — set to the small size of 550×310, so it just shows you a portion of the image that fits in the Game view.

If you were to run the game on a device or simply stretch your Game view to fit the whole image, you’ll see the entire background image.

Although Unity’s settings make sense in most scenarios, there are times when you need different behavior. Like when you have a small monitor that doesn’t fit your target device’s resolution.

Additionally, many games support only one resolution.

Designers use this reference resolution to dictate sizes, positions and other data. So, when you develop the game you want to make sure to enter the designer’s specifications without additional calculations, so the user sees everything exactly as intended.

If you’ve ever ignored your designer’s directions, surely you know there’s a price to pay. Really though, the user’s experience and the varying resolutions out there are more important, but you have to keep your designer happy, too. :]

Fortunately, a special component comes to the rescue. This component is called Reference Resolution and you need to add it to the Canvas component.

Select Canvas in the hierarchy, and then click on Add Component. Start typing Reference Resolution to find the required component and click on it as soon as it shows in the list.

rmouse_ui_14

After adding the component, set its Resolution to 1136 x 640. Also, slide the Match Width or Height all the way to the right, or simply enter 1 in the input field.

rmouse_ui_15

After making those changes, you’ll immediately see the full background image, even in a small Game view window.

rmouse_ui_17

Change the Game view resolution to see how your game might look in a different resolution, for example on 3-5 inch iPhone. Nice. It still looks good!

rmouse_ui_16

Now switch to the Scene view, and you’ll see the Canvas’s size doesn’t change when you resize the Scene view.

As you can see, the side edges of the screen are neatly cropped, while the central part is fully visible. This is the result of setting Match Width or Height to 1 (match height). It works perfectly for your target resolutions.

And that’s how you manage your designer’s instructions for the background and your users’ many potential resolutions.

But what about the buttons? What happens when they’re very close to the left or the right edge of the screen? You sure don’t want to crop or hide them.

Fortunately, Unity has a feature that will help you sidestep this rookie error. You’ll learn about it soon.

Adding Header Image

It might have seemed a bit time consuming to add the background image, but that’s mostly because you were setting up the initial UI. Plus, after doing this a couple of times you’ll find the setup to be so fast and easy that you’ll barely have time to blink before you’re done.

Before moving on to buttons and other UI controls, you’ll add one more image — the header image. For this exercise, you’ll use a non-fullscreen image to demonstrate a few other important concepts of a new GUI system.

Open the Scene view and select GameObject\UI\Image in the menu. This will add another white image somewhere to the scene. Here’s where it ended up for me:

rmouse_ui_18

Note: Should the image in end up in the hinterlands, just set its Pos X and Pos Y properties to 0

Now, turn that white rectangle into an actual image by following these steps:

  1. Select Image in the hierarchy and rename it to img_header.
  2. Open the Menu folder in the project browser and search for the header_label image.
  3. Drag this image to the Source Image field on the Inspector.
  4. Click Set Native Size in the Inspector.

rmouse_ui_19

As you can see, it was easy enough to add another image. Now you just need to work with the positioning, which brings you to your next exercise: working with the Rect Transform component.

Rect Transform, Anchors, Pivot and you

If you worked with Unity before, or at least completed some Unity tutorials on this website, then you’ve probably had some exposure to the Transform component.

If not, that’s fine too. It’s simply a tool that can position, rotate and scale objects in a scene. Here’s what it looks like:

rmouse_ui_20

You will see the Transform component when select any type of GameObject in your Hierarchy.

rmouse_ui_21

However, if you select any UI element, for example img_header, you’ll see a different component named Rect Transform.

rmouse_ui_22

As you can see, Transform and Rect Transform look a bit different, but the Rect Transform can change the way it looks, depending on the Anchor settings. For example, it can look like this:

rmouse_ui_23

Note: Instead of Pos X, Pos Y, Width and Height, you work with Left, Top, Right and Bottom.

Are you wondering about the Anchors setting that changes the look of Rect Transform so dramatically? You’ll find the answers you seek in the next section.

Anchors

Setting Anchors is a simple, elegant and powerful way to control the position and size of your UI elements, relative to their parent. It’s especially handy when you resize the parents.

When you set Anchors, you specify several positions in the parent, usually one in each corner of the UI element Rect. When the parent is resized, your UI element will try to maintain uniform distance to the anchor points, thus forcing it to move or resize right along with its parent.

To see different Anchor Presets just select img_header in the hierarchy and click on the rectangle right above the Anchors field in the Rect Transform component.

rmouse_ui_24

After clicking, you’ll see various Anchor Presets; these are the most common settings for Anchors, but you’re not restriced to them and can customize them. You can also select different horizontal and vertical behavior for your UI element.

This will all make more sense once you work with it. If you look at the next image, which has the background image disabled, you’ll be able to see the Canvas size changes a bit better.

As you can see, the Anchors settings control how your UI element adapts to screen size changes.

rmouse_ui_25

I’m sure you want to try some different settings to understand how they work, but before you do be sure to at least read through the next section. It’ll help you understand Anchors a little better so that you can get more out of your experimentation.

Anchors Manipulator

Currently, the Anchors shown use 4 triangles. Here is how it looks with Anchors set to the top-center:

rmouse_ui_26

Custom Anchors

You can manually move Anchors to a custom position as the presets are entirely optional — they are just for your convenience.

Note:

You might find yourself in a situation where the translation gizmo covers the anchor icon, making it impossible to select the anchor.

In this case, just select the anchor icon by choosing an anchor preset (for example, the left-hand side of the screen). The anchor icon will shift to that part of the screen, allowing you to select and move it at will.

rmouse_ui_27

Note: See how the image moves to the right when you resize the Canvas? However, it moves only a little in relation to the right edge of the Canvas. This happens because Anchors are set to 25% width of the Canvas.

Splitting Anchors

You can split Anchors to make stretch a UI Element horizontally, vertically or in both dimensions.

rmouse_ui_28

Note: You’re not actually resizing the Canvas when dragging one if its edges. In fact, you can’t resize the Canvas this way.

Look for the word Preview, next to the cursor when you try to resize it. Use it to experiment with sizes and see how your UI elements adapt to different screen sizes.

rmouse_ui_29

Rect Transform Depends on the Current Anchors Setting

Depending on the Anchors setting, the Rect Transform provides different ways to control the size and position of your UI element.

If you set Anchors to some single point, without stretching, you’ll see Pos X, Pos Y, Width and Height Properties.

However, if you set Anchors in such a way that stretches your UI Element, you’ll get Left and Right instead of Pos X and Width (if you set it to stretch horizontally) and get Top and Bottom instead of Pos Y and Height (if you set it to stretch vertically).

In this screenshot, img_header’s Anchors are set to middle-stretch. This means that the image stays in the middle of the Canvas vertically and stretches horizontally.

rmouse_ui_30

Since Pos X and Width depend on the size of the parent, set the padding from the left and right edges of the parent.

Pivot

There is one final property to discuss in the Rect Transform component, and this is Pivot.

The Pivot is a point around which all transformations are made. In other words, if you set your UI Element position, you set the pivot point. If you rotate your UI Element, it’ll rotate around that point.

The Pivot is set in normalized coordinates. This means that it goes from 0 to 1 for both height and width. Where (0,0) is the bottom left corner and (1,1) is the top right corner.

Note: You can also set Pivot outside the UI Element bounds. In this case, Pivot will be outside (0,0) – (1,1) range. This can be useful. For example, you might want to rotate your object around some point in the scene. To alter you pivot, you must make sure Pivot/Center button is toggled to Pivot like so: Pivot / Center button

You can change Pivot in the Rect Transform component in the Inspector or you can use the Rect Tool.

rmouse_ui_31

Take a look at following two images that demonstrate the UI Element with the same Pos X and Pos Y values, but each shows different placement in the scene.

The first image shows Pivot at its default value of (0.5 , 0.5), which is the center of the UI element. The Position is set to (0, 0) and Anchors are set to top-left.

rmouse_ui_32

Note: It’s important to understand that position of the UI Element is set relative to Anchors. This is why (0,0) position means the distance from Anchors, which are set to top-left corner of the Canvas.

Now take a look at the second image. As you can see, Position is unchanged at (0,0), but since the Pivot is set to left bottom corner (0,0) you can see that the image’s bottom corner, and not the center, is now placed at the Canvas’s top-left.

rmouse_ui_33

It’s harder to show how Pivot affects rotation and size using a still image, so here are few animations:

rmouse_ui_34

Please note how the image rotates around the pivot point indicated by a blue circle, which is an element you can freely move.

rmouse_ui_35

Note: Hold the ALT key while scaling to scale around the pivot point.

As you can see, Pivot also affects how your UI Element resizes.

Note: Another important thing to understand is that when you change the size of UI Element, you don’t change its Scale. Instead, you change its size e.g. Width and Height or Top, Right, Left, Bottom paddings.

There are a few differences between those. For example, size can’t be negative, but scale can be; using negatives will flip your UI element. In most cases, you should only change the size of your UI Elements.

Placing a Header Image

Phew! That was quite a few words dedicated to Rect Transform, Anchors and Pivot. Believe me, you’ll be grateful you spent the time working through the exercise, as understanding them is essential to awesome UI in your games.

Going forward, you’ll concentrate on actually creating the menu scene. The rest of the sections will go by in the twinkle of an eye.

All those manipulations completely exhausted the poor little img_header. It’s time to place it where it should be and leave it alone to recover.

rmouse_ui_36

Before you continue, re-enable img_background if you disabled it to see the Canvas border.

Then select img_header in the hierarchy and set its properties in the Inspector as follows:

  1. Click Set Native Size to reset the size, as you probably messed with it while playing around with Pivot.
  2. Set Anchors to top-center.
  3. Set Pos X to 0 and Pos Y to -100.

rmouse_ui_37

You should see something like this in your Scene view:

rmouse_ui_38

That’s it. Now, leave the header image alone. It’s a little tired, too. :]

rmouse_ui_39

Adding the Start Button

Now, that your app has a nice background with a label, it’s time to add some buttons.

Choose GameObject\UI\Button in the menu. This will add a Button object to the scene, you should see it in the hierarchy. If you expand it in the hierarchy, you’ll see that the button contains a text label — you’ll learn about these later.

rmouse_ui_40

Look at the button in the Inspector, and you’ll see it has a familiar Image (Script) component, the same as you used to add the background and the header label.

Additionally there is a button (Script) component. In other words, a button is just an image with an attached button script that contains a Text.

Note: The text label is optional, so if you have a button image with text drawn right into the image, you can delete the text element. You’ll do this a couple of times during this tutorial.

Positioning the Button

Now it’s all about positioning and resizing the button. Follow these steps:

  1. Select Button in the hierarchy and rename it to btn_start.
  2. Set its Anchors to bottom-stretch, since you want it to stretch horizontally if the screen size changes.
  3. Set both Left and Right to 400.
  4. Set Height to 80.
  5. Set Pos Y to 300.

rmouse_ui_41

Then select nested Text element and set its Text to Start Game. Change the Font Size to 32 to make the text of the button larger.

rmouse_ui_42

This is what you should see in the Scene view:

rmouse_ui_43

Well…you definitely have a button now, that’s for sure, and it’s in need of a facelift. To make the button look good, you’ll set an image as its background and then use a fancier font.

9-Slice Scaling

You set the image for the Button the same way you set an image for the Image. After all, they use exactly same component. However, unlike images that rarely scale, especially non-uniformly, buttons often come in completely different sizes.

Of course, you could create a background image for every single button size in your game, but why waste all that space? You’ll use a technique called 9-Slice scaling, which allows you to provide one small image that scales to fit all the sizes.

No, there is no magic involved. You won’t have to put your images in a magic fountain before you can use them :]

This technique makes this possible because the image does not scale evenly. There are nine zones, each of which scale differently.

rmouse_ui_44

This ensures the image will look good at any scale.

Preparing Button Images

Before you can use a sliced image, you need to set those 9 zones. To do this, open the Menu folder in the project browser and select btn_9slice_normal image.

In the Inspector’s Import Settings, set Format to Truecolor and then click on the Sprite Editor button to open the Sprite Editor view.

rmouse_ui_47

Note: Setting Format to Truecolor is not required and not related to image scaling. However, I experienced compression artifacts with my set of images, so I found that it’s better to do this. If you use your own images and they look good in the compressed format, then you don’t need to tinker with this setting.

In the Sprite Editor, set the Border values to L:14, R:14, B:16, T:16. Remember to click Apply!

rmouse_ui_45

Repeat the same process for btn_9slice_highlighted and btn_9slice_pressed images, which you’ll use for different button states.

Setting Button Images

After preparing all images, you only need to drag them to corresponding fields in the Inspector. Select btn_start in the hierarchy and follow these steps:

  1. Change Image Type to Sliced in the Image component.
  2. Change the Transition property in the Button component to SpriteSwap.
  3. Drag btn_9slice_normal to Source Image in the Image component.
  4. Drag btn_9slice_highlighted to Highlighted Sprite in the Button component.
  5. Drag btn_9slice_pressed to Pressed Sprite in the Button component.

rmouse_ui_48

Note: If you encounter this error message, This image doesn’t have a border, then you probably forgot to set the Border in the Sprite Editor in the Import Settings as described above.
rmouse_ui_46

Before running the scene and enjoying your cool buttons you’ll going to take a few seconds to change the font used by the nested Text label. This will make the button mega-awesome.

Setting Custom Font for the Button

Using a custom font is easy. Remember the Fonts folder in the package you downloaded and added it to the project? Now it’s time to break it out and use one of those fonts.

Select the Text label nested in the btn_start in the hierarchy. Then open the Fonts folder in the project browser and drag the TitanOne-Regular font into the Font field. Also set the Color to white.

rmouse_ui_49

Now run the scene and enjoy your new mega-awesome button! :]

rmouse_ui_50

Removing Button Transparency

Did you notice that you could see the background through the button? Depending on what you’re trying to achieve, this can be good or bad. For the main menu on this game, it’s better to remove this transparency.

Note: I believe this transparency is added by default, because in many cases you have your UI on top of your game view and want the player to see through buttons such as pause or joystick.

It only takes a few seconds to undo this. Select btn_start in the hierarchy and double-click on the Color property inside the Image component. In the opened color picker dialog set A (Alpha) to 255 and close the color picker.

rmouse_ui_51

Now it looks much better!

rmouse_ui_52

Adding the Settings Button

There are only few things left to do before moving on to the next part, and one of them is adding the Settings button.

You can probably do this yourself, so you’re only getting the size and position of the button to start. The rest is almost identical to how you created the Start Game button.

Note: The easiest way is of course to duplicate the button and adjust some properties, but try creating the button from scratch since you’re here to learn.

So, here are the properties of the Settings button that are different:

  • Name: btn_settings
  • Rect Transform: Left and Right are 450, Height is 70 and Pos Y is 180
  • Text: Settings
Solution Inside: Need help creating the Settings button? SelectShow>

This is what you should see in the Scene view after adding the Settings button:

rmouse_ui_55

Starting the Game

The final task for this part is to actually click the Start Game button and run the second scene in the game itself.

Adding Scenes to Build

Before you can run different scenes, you need to add them to the Scenes in Build list in the project settings, so that they are included in the final application.

To do this select File\Build Settings… to open the Build Settings dialog. Then open the Scenes folder in the project browser and drag the MenuScene first, and then the RocketMouse scene to the Scenes in Build list.

Note: The order is important. Follow it!

rmouse_ui_57

Then close the Build Settings dialog.

Creating UIManager

When you add an event handler to the button, you need to specify which method to call when you tap the button. This means you need to attach an object to a script, since you can’t use static methods.

So, add an empty GameObject and attach a script to it. This script will contain all methods called by UI elements in the MenuScene.

Choose GameObject\Create Empty in the menu. Then select GameObject in the hierarchy and rename it to UIManager.

After that, click Add Component in the Inspector and select New Script. Name it UIManagerScript. Make sure the Language is set to CSharp and click Create and Add.

This is what you should see in the hierarchy and the Inspector:

rmouse_ui_56

Double-click on the UIManagerScript in the Inspector to open the script in MonoDevelop. Once the script loads, remove the Start and Update methods, and add the StartGame method as follows:

public void StartGame()
{
    Application.LoadLevel("RocketMouse");
}

Save the file and make sure it contains no errors by building it within MonoDevelop. Selecting Build\Build All in the MonoDevelop’s menu to do this.

Calling the StartGame method when the Player Clicks the Button

Switch back to Unity and follow these steps:

  1. Select btn_start in the hierarchy and scroll down in the Inspector to the On Click (Button) list.
  2. Click the + button to add new item.
  3. Then drag UIManager from the hierarchy to the newly added item in the list.
  4. Click on the dropdown to select the function. Right now, it’s set to No Function.
  5. In the opened menu select UIManagerScript\StartGame ()

rmouse_ui_58

Run the scene and click the Start Game button, this should open the game scene.

Where to go From Here?

It might feel like you didn’t do much in this last section of this tutorial. Not true. You set up the UI, added images and buttons, and even wrote the code that starts the game when you click on the button!

In many games, that’s all that comprises the UI.

You also learned a lot about Rect Transform, Anchors, Pivot and so on. What’s cool is that now that you understand them, you’ll be able to move much faster when you apply these new skills to your own projects. You can download the completed project here.

In the next part of this series, you’ll learn how to animate UI elements, create dialogs, use controls like Slider and Toggle, and by the end of it you’ll have a working menu scene.

If you have any questions or comments please leave them below! See you in Part 2!

Unity New GUI Tutorial – Part 1 is a post from: Ray Wenderlich

The post Unity New GUI Tutorial – Part 1 appeared first on Ray Wenderlich.

Video Tutorial: Introduction to Unity Part 8: Intro to Scripting

Unity 4.6: New GUI – Part 2

$
0
0

Rocket Mouse New GUI

Learn to add some animation to your GUI.

Welcome back! In Part 1 of this three-part tutorial series, you created a nice scene with two buttons. You learned how to use the Image, Button and Text UI controls, as well as concepts such as Anchors and Pivot. However, the scene itself is pretty simple and in need of an upgrade.

Getting Started

In this tutorial, you’ll spruce up the scene by adding animations, a settings dialog and more UI controls like the slider and the toggle. If you don’t have the project already, download it here.

So, go ahead and open the project in Unity. Open the MenuScene, grab an invigorating beverage and start thinking GUI!

Animating Buttons

You’re going to jump right into the exercises by adding some cool animations. There are several reasons for that. First — animations are cool! Second, they’re practical for this porject. You need the buttons to exit from the scene so there’s space to display the new dialog that you’ll create later.

Creating Animation and Animator

Animating buttons is no different from animating any other Unity object. You’ll need to add an Animator component, create few animations and set up states and transitions between them.

Here are the steps to success:

  1. Select btn_start in the hierarchy
  2. Open the Animation view.
  3. Click [Create New Clip] in the Animations dropdown list on the left.
  4. Note: Select btn_start in the Hierarchy, since you’ll add the new animation and animator to the currently selected object.

    rmouse_ui_59

  5. Name the animation btn_start_slide_out and save it in the Animations folder.

rmouse_ui_60
In addition to creating the animation itself, Unity also kindly adds an animator component to btn_start and creates an Animator Controller.

rmouse_ui_61

Note: If you’re unfamiliar with animations and Animator Controllers in Unity, please complete the original tutorial – How to Make a Game Like Jetpack Joyride in Unity 2D.

Animating a Button Sliding Out of the Screen

Although you’ll technically make two animations — the button slide out and then the slide back in — you’re going to be a savvy developer and create one, and then reverse it.

To create the slide-out animation, follow these steps:

  1. Select btn_start in the hierarchy
  2. Make sure the Animation view is visible.
  3. Click on the 1:00 mark in the timeline and make sure animation recording turns on. It should do this automatically.
  4. Note: The easiest way to make sure recording is on is to take a look at playback controls and watch for them to turn red.
    rmouse_ui_62

  5. Change Anchors to top-stretch.
  6. Change Pos Y to 60 in the Inspector.
  7. Stop the recording by clicking the red circle button.

Note two following points marked with letters on the screenshot:

A: A keyframe was inserted automatically at 0:00 mark. At this point, the button is at its starting position, precisely where you positioned it in the previous tutorial.

B: Although the anchors’ visual representation didn’t turn red, you can see the numeric values changed and turned red, indicating that you’ve also animated the anchors.

rmouse_ui_63

Make both the animation and Scene view visible and play the animation. You’ll see something like this:

rmouse_ui_64

Did you notice the animation on the anchors? If not, surely you noticed that annoying blinking red arrow. (By the way, sorry about that. Graphic design isn’t my forte. Maybe I should have asked Vicki at Game Art Guppy for help.)

Anyways, why do you need to reposition anchors?

Well, when you think about it this way, it’ll be obvious: the position of the button is a distance to anchors. In case of btn_start, it was the distance from the bottom edge. Right now, you’re only working with vertical movement, so only the bottom edge matters.

To make sure the button “leaves” the screen, you move it up until it’s no longer visible. What do you do if you don’t know the height of the screen? How do you make sure the button stops right after it’s no longer visible?

The answer is by changing its anchors.

If you set anchors to the top edge of the screen, you simply set distance from the top edge of the screen. Thus, the button will always be above the edge and independent from the height of the screen, since it’s positioned relative to the screen’s top edge.

Animating Button Slide In

Nice work! You have a button that slides out of the screen, and now you need a reverse animation. You’ll use it in two cases:

  1. When the scene loads, you want the button to slide into position instead of simply appearing.
  2. When you close the settings dialog, the buttons should return to their initial positions

It’s quite easy to do. First, you need to disable looping of the animation, since the button should move up/down and plant instead moving back and forth like a ping-pong ball.

To disable looping, open the Animations folder in the project browser and select btn_start_slide_out animation. In the Inspector, uncheck Loop Time.

rmouse_ui_65

Then select btn_start in the hierarchy and open the Animator view. Right-click on the btn_start_slide_out state and select Copy.

rmouse_ui_66

Then right-click somewhere on the free space inside the Animator view, and select Paste. This duplicates the btn_start_slide_out state.

rmouse_ui_67

Now, select this duplicated state, likely called something like btn_start_slide_out 0, and rename it to btn_start_slide_in in the Inspector. Additionally, set Speed to -1.

rmouse_ui_68

Then, inside the Animator view, right-click on the btn_start_slide_in and select Set As Default, since you want the button to start its lifecycle by sliding into the screen and not vice-versa.

rmouse_ui_69

Next, you need a parameter to control the state of the button. Click the + button and add new Bool parameter named isHidden.

rmouse_ui_70

Finally, add two transitions between states. To do this, right-click on the btn_start_slide_out state and select Make Transition. Then click on the btn_start_slide_in to make a transition.

After that, create a reverse transition by right-clicking btn_start_slide_in, selecting Make Transition and then clicking on the btn_start_slide_out. This is what you should get in the end:

rmouse_ui_71

You’re close, but you don’t want your transitions to be unconditional. Instead, you should use the isHidden parameter.

Select transition from btn_start_slide_out to btn_start_slide_in and change Conditions in the Inspector so that isHidden equals false.

rmouse_ui_72

Then select the transition that goes in opposite direction, from btn_start_slide_in to btn_start_slide_out and set its Conditions to be isHidden equals true.

rmouse_ui_73

Run the scene. You should see your button sleekly sliding in. Then change isHidden manually to make the button slide back.

rmouse_ui_74

Note: Occasionally, I’ve encountered problems during testing when manually switching isHidden — the button jumped to its start/stop position. However, everything worked perfectly fine when I changed the parameter within the code.

So if you’re experiencing problems, there’s no need to pound your fist on the desk. Just wait until you add the required code, which you’ll do soon.

Animating Settings Button

The settings button should slide down the screen to make some space in the center for the dialog.

Do you think you can animate the settings button yourself? All you need to know that

  • Offscreen Pos Y should be -50
  • You don’t need to change Anchors, since the button is already positioned relative to the bottom edge of the screen.

Give it a try on your own. If you need a nudge, feel free to sneak a peek into the spoiler below.

Solution Inside: Animating Settings Button SelectShow>

This is what you should get in the end:

rmouse_ui_75

Well, it’s nice to see the Settings button going up and down, but shouldn’t both buttons slide out simultaneously, just as they slide in at the start?

Of course they should, and you’re going to make that happen next.

Triggering Buttons Animation from the Script

In MonoDevelop, open the UIManagerScript that you created in Part One, and add the following instance variables just inside the class definition:

public Animator startButton;
public Animator settingsButton;

After that, add following method:

public void OpenSettings()
{
    startButton.SetBool("isHidden", true);
    settingsButton.SetBool("isHidden", true);
}

That is the all code you need. Save the script and switch back to Unity.

In Unity, select UIManager in the Hierarchy. Drag btn_start from the hierarchy to the Start Button field in the Inspector and btn_settings to the Settings Button field.

rmouse_ui_76

Then select btn_settings in the hierarchy and click + in the On Click (Button) list. Drag UIManager from the hierarchy to the new item in the list. After that, open the function selection menu and select UIManagerScript\OpenSettings ().

rmouse_ui_77

Run the scene. Wait for the buttons to stop moving and click on the Settings button. You should see both buttons move out of the screen in opposite directions simultaneously.

rmouse_ui_78

Adding the Settings Dialog

Look at all that gorgeous free space you created! That seems like the perfect place for a dialog to slide in there and fill the empty space. After all, nature abhors a vacuum :]

Creating the Panel

Usually, dialogs contain some other controls that should appear and move with dialog. Hence, it’s effective to create the dialog as a panel and set other UI Elements as child objects.

To create a panel, select GameObject\Create UI\Panel in the menu. This will create a full-screen panel that uses a white, semi-transparent image as a background. So, you should see some kind of full-screen veil.

rmouse_ui_79

However, this dialog won’t be full-screen; in fact, it will be relatively small. Follow these steps to set the dialog’s size and position:

  1. Select Panel in hierarchy and rename it to dlg_settings.
  2. Set its Anchors to middle-right, since you’ll position the dialog to the right edge off the screen, so that it’s not visible when you run the scene.
  3. Set Width to 400 and Height to 150.
  4. Set Pos X to 220 and Pos Y to 0.

rmouse_ui_80

You should see a semi-transparent rectangle to the right of the canvas rectangle. All UI elements outside this rectangle are not visible on the screen. This is precisely what you want for the dialog!

Setting the Dialog’s Background Image

You’re going to use a 9-slice image as the dialog’s background, so you need to set the border in the Import Settings first.

Open the Menu folder in the project browser and select settings_panel_bg_9slice. In the Inspector, click Sprite Editor to open the Sprite Editor view.

Set all Border values to 20 and click Apply at the top.

rmouse_ui_81

Now you can use this image as dialog background.

Select dlg_settings in the hierarchy and drag settings_panel_bg_9slice to the Source Image field in the Inspector. Double-click on Color right next to the Source Image field, and set A to 255 to remove transparency.

rmouse_ui_82

This is how the dialog should look like after you set the background image:

rmouse_ui_83

Adding the Label

In its present state, it’s difficult to argue that green rectangle is a settings dialog, but there’s an easy way to fix this — all you need to do is to write “Settings” on it. Poof! Whoosh! Magic. :]

Select GameObject\Create UI\Text to create a new Text UI element. Select Text in the hierarchy and rename it to lbl_settings. Then drag lbl_settings over dlg_settings to add it as a child object.

rmouse_ui_84

After that, select lbl_settings in the hierarchy and make following changes:

  1. Set Anchors to top-center.
  2. Set Pos X to 0 and Pos Y to -40.
  3. Change Text to Settings.
  4. Open the Fonts folder in the project browser and drag DCC – Dreamer font to the Font field in the Inspector.
  5. Set Font Size to 30.
  6. Set Alignment to Center Align.
  7. Set Color to White, with A (Alpha) 255 to remove transparency.

rmouse_ui_85

Animating the Settings Dialog

Now you’ve got a legitimate Settings dialog, and the next step is to make it appear when the user clicks the Settings button.

You’re going to use almost exactly the same technique as you did to make the buttons slide in and out, the only difference being that the dialog won’t slide in automatically after the scene starts.

Select dlg_settings in the hierarchy and open the Animation view. Then create a new animation by clicking [Create New Clip] in the animations list dropdown.

rmouse_ui_86

Name the animation dlg_settings_slide_in and save it in the Animations folder.

rmouse_ui_87

Then click on the 1:00 mark in the timeline and make sure recording is started, or start it manually by clicking the record button.

rmouse_ui_88

In the Inspector, set Anchors to middle-center and Pos X to 0.

rmouse_ui_89

Stop recording the animation.

rmouse_ui_90

Open the Animations folder in the Project browser and select dlg_settings_slide_in. In the Inspector uncheck Loop Time.

rmouse_ui_93

Now, switch to the Animator view. Copy and paste the dlg_settings_slide_in state to duplicate it. Rename the duplicate to dlg_settings_slide_out, and set its Speed to -1.

rmouse_ui_91

Note: This time, don’t change the default state! Dialog’s default state should stay dlg_settings_slide_in.

Click the + button and add new Bool parameter named isHidden.

Create two transitions between states, just as you did for the buttons. Then add isHidden parameter of type Bool.

Change the conditions of the dlg_settings_slide_out => dlg_settings_slide_in transition to be isHidden equals false, and for the dlg_settings_slide_in => dlg_settings_slide_out transition to be isHidden equals true.

rmouse_ui_92

Run the scene now and you’ll see the dialog sliding in at the start, and then overlapping the buttons.

rmouse_ui_94

This is getting there, but still not what you want. You need to disable the Animator component so it won’t play the animation at the start.

Select dlg_settings in the hierarchy and disable the Animator component.

rmouse_ui_95

Displaying Dialog on Button Click

When you run the scene, the dialog doesn’t appear straight away. This is good — however, it won’t show up even when you click the settings button. This — is not good.

My friend, you’re looking at your next problem to solve.

Open the UIManagerScript in MonoDevelop and add following instance variable:

public Animator dialog;

Then add following code to the end of OpenSettings:

public void OpenSettings()
{
    //..skipped..
 
    dialog.enabled = true;
    dialog.SetBool("isHidden", false);
}

This enables the Animator component and sets the correct value to the isHidden parameter.

Finally add new method called CloseSettings as follows:

public void CloseSettings()
{
    startButton.SetBool("isHidden", false);
    settingsButton.SetBool("isHidden", false);
    dialog.SetBool("isHidden", true);
}

This returns the buttons and hides the dialog. You’ll add the UI element that calls this method in a moment.

Save the UIManagerScript and switch back to Unity.

Select UIManager in the hierarchy and drag dlg_settings to the Dialog field in the Inspector.

rmouse_ui_96

Run the scene, then click the Settings button and see how the buttons slide out as the dialog slides in.
That’s better, but you can’t close the dialog.

To fix this, you need to add some kind of close button to the dialog.

Adding the Close Button

Select GameObject\Create UI\Button to create a button. Rename this new button to btn_close and drag it over dlg_settings in the hierarchy to add it as a child object. Also, this button won’t have a text on it, so remove the text nested in btn_close.

This is what you should have in the hierarchy at this point:

rmouse_ui_97

Now select btn_close and follow these steps:

  1. Set Anchors to top-right.
  2. Set both Pos X and Pos Y to 0.
  3. Open the Menu folder in the Project browser and drag settings_btn_close to Source Image field in the Inspector.
  4. Click Set Native Size.

rmouse_ui_98

This is how the dialog should look in the Scene view now:

rmouse_ui_99

Note: This time, you’re going to use another method to highlight the button’s image (Transition property in the Button script) called ColorTint, which is the default transition type. You’ll do this instead of adding two more images to represent highlighted and pressed button states.

The button looks great, but it does nothing. Fortunately, you’ve already added the method this button needs to call.

Select btn_close in the hierarchy, scroll down to the On Click (Button) list and click +. Drag UIManager from the hierarchy to the new item and then select UIManagerScript\CloseSettings () method in the dropdown.

rmouse_ui_100

Run the scene. Click the Settings button and close the scene by clicking Close after the dialog slides into the scene.

rmouse_ui_101

Hey, you’ve done well. That looks nice! :]

Adding Sound Settings

There’s not much sense in keeping a meaningless settings dialog, so, it’s time to add some actual settings to it. In this dialog, the player will have control over the music’s volume in the menu scene.

Music? Yes, what fun is a game without a rockin’ soundtrack?

Adding Music to the Menu Scene

You’re welcome to rummage around your files for a suitable clip, but you don’t have to because the project already contains a snappy music track. All you need to do is to play it.

Select Main Camera in the hierarchy and add the Audio Source component. Then, in the project browser, open the Audio folder and drag music to the Audio Clip field in the Inspector.

Enable Play On Awake.

rmouse_ui_102

Toggling Music On and Off

To toggle music on and off you’re going to use a…wait for it…toggle control. Select GameObect\Create UI\Toggle to add a toggle UI element to the scene.

rmouse_ui_103

The toggle controls consist of the root object which has a Toggle script attached, and several child objects:

  • Background: Image that is always visible (i.e. in both On and Off states)
  • Checkmark: Image that is only visible when toggle is active (ON).
  • Label: A label displayed next to toggle.

You don’t need a label this time, so remove the nested Label. Then rename toggle to tgl_sound and drag it over dlg_settings to put it inside the dialog. This is what you should see in the hierarchy after you’re done:

rmouse_ui_104

Select tgl_sound in the hierarchy. Set its Anchors to middle-left, Pos X to 115 and Pos Y to -10.

rmouse_ui_105

Note: Remember how anchors and position are set relative to the parent? This is why it’s important to add tgl_sound as a child of dlg_settings first and only after that set its position.

Keep in mind, changing anchors and pivot won’t change the UI element position, instead, they update position fields (e.g. Pos X, Pos Y, Left, Right) to values that position the element at the same place by using new anchors and pivot. Set these first, and play with the them to set the correct position.

Also, under the Toggle (Script) component, uncheck the Active checkbox.

Now you need to set images for Background and Checkmark child objects. Just as you’ve done with the other images, take them from the Menu folder in the project browser, and open that folder in the project browser.

You’re going to need two images:

  • settings_btn_sound for Background
  • settings_btn_sound_checkmark for Checkmark

Select Background contained in tgl_sound in the hierarchy and drag settings_btn_sound from the project browser to Source Image in the Inspector. Then click Set Native Size.

rmouse_ui_106

Then select Checkmark and repeat the previous steps, but this time use the settings_btn_sound_checkmark image from the project browser.

rmouse_ui_107

This is what you should see in the Scene View:

Unity Settings GUI

Note: As you can see, the size of the root object (wide rectangle) doesn’t match the background images. You can adjust its size, but it just fine this way.

Muting the Music

The good thing about UI elements’ event handlers is that sometimes you can get away without writing any code at all. Instead, you can set the UI element to change the property or directly call a function of the component attached to the object.

Here’s how you can change the mute property of the Audio Source component attached to MainCamera.

Select tgl_sound in the hierarchy, and in the Inspector find On Value Changed (Boolean) list. Click + to add new item.

rmouse_ui_109

Drag MainCamera from the hierarchy to the newly added item. Open the function selection dropdown and select AudioSource\mute from the Dynamic bool section at the top.

rmouse_ui_110

Note: When you look closely at the function selection options, you’ll see two mute properties: one in the Dynamic bool section and the other in Static Parameters.

The difference is quite trivial. If you select mute in the Dynamic bool section, its value will be set to the current value of the toggle’s Active property each time you toggle it.

If you select the mute property from the Static Parameters section, the new input field will appear and you’ll able to set its value in the Inspector to some constant value.

Of course, in the Dynamic bool section there are only properties and methods that take Bool values, because toggle’s active property type is Bool. Since you can specify any value as the static parameter, the Static Parameters section contains all public properties and methods.

Hence, when toggle is active (e.g. active equals true) it sets mute property of AudioSource to true and mutes the music.

Run the scene, open the settings dialog and try switching music ON and OFF.

Using Slider to Regulate the Volume

It’s really cool that toggle can synchronize its ON and OFF states with some other component’s field, but what if you have a range of values? In this case, you can use the Slider UI element.

Select GameObject\Create UI\Slider to add a slider. Rename it to sdr_volume and put it inside dlg_settings.

rmouse_ui_111

Select sdr_volume in the hierarchy and set its Anchors to middle-right. Then set its Pivot to (1, 0.5) so that you could position it using the middle point of its right edge.

Finally set its Pos X to -20, Pos Y to -10, Width to 270 and Height to 35.

rmouse_ui_114

This is how the Settings dialog should look right now:

rmouse_ui_115

If you take a look at the hierarchy, you’ll see the slider control has more parts than a toggle or button. Here are the main parts:

  • Background: Image that shows the bounds of the slider and its inner area when it’s not filled (i.e. when handle is all the way to the left).
  • Handle: Image for the handle. You drag it to change the slider’s value.
  • Fill: Image that stretches to show the value of the slider.

In fact, the fill image is not the only part that can stretch, so normally it’s better to use 9-scale images for all three parts. And you have such images! Lucky you! :]

Open the Menu folder in the project browser and find three images corresponding to each part of the slider: slider_background, slider_fill and slider_handle.

rmouse_ui_112

For each image, open the Sprite Editor in the Inspector and set all values for Border to 8. Click Apply.

rmouse_ui_113

Now you need to set the corresponding image for each part of the slider:

  1. Select sdr_volume and drag slider_background to Source Image in the Inspector.
  2. Select Fill (not Fill Area) and drag slider_fill to Source Image.
  3. Select Handle and drag slider_handle to Source image.

If you run the scene now and open the Settings dialog, you should see something like this:

rmouse_ui_116

Changing the Volume of the AudioSource Component

Changing the music volume using the slider is similar to what you did with toggle.

Select sdr_volume in the hierarchy. In the Inspector, scroll down to see On Value Changed (Single) list and click + to add new item.

Drag MainCamera from the hierarchy to that new item in the list, open the function selection dropdown and select AudioSource\volume in the Dynamic float section.

rmouse_ui_117

Run the scene, open the Settings dialog and change the slider’s value. You should hear the volume go up and down as you drag the slider handle. Personally, I find it to be a super-awesome feature. :]

Where To Go From Here?

Just as I promised in the end of Part 1, in this part you’ve added more controls, learned how to animate them and made a fully functioning menu scene. While it’s fairly simple, you’ve explored most of the UI controls.

If you’d like to see it in its final, perfect form, download it here: Rocket Mouse Part Two Final Project

In Part 3, the final part, you’re going to learn advanced techniques, including using the mask component to create a sliding menu. Also, you’ll create more animations and learn how to migrate legacy GUI code to the new UI.

If you have any questions, comments or discoveries to share, please feel free to join the conversation below.

Unity 4.6: New GUI – Part 2 is a post from: Ray Wenderlich

The post Unity 4.6: New GUI – Part 2 appeared first on Ray Wenderlich.

An iOS 8 Surprise Coming Soon!

Video Tutorial: Introduction to Unity Part 9: Scripting (part 2)

Reminder: Free Live Tech Talk (iOS 8 App Extensions) Tomorrow (Tuesday)!

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

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

This is a reminder that we are having a free live tech talk on iOS 8 App Extensions tomorrow (Tuesday Sep 16), and you’re all invited! Here are the details:

  • When: Tuesday, Sep 16 at 2:00 PM EST – 3:00 PM EST
  • What: iOS 8 App Extensions Tech Talk/Demo followed by live Q&A (come w/ questions!)
  • Who: Chris Wagner (iOS 8 by Tutorials author)
  • Where: Google Hangouts Event Page
  • Why: For learning and fun!
  • How: Visit the event page and a video URL should be posted. Follow the instructions there to submit your Q&A (via text) as the talk runs.

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

Reminder: Free Live Tech Talk (iOS 8 App Extensions) Tomorrow (Tuesday)! is a post from: Ray Wenderlich

The post Reminder: Free Live Tech Talk (iOS 8 App Extensions) Tomorrow (Tuesday)! appeared first on Ray Wenderlich.


Unity New GUI Tutorial – Part 3

$
0
0

rmouse_ui_146In this third and final part of this series all about Unity’s New GUI

In Part 1, you created a menu scene, complete with an adaptive background and neatly controlled graphical elements, thanks to expert-level use of anchors, pivot and other cool trick.

Part 2 was all about animating buttons and actions to make your game uber-interactive.

Now you’re going to build on these skills to round out your understanding of Unity’s new GUI, but you’re not going to stop with a fancy new menu. You’ll also migrate the RocketMouse game scene from the old legacy GUI system to the new GUI system.

Getting Started

To start, simply open the Unity project at the point where you left it at the end of Part 2.

If you tinkered with your old project file to a point beyond recognition — or skipped the last part — you can download the final project for Part 2 here: RocketMouse_FinalPartThree. Unpack it and open it in Unity.

Strap yourself in, this tutorial is about to get real.
Assume the Position

Creating a Sliding Menu

In many cases, you want to provide your users easy access to some game options or features, but don’t want to waste space on the screen. This is a job for a sliding menu.

Creating a Sliding Menu

In many cases, you want to provide your users easy access to some game options or features, but don’t want to waste space on the screen. This is a job for a sliding menu.

You’ve seen these before, they’re a control that comprises a small, unassuming button that is always visible and a menu that slides out to reveal options. Your first step is adding that button.

Adding an Open Button

You might already know how to add a button, especially if you worked through the first two parts of this series. If not, you can probably work off these directions.

Select GameObject\UI\Button in the menu. Rename the newly added button to btn_slide and remove the nested Text object, since the button won’t need a label.

Select btn_slide in the hierarchy and open the Menu folder in the project browser. Drag the btn_9slice_normal image to the Source Image field in the Inspector.

Now set the button position and size as follows:

  1. Set Anchors to bottom-left.
  2. Set both Pos X and Pos Y to 80.
  3. Set Width and Height to 64.

rmouse_ui_118

And that’s how simple it is to complete the first step.

Add the Masking Panel

To create this control, you’re going to need two panels. One will define the mask and the other will move within the mask.

Note: If you’re not entirely sure what a mask is, don’t sweat it. Just follow the steps and you’ll see how it works in real-time. You’ll need to have both panels to see it in action.

Select GameObject\UI\Panel to create the first panel that will be the mask. This will add a Panel to the hierarchy. Select it and follow these steps:

  1. Rename it to pnl_mask.
  2. Drag it over the btn_slide to add it as a child object.
  3. Set Anchors to top-center.
  4. Set Pivot to (0.5, 0)
  5. Set both Pos X and Pos Y to 0.
  6. Set Width to 64 and Height to 192.
  7. Add the mask component, by clicking Add Component button and selecting UI\Mask.
  8. Uncheck Show Mask Graphic inside the mask component dialog.

rmouse_ui_119

Note: You don’t always have to add the panel with a mask as a child node of the button. But when you do, you ensure that when the button moves, the masking panel moves with it.

Adding the Content Panel

Add another panel by selecting GameObject\UI\Panel and following these steps:

  1. Rename it to pnl_content
  2. Add it as a child of pnl_mask

    Note: Did you notice that you can see only a small portion of the white panel, although its size didn’t change? After adding it as a child of the panel with a mask, you now only see the portion of pnl_content that is inside the rect of pnl_mask.

  3. Set the Anchors to stretch-stretch.
  4. Set Left, Top, Right and Bottom to 0.
  5. Set Pivot to (0.5, 1)

rmouse_ui_120

Now it’s time to change the background image for the content panel.

Open the Menu folder in the project browser and select the slide_menu_panel_9slice image. Open Sprite Editor in the Inspector and set all Border values to 8. Click Apply!

rmouse_ui_121

After that, select pnl_content in the hierarchy, and then drag slide_menu_panel_9slice from the project browser to Source Image field in the Inspector.

On the following GIF, you can see both how the content panel should look and how the mask component works. Now you see it, now you don’t

rmouse_ui_122

Note: As you can see, a mask works similarly to a window in a wall. If someone is walking along a wall, you can only see him when he passes by a window. Another way to think of it is as a cloaking device that allows only a portion of the image to show through.

Adding Buttons

You’re about to add three buttons to the sliding menu.

To create the first button, select GameObject\UI\Button. Rename it to btn_about and remove the text child.

Drag the btn_about button on pnl_content in the hierarchy to add it as a child. Open the Menu folder in the project browser and drag slide_menu_btn_about to the Source Image in the Inspector. Click Set Native Size.

Set Anchors to top-center and Pivot to (0.5, 1). After that, set both Pos X to 0 and Pos Y to 0.

Now it’s your turn to add two remaining buttons, all by yourself.

Name them btn_achievements and btn_leaderboards and use the slide_menu_btn_achievements and the slide_menu_btn_leaderboards images respectively.

If you need a nudge, feel free to open up the spoiler.

Solution Inside: Adding More Buttons SelectShow>

This is what you see in the end:

rmouse_ui_125

Making the Panel Slide Up and Down

To make the panel slide up and down, you’re going to use the same technique you’ve already employed for buttons and settings dialog.

It will be easy, just follow these steps:

  1. Select pnl_content in the hierarchy and open the Animation view.
  2. Create a new clip using the [Create New Clip] option.

    rmouse_ui_126

  3. Name the animation sliding_menu_down and save it the Animations folder.

    rmouse_ui_127

  4. Click on the 1:00 mark in the timeline. This should also enable recording in the Animation view. Turn it on by pressing the red circle button, and then look for the playback controls to turn red.

    rmouse_ui_128

  5. Set the Top to 192 in the Inspector and stop recording.

    rmouse_ui_129

  6. Open the Animations folder in project browser, select sliding_menu_down and in the Inspector, uncheck Loop Time.

    rmouse_ui_138

  7. Select pnl_content in hierarchy and open the Animator view. Copy and paste the sliding_menu_down state to create a duplicate.

    rmouse_ui_130

  8. Rename the duplicate to sliding_menu_up and set its Speed to -1 in the Inspector.
  9. rmouse_ui_131

  10. In the Animator view, set sliding_menu_up as default by right-clicking on it and selecting Set As Default.
  11. Create two transitions: from sliding_menu_up to sliding_menu_down and from sliding_menu_down to sliding_menu_up.

    rmouse_ui_132

  12. Add a new Bool parameter named isHidden and set its default value to true.

    rmouse_ui_135

  13. Select the transition from sliding_menu_up to sliding_menu_down, and in the list of conditions set isHidden to true.
  14. rmouse_ui_133

  15. Select the transition from sliding_menu_down to sliding_menu_up, and this time set Conditions to be isHidden equals false.

    rmouse_ui_134

  16. And as a finishing touch, select pnl_content in the hierarchy and disable Animator component, just as you did for the settings dialog. This is a requirement, because you don’t want to start the animation right at the start.
  17. rmouse_ui_139

That’s it, 14 easy steps! :]

Adding Code to Toggle the Menu

Open MonoDevelop once again. Although you have to agree that creating UI using the legacy GUI system would require you to spend much more time in MonoDevelop. :]

Regardless, it still has a purpose, so open the UIManagerScript in MonoDevelop and add following instance variable:

public Animator contentPanel;

After that, add the following method:

public void ToggleMenu()
{
    contentPanel.enabled = true;
 
    bool isHidden = contentPanel.GetBool("isHidden");
    contentPanel.SetBool("isHidden", !isHidden);
}

This enables the animator component as soon as you open the sliding menu and sets the correct isHidden parameter value.

One final thing — you need to move the panel down at the start, so add the following Start():

void Start()
{
    RectTransform transform = contentPanel.gameObject.transform as RectTransform;        
    Vector2 position = transform.anchoredPosition;
    position.y -= transform.rect.height;
    transform.anchoredPosition = position;
}

In this Start method, you simply take the height of the content panel and move it down by this value, thus making it completely hidden.

Note: You could move the panel down in Unity and skip writing this code in the Start method. However, doing so makes it more difficult to work with the contents of the panel in Unity, since the mask component would hide it.

Save the script and switch back to Unity. In Unity, select UIManager in the hierarchy and drag pnl_content from the hierarchy to the Content Panel field in the Inspector.

rmouse_ui_136

Now, select btn_slide in the hierarchy. In the Inspector, find a list of On Click (Button) event handlers and add a new one by clicking the + button.

After that, drag UIManager from the hierarchy to that new handler. Then, in the function selection dropdown, select UIManagerScript\ToggleMenu ().

rmouse_ui_137

Run the scene and relish in your cool sliding-up-and-down menu.

Adding a Rotating Gear Icon

There is something missing, don’t you think? Oh, of course! The rotating gears icon on the opening button itself — the one shown in the animated GIF image at the start of this part.

Adding the Gear Image

Your first step is to add an image as a child object of the btn_slide, and animate it during the menu opening and closing animations.

Choose GameObject\UI\Image to create a new image. Drag it over the btn_slide in the hierarchy to add it as a child object.

After that, follow these steps:

  1. Rename the image to img_gear
  2. Set the Anchors to middle-center
  3. Set both Pos X and Pos Y to 0.
  4. Open the Menu folder in project browser and drag the slide_menu_gear image to the Source Image field in the inspector.
  5. Click Set Native Size.

rmouse_ui_140

Animating the Gear Image

By now, the technique of creating two animation states and a parameter to switch between them should be second nature. So, you should be able to create a left-rotating gear and reverse the animation to make a right-rotating gear.

Here are the need-to-know details:

  • Animation duration should be identical to the sliding panel animation, and this is easy since all animations in this tutorial are exactly 1 second long.
  • The gear should rotate 360 degrees around the Z axis (Rotation Z).
  • Use the same name isHidden for parameter name and set its default value to true.
  • Remember to disable looping and the animator component.

Should you find that you need more detailed directions, feel free to open the spoiler below.

Solution Inside: Rotating the Gear SelectShow>

Triggering the Gear Animation from the Code

To complete the sliding menu control, you need to trigger the gear animation from code, but you only need to write a few lines.

Open the UIManagerScript in MonoDevelop and add following instance variable:

public Animator gearImage;

Then scroll down and find ToggleMenu. Add following to the bottom of the method’s body:

public void ToggleMenu()
{
    //..skipped..
 
    gearImage.enabled = true;
    gearImage.SetBool("isHidden", !isHidden);
}

This enables the animator component and sets its isHidden parameter to the same value as the content panel’s animator isHidden parameter.

Save the script file and switch back to Unity.

In Unity, select UIManager in the hierarchy. Drag img_gear to the Gear Image field in the inspector.

rmouse_ui_145

Run the scene and enjoy your fancy rotating gear icon.

rmouse_ui_146

Good job! The sliding menu is complete and your scene is coming together.

You’re not going to handle clicks on the buttons in the menu, because you should be already familiar with handling UI events and actually integrating Game Center would send this tutorial down a rabbit hole.
Instead, you’re going to update the old GUI-based RocketMouse scene so that it uses the new GUI system.

Note: If you haven’t completed the original tutorial, you’ll be fine — though you’ll learn a lot more about this powerful new system by working through it. You won’t be diving deep into the code or need to understand the game mechanics. All you’re going to do is replace the onGUI method with the new GUI system.

Updating RocketMouse Scene to use the New GUI

As mentioned in Part 1, once you’ve made the move to Unity 4.6, you can forget the onGUI method just like a bad dream.

In the RocketMouse game, a few UI elements use this old method to display: scored points and the button to restart the game. You’re going to replace them with new text and image UI elements, and a dialog that allows you to restart the game or exit to the main menu.

Adding the Points Label

Switch to the RocketMouse scene and open the Scenes folder in the project browser. Double-click on the RocketMouse scene to open it.

Choose GameObject\UI\Text to create a new Text UI element. You’re also going to work with Canvas and EventSystem while you’re in here.

rmouse_ui_147

Select Text in the hierarchy and make following changes in the Inspector:

  1. Rename it to txt_points.
  2. Set Anchors to top-left.
  3. Set Pivot to (0, 0.5).
  4. Set Pos X to 50 and Pos Y to -30.
  5. Change Text to 0, since the player starts with zero points.
  6. Open the Fonts folder in the project browser and drag TitanOne-Regular to the Font field in the Inspector.
  7. Set Font Size to 24.
  8. Set Horizontal Overflow to Overflow, to make sure the label can display even the most outrageous scores.

rmouse_ui_148

Also, don’t forget to change the color of the text to be white.

Adding a Points Icon

Nowadays, simply displaying text to show the points is not enough. You need to make sure that it’s perfectly clear what this text means from the moment the player’s eyes see it.

Yes, players these days are spoiled by impressive UI on even the simplest apps, so you need to add an icon to make the score perfectly crisp, clear and well defined.

Select GameObject\UI\Image to create a new Image. Select it in the hierarchy and follow these steps:

  1. Rename it to img_points
  2. Drag it over txt_points to add it as a child, so that when you move the label, the icon moves too.
  3. Set Anchors to middle-left.
  4. Set Pivot to (1, 0.5).
  5. Set both Width and Height to 32.
  6. Set Pos X to -5 and Pos Y to 0.
  7. Open the Sprites folder in the project browser and drag the coin image to Source Image field in the Inspector.

Note: This time you use the image from the Sprites folder and not click Set Native Size, because you’re going to reuse the image used for coins in the game, and it’s a bit bigger than the icon.

Updating Points Label

In the original tutorial, most of the code lives in the MouseController.cs script, so you’ll edit this script to update the points label. In fact, until the end of this tutorial, you’ll only work with this script.

Note: Normally, I’d break this huge script into several smaller chunks, since it’s too big. But, I don’t want you to waste your time on housekeeping, especially because refactoring will take more time and will require a strong understanding of existing code.

It’s better to work with it in a big ol’ block so you can just make the small changes needed and move on with your life.

Open the Scripts folder in the project browser and double-click on the MouseController script to open it in MonoDevelop.

When the script loads, find and remove following methods, which use the old GUI system:

  • onGUI
  • DisplayCoinsCount
  • DisplayRestartButton

Add the following using directive:

using UnityEngine.UI;

After that, add the following instance variable to contain a reference to the label:

public Text coinsLabel;

Finally, add the following line at the end of CollectCoin, which is called every time the mouse collects a coin.

coinsLabel.text = coins.ToString();

Save the script file and switch back to Unity.

In Unity, select mouse in the hierarchy and drag txt_points it to the Coins Label field in the Inspector.

rmouse_ui_149

Run the scene and send the mouse out to collect a few coins. You should see the label update when he collects a coin.

rmouse_ui_150

Everything is looking good, but you might have noticed one rather embarassing problem. When you removed the old onGUI method you also removed the button that displayed when the mouse dies, so the player won’t be able to restart the game when the mouse dies. Doh!

Adding a Restart Dialog

I think you’ve got a good handle on the new GUI system and can create this dialog without a bunch of prodding from me. So create a panel with a label and two buttons that look like this:

rmouse_ui_151

And place it in the center of the canvas.

rmouse_ui_152

Come back when you’re done, you’re on your own, friend!

Gotcha? :] Of course I’m not going to leave you hanging. If you’d like a step-by-step, just open up the spoiler below.

Solution Inside: Solution SelectShow>

Displaying the Restart Dialog

You’re not going to animate the dialog appearance, because you probably know how to do this by now and grow weary of me repeating the directions.

This time, you’ll hide the dialog at the start and show it when the player loses the game.

Open the MouseController script in MonoDevelop and add the following instance variable:

public GameObject restartDialog;

Then add following line of code in Start, to hide the dialog at the start:

restartDialog.SetActive(false);

Scroll down and add following line to the end of HitByLaser:

restartDialog.SetActive(true);

As you probably guessed, the HitByLaser method is called when the mouse dies. Hence, it’s the perfect place to display a restart dialog.

Add the following two methods to restart and exit the game:

public void RestartGame()
{
    Application.LoadLevel (Application.loadedLevelName);
}
 
public void ExitToMenu()
{
    Application.LoadLevel ("MenuScene");
}

You’ll link them to the corresponding buttons in a moment.

Save the script file and switch back to Unity.

In Unity, select mouse in the hierarchy and drag dlg_restart to the Restart Dialog field in the Inspector.

rmouse_ui_158

Then select btn_restart in the hierarchy and scroll down to the On Click (Button) list.

Click + to add new item. After that, drag mouse from the hierarchy to this new item. In the function selection dropdown, select MouseController\RestartGame ().

rmouse_ui_159

Now, select btn_exit, and repeat the process, but this time select MouseController\ExitToMenu () function.

Run the scene and send your mouse into the laser’s line of fire. You should see a dialog appear instantly after he dies. If you press Restart, you’ll restart the game. If you press Exit you’ll return to the main menu.

rmouse_ui_160

And once again I’m ending a tutorial on a high note — with an image of the poor, lifeless mouse. Sorry, no kittens today, maybe in the next series. :]

Where To Go From Here?

Congratulations on completing this tutorial! You can download the final project here: RocketMouse_Final

I hope you like the new GUI system and are excited to create some cool user interfaces in your games! Surely, the prospect of minimal coding alone should have you feeling a bit gleeful.

If you create some awesome control using new GUI system, we’d all love to see your handiwork. Go ahead and post a screenshot, video or GIF animation in comments to show the world your awesome new skills — and maybe inspire a fellow dev or few (or make them jealous). :]

If you have any questions or comments, please leave them below. I will be happy to answer!

Good luck!

Unity New GUI Tutorial – Part 3 is a post from: Ray Wenderlich

The post Unity New GUI Tutorial – Part 3 appeared first on Ray Wenderlich.

iOS 8 App Extensions Tech Talk Video

$
0
0

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

Today in our September Tech Talk, Chris Wagner (co-author of iOS 7 and 8 by Tutorials) gave an excellent talk and Q&A on iOS 8 App Extensions.

Here’s the video for anyone who didn’t get a chance to watch!

Helpful Links

Here are some handy links to learn more about app extensions:

Want to Join Us Next Month?

Thanks again to Chris for giving a great talk and Q&A, having the guts to present to a live audience :] And thank you to everyone who attended – we hope you enjoyed it!

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

iOS 8 App Extensions Tech Talk Video is a post from: Ray Wenderlich

The post iOS 8 App Extensions Tech Talk Video appeared first on Ray Wenderlich.

Introducing the iOS 8 Feast!

$
0
0

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

This year marks our 4th annual iOS release celebration: the iOS 8 Feast.

iOS 8 Feast

The iOS 8 Feast runs over the next month, and consists of eight courses:

  • Optional Appetizer: Bonus Tutorial Unlocks
  • Second Course: Swift by Tutorials
  • Third course: iOS 8 by Tutorials
  • Fourth course: Core Data by Tutorials
  • Fifth course: iOS Animation with Swift Video Tutorials
  • Sixth course: iOS 8 Tutorial Month
  • Seventh course: Surprise Announcement!
  • Dessert: iOS 8 Feast Giveaway

During the iOS 8 Feast, we’ll help you get fully up-to-speed with iOS 8 and Swift development, no matter how you prefer to learn. You’ll learn about Adaptive UI, App Extensions, Cloud Kit, Handoff, Scene Kit, and much more.

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

Optional Appetizer: Bonus Tutorial Unlocks

If I had to pick one thing Apple introduced this year that has developers more excited than anything else, I’d pick the elephant in the room: Swift.

elephant-swift

Swift has everyone excited, whether you’re a complete beginner or an experienced developer. We have a lot in store for both during the iOS 8 Feast, but what if you want something right now?

Good news – we have an optional appetizer ready for you!

  • Beginners will get started with iOS Development the easy way, by getting early access part 1 of The iOS Apprentice, 3rd Edition for free – now fully updated for iOS 8 and Swift!
  • Experienced developers will brush up on one of the coolest (and also trickiest) new aspects of Swift: generics, in a free abbreviated chapter from our new book Swift by Tutorials.

In order to help unlock these optional appetizers, just retweet this post. If/when the post reaches 100 retweets, we will immediately send both appetizers to all newsletter subscribers. (Not subscribed? Do so here.)

Just click the button below!


Second Course: Swift by Tutorials

Still hungry? Don’t worry, we’ve got a full course ready for you: Swift by Tutorials!

Swift-PDF-phones-640

Swift by Tutorials is our brand-new book to help you learn everything you need to know about Swift to use it in real-world apps: via hands-on tutorials.

Swift by Tutorials is for developers who already have some programming experience, and want to get quickly up-to-speed with Swift development. If you are a complete beginner to programming, check out The iOS Apprentice instead.

No matter your level of Swift experience, you’ll definitely learn a ton – the book goes all the way from beginner to advanced material like functional programming, Swift and Cocoa, thinking in Swift vs. Objective-C, and more.

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

Swift by Tutorials is written by Colin Eberhardt and Matt Galloway, who bring tons of technical and writing experience, as authors of the iOS by Tutorials series and Essential Objective-C.

We hope you enjoy learning Swift with Colin and Matt!

Third Course: iOS 8 By Tutorials

iOS 8 by Tutorials

Learning Swift is important, but just as important is learning all of the cool new APIs that came out in iOS 8.

For the fourth year in a row, we are releasing a brand new book to help you get up-to-speed: iOS 8 by Tutorials!

Here’s a quick preview of what you’ll find in the book:

  • Adaptive UI: Learn how to make your apps adapt to different screen sizes with Unified Storyboards, Size Classes, Traits and more.
  • App Extensions: Learn how to make extensions of all types, from Today, to Share, to Action, to Photo Editing and more.
  • Cloud Kit: Learn how to store your app’s data between multiple users with the new and powerful Cloud Kit framework.
  • Live Rendering: Learn how to expose and configure your custom controls in Interface Builder.
  • Handoff: Learn how to pass the user’s current work between devices.
  • Scene Kit: Learn the basics of using Scene Kit from an app developer’s perspective.
  • Visual Effect (Blur) View and Vibrant Text: Learn how to easily add blur effects and vibrant text into your apps.
  • And much more…: From UIKit improvements to photo improvements to the Modern WebKit framework, there are many more goodies in store for you!

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

As part of the iOS 8 Feast, we are releasing a new iOS 8 book each week. iOS 8 by Tutorials will be released next Wednesday, Sep 24.

We can’t wait to show you the book, and we look forward to seeing you use these cool new iOS 8 APIs in your own apps!

Fourth course: Core Data by Tutorials

Core Data by Tutorials

Every app needs to store data, and Core Data is the best way to do so on iOS. But learning Core Data is notoriously difficult – especially when you get into more complicated areas like concurrency, unit testing, performance optimization, and more.

We thought we could do a lot to make Core Data easier to learn, taking you from beginning to advanced via hands-on tutorials – so we made Core Data by Tutorials!

The best part is Core Data by Tutorials is fully up-to-date for iOS 8 and Swift – the first one of its kind!

Core Data by Tutorials is written by some of our best authors, who bring years of hard-won experience using Core Data in large-scale apps: Aaron Douglas, Saul Mora, Matthew Morey, and Pietro Rea.

We will be releasing Core Data by Tutorials as the last book in the iOS 8 Feast: on Wednesday, Oct 15. We think you’ll find it well worth the wait! :]

Fifth course: iOS Animation with Swift Video Tutorials

Don’t worry video tutorial subscribers, we haven’t forgotten about you!

In fact, we have something very special in store for you. You get exclusive access to a brand new video tutorial series on iOS Animation – fully up-to-date with iOS 8 and Swift!

This video tutorial series by Marin Todorov teaches you everything you need to know to be an iOS Animation Master. Check out the introduction of the series to see for yourself:

The first part of the series is going to be released today, and more will come each week.

We think you’re going to love this series – it’s chock-full of amazing up-to-date content you won’t find anywhere else (enough to fill an entire book)!

And the best part is this is just the beginning of new Swift video tutorials coming your way – stay tuned!

Sixth Course: iOS 8 Tutorial Month

“That all sounds great,” you may think, “but what I really want is something FREE!”

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

For the next month, we will be releasing a free Swift tutorial every day Monday-Friday!

iOS 8 Tutorial Month

Notice that during the iOS 8 Tutorial Month, we will be releasing a new Swift book every Wednesday! Here’s the release schedule for your convenience:

  • Wednesday 9/17 [Today]: Swift by Tutorials, The iOS Apprentice 3rd Edition, Part 1
  • Wednesday 9/24: iOS 8 by Tutorials
  • Wednesday 10/1: iOS Games by Tutorials Second Edition, The iOS Apprentice 3rd Edition, Part 2
  • Wednesday 10/8: The iOS Apprentice 3rd Edition, Part 3
  • Wednesday 10/15: Core Data by Tutorials, The iOS Apprentice 3rd Edition, Part 4
  • Wednesday 10/22 [End of Feast]: iOS 8 Feast Giveaway Winners Announced

Check back every day for a new free tutorial – or every Wednesday for a new Swift book!

Seventh course: Surprise Announcement!

RW-DevCon_500

Next, we have a very special surprise announcement for you!

We are very happy to announce that by popular demand, we are hosting an official raywenderlich.com conference: RWDevCon!

The conference will run February 6-7, 2015 in downtown Washington DC. We are teaming up with John Wilker from 360Conferences to host the conference, so if you’re a fan of 360iDev, you’ll love RWDevCon!

What makes RWDevCon different from other conferences is that it will be focused on high quality, hands-on tutorials. Rather than just watching talks, you’ll get to participate!

RWDevCon-Tracks

In addition, all of the material at the conference will be coordinated as a team, much like we do for our books, so that you can get the most optimal experience.

For a short time, we are offering an Early Bird Discount of $100 off. Be sure to snag your discount while you still can – tickets are limited.

The team and I can’t wait to meet you in-person! :]

Dessert: iOS 8 Feast Giveaway

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

The other day on Twitter I ran an informal poll to see what everyone’s favorite iOS dev 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!

(Are you a tool developer interested in contributing a prize? Contact me!)

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

iOS 8 Feast Giveaway

Coding Tools

  1. AppCode 3 Personal License ($99 value): An intelligent IDE that helps iOS/OSX developers create outstanding apps with ease and pleasure. Now supports Swift!
  2. Tower Git ($60 value): The most powerful Git client for your Mac.
  3. Spark Inspector ($50 value): Monitor, understand, and experiment with your app structure at a glance with Spark Inspector. You have to see it to believe it!
  4. Base 2 ($30 value): A Mac OS X application for creating, designing, editing, and browsing SQLite 3 database files.
  5. Paw 2 ($20 value): The missing HTTP client for OS X. Easily craft and test HTTP and REST requests!
  6. Dash ($20 value): Instant offline access to documentation sets, and extremely handy snippet manager.

Mockup Tools

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

Design Tools

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

Game Tools

  1. Spine Essential ($75 value): Animate sprites for your games, with runtimes for Sprite Kit, Unity, Cocos2D, and more!
  2. Particle Designer 2.0 Indie License ($75 value): Create amazing particle systems for your games with a visual editor. Now 100% redesigned, and fully Sprite Kit compatible!
  3. Glyph Designer ($40 value): Design beautiful fonts for your iOS games.
  4. Texture Packer ($39 value): The sprite sheet creator that turns chaos into order!
  5. PhysicsEditor ($19 value): Edit your physics shapes with ease!

Productivity Tools

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

iOS Controls

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

Conference Tickets

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

PDF Books and Starter Kits

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

Video Tutorials

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

Print Books

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

Bonus Loot

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

In total, the grand prize winner will receive over $4,800 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 50+ 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 random retweeters!

  • 10 people will win a free raywenderlich.com PDF book or starter kit of their choice, and geeky magnet set and sticker! ($129 value)
  • 10 people will win a copy of AppCooker, a popular iOS app mockup tool that works on your iPad! ($18 value)
  • 10 people will win a copy of Soulver, a handy app where you can play around with numbers more conveniently than a traditional calculator. ($12 value)
  • 7 people will win a copy of Dash, a handy offline documentation viewer and snippet manager. ($20 value)
  • 7 people will win a copy of Paw 2, the missing HTTP client for OS X. ($20 value)
  • 7 people will win a copy of Reflector, an AirPlay receiver that allows you to wirelessly display your iPad or iPhone on your Mac. ($13 value)
  • 3 people will win a set of iOS Controls: Either ShinobiCharts, ShinobiGrids, or ShinobiEssentials. ($395 value)
  • 3 people will win a copy of PaintCode, a vector drawing app that generates Swift code in real time. ($100 value)
  • 3 people will win a copy of Particle Designer 2 and Glyph Designer, two essential tools for iOS 2D game development. ($99 value)
  • 3 people will win a personal license of AppCode, an intelligent IDE that helps iOS/OSX developers create outstanding apps with ease and pleasure – now updated for Swift! ($99 value)
  • 3 people will win a copy of Tower Git, the most powerful Git client for your Mac. ($60 value)
  • 3 people will win a copy of Texture Packer and PhysicsEditor, two essential tools for creating sprite sheets and physics shapes for your iOS games. ($58 value)
  • 3 people will win a copy of Spark Inspector, a tool that helps you monitor, understand, and experiment with your apps’s UI structure at a glance. ($50 value)
  • 3 people will win a copy of xScope, ten tools in one that will help any designer or developer do their job faster and produce more accurate results. ($50 value)
  • 3 people will win a copy of 1Password for Mac, the most popular password manager for the Mac! ($50 value)
  • 3 people will win a copy of Base 2, a Mac OS X application for creating, designing, editing, and browsing SQLite 3 database files. ($30 value)
  • 3 people will win a copy of Pixelmator, an inspiring, easy-to-use, beautifully designed image editor built to help you create stunning new images and edit your existing photos. ($30 value)
  • 3 people will win a copy of iOS Hat, a handy tool that turns Photoshop layers into Objective-C or Swift! ($20 value)
  • 1 person will win a copy of Spine Essential, a tool to help you animate sprites for your games! ($75 value)
  • 1 person will win a copy of Briefs, the essential app design and mockup tool for a professional design workflow. ($199 value)

That’s a lot of winners – over 80 in total – so you have a lot of chances to win. This makes for over $10,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 8 Feast with the #ios8feast 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 #ios8feast hashtag, and they’ll get the epic loot!

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


The random drawing will be in a month, when the iOS 8 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 Swift tutorials right now? Retweet this post – if it reaches 100 tweets, we’ll send out the new tutorials right away!
  • Want to learn about Swift, iOS 8, and Core Data? Check out our new Swift by Tutorials Bundle – the first book was released today, and the remaining this month!
  • Want tons of free tutorials? Come back here every Monday-Friday for the next month for a new tutorial on Swift and iOS 8!
  • Want to meet the team and fellow readers in-person? Sign up for RWDevCon: The Tutorial Conference, before tickets sell out!
  • Want to get mad loot? Send one or more tweets during the next month with the #ios8feast hashtag!

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 8 and Swift tutorials, and if you have any questions or comments about the iOS 8 Feast, please join the forum discussion below!

Introducing the iOS 8 Feast! is a post from: Ray Wenderlich

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

Swift Generics Tutorial

$
0
0
Take a deep dive into Swift Generics!

Take a deep dive into Swift Generics!

Note from Ray: Congratulations, you did it! By helping to spread the word about the iOS 8 Feast, you unlocked the first Swift tutorial in less than 1/2 hour! This is an abbreviated version of a chapter from Swift by Tutorials to give you a sneak peek of what’s inside the book. We hope you enjoy!

If you’ve been playing around with Swift, you already know the basics of Swift and how to write classes and structs. But Swift is more than this—much more. The topic of this tutorial is a very powerful Swift feature already popular in several other languages: generics.

With type-safe languages, it’s a common problem to want to write code that acts on one type, but is also perfectly valid acting on another type. Imagine, for example, a function to add two integers. A function to add two floats would look very similar—in fact, it would look identical. The only difference would be the type of the variables.

In a strongly-typed language, you would need to define separate functions like addInts, addFloats, addDoubles, etc., where each function had the correct argument and return types.

Many languages implement solutions to this problem. C++, for example, uses templates. Swift, like Java and C#, uses generic programming—hence the topic of this tutorial!

Throughout this Swift Generics tutorial, you’ll tour the existing generics in the language, including some you’ve seen already. Then, you’ll build a Flickr photo search app with a custom generic data structure to keep track of the user’s search terms.

Note: This Swift functional programming tutorial assumes you already know the basics of Swift development. If you are new to Swift, we recommend you check out some of our other Swift tutorials first.

Introducing Generics

You might not know it, but you’ve probably already seen generics at work in Swift. Arrays and dictionaries are classic examples of the type safety of generics in action.

Objective-C developers are accustomed to arrays and dictionaries holding objects of many types in the same collection. This provides for great flexibility, but how do you know what an array returned from an API is meant to hold? You can only be sure by looking at documentation or at variable names, another form of documentation. Even with documentation, there is nothing (other than bug-free code!) to prevent something unexpected in the collection at runtime.

Swift, on the other hand, has typed arrays and dictionaries. An array of Ints can only hold Ints and can never (for example) contain a String. This means you can document code by writing code, allowing the compiler to do the type checking for you.

For example, in Objective-C UIKit, the method that handles touches in a custom view is as follows:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;

The set in this method is known to contain only UITouch instances, but only because the documentation says so. Nothing is stopping the objects in there from being anything else, and you generally need to cast the touches in the set as UITouch instances to effectively treat them as UITouch objects.

Swift doesn’t have a set defined in the standard library at this time. However, if you used an array in place of a set, then you could write the above method like this:

func touchesBegan(touches: [UITouch]!, withEvent event: UIEvent!)

This tells you that the touches array only contains UITouch instances, and the compiler will throw an error if the code calling this method tries to pass anything else. Not only does the compiler control types placed into the touches array, but you no longer need to cast elements to instances of UITouch!

Overall, generics provide types as a parameter to the class. All arrays act the same way, storing values in a list, but generic arrays parameterize value type. You might find it helpful to think of it like this: The algorithms you’ll use on arrays are non-type-specific, so all arrays, with all types of values, can share them.

Now that you have a basic sense of generics and their utility, you’re ready to apply them to a concrete scenario.

Generics in Action

To put generics to the test, you’re going to build an app that searches Flickr for images.

Start by downloading the starter project for this tutorial. Open it and quickly familiarize yourself with the main classes. The Flickr class handles talking to the Flickr API. Notice the API key is located with this class—one has been provided, but you may want to use your own in case you want to expand on the app. You can sign up for one here.

Build and run the app. You’ll see this:

001_StarterProject

Not much yet! Never fear, you’ll soon have this thing pulling in pictures of cats! (What else?)

Ordered Dictionaries

Your app is going to download pictures for each user query. It will display them in a list with the most recent search at the top.

But what if your user searches for the same term twice? It would be nice if the app brought the old results back up to the top of the most recent list and replaced it with new results.

You might use an array for the data structure to back this, but for the purpose of learning generics, you’re going to create a new collection: an ordered dictionary.

In many languages and frameworks (including Swift) sets and dictionaries do not guarantee any kind of order, in contrast to arrays. An ordered dictionary is like a normal dictionary, but the keys are in a defined order. You’ll use this functionality to store search results keyed by search term, making it quick to find results and also to maintain the order for the table view.

If you were being hasty, you might create a custom data structure to handle the ordered dictionary. But you are forward thinking! You want to create something that you can use in apps for years to come! This is a perfect use case for generics.

The Initial Data Structure

Add a new file by clicking File\New\File… and selecting iOS\Source\Swift File. Click Next and call the file OrderedDictionary. Finally, click Create.

You will have an empty Swift file. Add the following code to it:

struct OrderedDictionary {  
}

So far this should be no surprise. The object is going to be a struct because it should have value semantics.

Note: In short, value semantics is a fancy way of saying “copy/paste behavior”, rather than “shared reference behavior”. Value semantics brings a number of benefits, such as not having to worry about some other piece of code modifying your data unexpectedly. To learn more, check out Chapter 3 of Swift by Tutorials, “Classes and Structs”.

Now you need to make it generic so it can hold whatever type of values you want. Change the struct definition to the following:

struct OrderedDictionary<KeyType, ValueType>

The elements inside the angled brackets are the type parameters of the generic. KeyType and ValueType are not types themselves, but rather become parameters that you can use in place of types within the struct’s definition. All will become clear shortly.

The simplest way to implement an ordered dictionary is to maintain both an array and a dictionary. The dictionary will hold the mapping, and the array will hold the order of the keys.

Add the following code inside the struct’s definition:

typealias ArrayType = [KeyType]
typealias DictionaryType = [KeyType: ValueType]
 
var array = ArrayType()
var dictionary = DictionaryType()

This declares two properties, as described, and also two type aliases, which are a way to give a new name to an existing type. Here, you give aliases to the array and dictionary types for the backing array and dictionary, respectively. Type aliases are a great way to take a complex type and give it a much shorter name.

Notice how you can use the type parameters KeyType and ValueType from the struct definition in place of types. The array is an array of KeyTypes. Of course, there is no such type as KeyType; instead Swift treats it as whatever type the consumer of OrderedDictionary passes during instantiation of the generic.

At this point, you’ll notice a compiler error:

Type 'Keytype' does not conform to protocol 'Hashable'

This might come as a surprise. Take a look at the implementation of Dictionary:

struct Dictionary<KeyType: Hashable, ValueType>

This is awfully similar to the definition of OrderedDictionary, except for one thing—the “: Hashable” after KeyType. The Hashable after the semicolon declares that the type passed for KeyType must conform to the Hashable protocol. This is because Dictionary needs to be able to hash keys for its implementation.

It’s very common to constrain generic type parameters in this way. For example, you might want to constrain the value type to conform to the Equatable or Printable protocols depending on what your app needs to do with those values.

Open OrderedDictionary.swift and replace your struct definition with the following:

struct OrderedDictionary<KeyType: Hashable, ValueType>

This declares that the KeyType for OrderedDictionary must conform to Hashable. This means that whatever type KeyType becomes, it will be acceptable as a key for the underlying dictionary as well.

The file will now compile again without any errors!

Keys, Values and All That Jazz

What use is a dictionary if you can’t add values to it? Open OrderedDictionary.swift and add the following function inside your struct definition:

// 1
mutating func insert(value: ValueType, forKey key: KeyType, atIndex index: Int) -> ValueType?
{
  var adjustedIndex = index
 
  // 2
  let existingValue = self.dictionary[key]
  if existingValue != nil {
    // 3
    let existingIndex = find(self.array, key)!
 
    // 4
    if existingIndex < index {
      adjustedIndex--
    }
    self.array.removeAtIndex(existingIndex)
  }
 
  // 5
  self.array.insert(key, atIndex:adjustedIndex)
  self.dictionary[key] = value
 
  // 6
  return existingValue
}

This introduces a couple of new things. Let’s take it step by step:

  1. The method to insert a new object, insert(_:forKey:atIndex), needs to take three parameters: the value for a particular key and the index at which to insert the key-value pair. There is a keyword here that you might not have seen before: mutating.


    Structs are designed to be immutable by default, meaning you ordinarily can’t mutate struct member variables in an instance method. Since that is quite limiting, you can add the mutating keyword to tell the compiler that the method is allowed to mutate state in the struct. This helps the compiler make decisions about when to take copies of structs (they are copy-on-write) and also helps document the API.

  2. You pass the key to the indexer of the Dictionary, which returns the existing value if one already exists for that key. This insert method emulates the same behavior as the Dictionary’s updateValue and therefore saves the existing value for the key.
  3. If there is an existing value, then and only then does the method find the index into the array for that key.
  4. If the existing key is before the insertion index, then you need to adjust the insertion index because you’re about to remove the existing key.
  5. You update the array and dictionary, as appropriate.
  6. Finally, you return the existing value. Since there might not be an existing value, the function returns an optional value.

Now that you have the ability to add values to the dictionary, what about removing values?

Add the following function to the OrderedDictionary struct definition:

// 1
mutating func removeAtIndex(index: Int) -> (KeyType, ValueType)
{
  // 2
  precondition(index < self.array.count, "Index out-of-bounds")
 
  // 3
  let key = self.array.removeAtIndex(index)
 
  // 4
  let value = self.dictionary.removeValueForKey(key)!
 
  // 5
  return (key, value)
}

Let’s take it step by step again:

  1. Once more, this is a function that mutates the internal state of the struct, and you therefore mark it as such. The name removeAtIndex matches the method on Array. It’s a good idea to consider mirroring the APIs of the system library when appropriate. It helps make developers using your API feel at home on the platform.
  2. First, you check the index to see if it’s within the bounds of the array. Trying to remove an out-of-bounds element from the underlying array will trigger a runtime error, so the check here will catch that condition a bit earlier. You may have used assertions in Objective-C with the assert function; assert is available in Swift too, but precondition is active in release builds so your shipped apps will terminate if the preconditions fails.
  3. Next, you obtain the key from the array for the given index while at the same time removing the value from the array.
  4. Then, you remove the value for that key from the dictionary, which also returns the value that was present. The dictionary might not contain a value for the given key, so removeValueForKey returns an optional. In this case, you know that the dictionary will contain a value for the given key, because the only method that can add to the dictionary is your own insert(_:forKey:atIndex:), which you wrote. Thus you can immediately unwrap the optional with ! knowing there will be a value there.
  5. Finally, you return the key and value in a tuple. This parallels the behavior of Array removeAtIndex and Dictionary removeValueForKey, which return the existing values.

Accessing Values

You can now write to the dictionary but you can’t read from it—that’s no good for a data structure! You’re now going to add the methods that will allow you to retrieve values from the dictionary.

Open OrderedDictionary.swift and add the following code to the struct definition, just underneath the array and dictionary variable declarations:

var count: Int {
  return self.array.count
}

This is a computed property for the count of the ordered dictionary, a commonly needed piece of information for such a data structure. The count of the array will always match the count of the ordered dictionary, so this is an easy one!

Next, you need a way to access elements of the dictionary. In Swift, you access a dictionary using the subscript syntax, as follows:

let dictionary = [1: "one", 2: "two"]
let one = dictionary[1] // Subscript

You’re familiar with this syntax by now, but have likely only seen it used on arrays and dictionaries. How would you achieve this using your own classes and structs? Swift, fortunately, makes it simple to add subscript behavior to custom classes.

Add the following code to the bottom of the struct definition:

// 1
subscript(key: KeyType) -> ValueType? {
  // 2(a)
  get {
    // 3
    return self.dictionary[key]
  }
  // 2(b)
  set {
    // 4
    if let index = find(self.array, key) {
    } else {
      self.array.append(key)
    }
 
    // 5
    self.dictionary[key] = newValue
  }
}

Here’s what this code does:

  • This is how you add subscript behavior. Instead of func or var, you use the subscript keyword. The parameter, in this case key, defines the object that you expect to appear inside the square brackets.
  • Subscripts can comprise setters and getters, just like computed properties can. Notice that this one has both (a) a get and (b) a set closure, defining the getter and setter, respectively.
  • The getter is simple: It needs to ask the dictionary for the value for the given key. The dictionary’s subscript already returns an optional to allow for indicating that no value exists for that key.
  • The setter is more complex. First, it checks if the key already exists in the ordered dictionary. If it doesn’t exist, then you need to add it to the array. It makes sense are for the new key to go at the end of the array, so you add the value to the array using append.
  • Finally, you add the new value to the dictionary for the given key, passing in the new value via the implicitly named variable newValue.

Now you can index into the ordered dictionary as if it were a normal dictionary. You can get the value for a certain key, but what about accessing by index, as with an array? Seeing as how this is an ordered dictionary, it would be useful to access an element by index too.

Classes and structs can have multiple subscript definitions for different argument types. Add the following function to the bottom of your struct definition:

subscript(index: Int) -> (KeyType, ValueType) {
  // 1
  get {
    // 2
    precondition(index < self.array.count, 
                 "Index out-of-bounds")
 
    // 3
    let key = self.array[index]
 
    // 4
    let value = self.dictionary[key]!
 
    // 5
    return (key, value)
  }
}

This is similar to the subscript you added previously, except that the type of the parameter is now Int, because that is what you use to reference the index of an array. This time, however, the return type is a tuple of key and value, because that is what your OrderedDictionary stores at a given index.

Here’s what this code does:

  1. This subscript only has a getter. You could implement a setter for it as well, first checking that indexes that are within the size range of the ordered dictionary.
  2. The index must be within the bounds of the array, which defines the length of the ordered dictionary. You use a precondition to alert programmers who try to access beyond the bounds of the ordered dictionary.
  3. You find the key by obtaining it from the array.
  4. You find the value by obtaining it from the dictionary for the given key. Notice, again, the use of the unwrapped optional, because you know that the dictionary must contain a value for any key that’s in the array.
  5. Finally, you return a tuple containing the key and value.

Challenge: Implement a setter for this subscript. Add set followed by a closure, just as in your previous subscript definition.

Solution Inside: Hint 1 SelectShow>
Solution Inside: Hint 2 SelectShow>

At this point, you may wonder what happens if KeyType is Int. The benefit of generics is to allow any hashable type as the key, including Int. In that case, how does the subscript know which subscript code to use?

That’s where you would need to give more type information to the compiler to let it know your intentions. Notice that each of the subscripts has a different return type. Therefore, if you tried to set a key-value tuple, the compiler would know that it should use the array-style subscript.

Playground Testing

Let’s start a playground so that you can experiment with how the compile infers which subscript method to use, and how your OrderedDictionary works in general.

Create a new playground by clicking File\New\File…, selecting iOS\Source\Playground and clicking Next. Call it ODPlayground and then click Create.

Copy and paste the entirety of OrderedDictionary.swift into the new playground. You have to do this because, sadly, at the time of writing this tutorial the playground cannot “see” code in your app module.

Note: There is a workaround for this, other than the copy/paste method you’re doing here. If you were to move your app’s code into a a framework, your Playground could access your code, as Corrine Krych points out.

Now add the following to the bottom of your playground:

var dict = OrderedDictionary<Int, String>()
dict.insert("dog", forKey: 1, atIndex: 0)
dict.insert("cat", forKey: 2, atIndex: 1)
println(dict.array.description 
        + " : " 
        + dict.dictionary.description)
 
var byIndex: (Int, String) = dict[0]
println(byIndex)
 
var byKey: String? = dict[2]
println(byKey)

In the sidebar (or via View\Assistant Editor\Show Assistant Editor) you can see the output of the println():

002_Console

In this example, the dictionary has an Int key, so the compiler will look at the type of the variable being assigned to determine which subscript to use. Since byIndex is an (Int, String) tuple, the compiler knows to use the array style index version of the subscript which matches the expected return type.

Try removing the type definition from one of the byIndex or byKey variables. You’ll see a compiler error, indicating that the compiler doesn’t implicitly know which subscript to use.

PRO TIP: For type inference to work, the compiler requires that the type of an expression be unambiguous. When multiple methods exist with the same argument types but different return types, the caller needs to be specific. Adding a method in Swift can be a build-breaking change, so be aware!

Experiment with the ordered dictionary in the playground to get a feel for how it works. Try adding to it, removing from it and changing the key and value types, before returning to the app.

You can now read and write into your ordered dictionary! That takes care of your data structure. Now you can get cracking with the app!

Adding Image Search

It’s time to shift your attention back to the app in hand. Open MasterViewController.swift and add the following variable definition, just below the two @IBOutlets:

var searches = OrderedDictionary<String, [Flickr.Photo]>()

This is going to be the ordered dictionary that holds the searches the user submits to Flickr. As you can see, it maps String, the search term, to an array of Flickr.Photo, or the photos returned from the Flickr API. Notice you give the key and value in angle brackets just as you would for a normal dictionary. These become the type parameters KeyType and ValueType in the implementation.

You may wonder why the type Flickr.Photo has a period in it. It’s because Photo is a class defined inside the Flickr class. This hierarchy is a rather useful feature of Swift, helping to contain namespace while keeping class names short. Inside the Flickr class, you can use Photo alone to refer to the photo class, because the context tells the compiler what it is.

Next, find the table view data source method called tableView(_:numberOfRowsInSection:) and change it to look like this:

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

This method now uses the ordered dictionary to tell the table view how many rows it has.

Next, find the table view data source method tableView(_:cellForRowAtIndexPath:) and change it to look like this:

func tableView(tableView: UITableView, 
               cellForRowAtIndexPath indexPath: NSIndexPath)
              -> UITableViewCell
{
  // 1
  let cell = 
    tableView.dequeueReusableCellWithIdentifier("Cell", 
      forIndexPath: indexPath) as UITableViewCell
 
  // 2
  let (term, photos) = self.searches[indexPath.row]
 
  // 3
  if let textLabel = cell.textLabel {
    textLabel.text = "\(term) (\(photos.count))"
  }
  return cell
}

Here’s what you are doing in this method:

  1. First, you dequeue a cell from the UITableView. You need to cast it directly to a UITableViewCell because dequeueReusableCellWithIdentifier still returns AnyObject (id in Objective-C) and not a UITableViewCell. Perhaps in the future, Apple will rewrite its APIs to take advantage of generics as well!
  2. Then, you obtain the key and value for the given row, using the subscript by index that you wrote.
  3. Finally, you set the cell’s text label appropriately and return the cell.

Now for the meat in the pie. Find the UISearchBarDelegate extension and change the single method in there to look like this:

func searchBarSearchButtonClicked(searchBar: UISearchBar!) {
  // 1
  searchBar.resignFirstResponder()
 
  // 2
  let searchTerm = searchBar.text
  Flickr.search(searchTerm) {
    switch ($0) {
    case .Error:
      // 3
      break
    case .Results(let results):
      // 4
      self.searches.insert(results, 
                           forKey: searchTerm, 
                           atIndex: 0)
 
      // 5
      self.tableView.reloadData()
    }
  }
}

This method is called when the user taps on the search button. Here’s what you are doing in this method:

  1. You resign the search bar as first responder, dismissing the keyboard.
  2. Then, you take the search term as the text in the search bar right now, and use the Flickr class to search for that term. The search method of Flickr takes both a search term and a closure to execute on success or failure of the search. The closure takes one parameter: an enumeration of either Error or Results.
  3. In the case of Error, nothing happens. You could make it show an alert here if you wanted, but let’s keep this simple for now. The code requires a break here to tell Swift’s compiler of your intention that the error case do nothing.
  4. If the search works, search returns the results as the associated value in the SearchResults enum type. You add the results to the top of the ordered dictionary, with the search term as the key. If the search term already exists in the dictionary, this will bring the search term to the top of the list and update it with the latest results.
  5. Finally, you reload the table view because you now have new data.

Woo! Your app will now search for images!

Build and run the app, and make a couple of searches. You’ll see something like this:

003_Search

Now repeat one of the searches that’s not at the top of the list. You’ll see it pop back to the top:

004_Search2

Tap into one of the searches and notice it doesn’t show the photos. It’s time to fix that!

Show Me the Photos!

Open MasterViewController.swift and find prepareForSegue. Change it to look like this:

override func prepareForSegue(segue: UIStoryboardSegue, 
                              sender: AnyObject?)
{
  if segue.identifier == "showDetail" {
    if let indexPath = self.tableView.indexPathForSelectedRow()
    {
      let (_, photos) = self.searches[indexPath.row]
      (segue.destinationViewController
         as DetailViewController).photos = photos
    }
  }
}

This uses the same method of accessing the searches ordered dictionary as when creating the cells. It doesn’t use the key (search term), though, so you indicate with the underscore that this part of the tuple doesn’t need to be bound to a local variable.

Build and run the app, make a search and then tap into it. You’ll see something like this:

005_Cats

Hello, cats! Doesn’t this make you want to just purr with pleasure? :]

Where To Go From Here?

Here is the finished sample project from this Swift Generics tutorial.

Congratulations, you have learned a lot about generics! In addition, you have learned about other interesting things like subscripting, structs and mutability, preconditions, and more.

If you want to learn more about Generics, check out the full chapter in Swift by Tutorials, where I take this example a bit further and cover generic functions and protocols as well.

I hope to see you make use of the power of Generics in your future apps to help avoid code duplication and make your code more reusable. If you have any questions or comments in your journey, please join the forum discussion below!

Swift Generics Tutorial is a post from: Ray Wenderlich

The post Swift Generics Tutorial appeared first on Ray Wenderlich.

Video Tutorial: iOS Animations: Introduction

Video Tutorial: iOS Animations Part 1: Getting Started

Swift Functional Programming Tutorial

$
0
0
Learn how to use functional programming in Swift!

Learn how to use functional programming in Swift!

Note from Ray: This is an abbreviated version of a chapter from Swift by Tutorials to give you a sneak peek of what’s inside the book. We hope you enjoy!

When making the transition from Objective-C to Swift, it’s logical to map concepts you know in Objective-C onto Swift. You know how to create classes with Objective-C, and now you know the equivalent in Swift. There are, of course, some completely new features, such as generics and range operators, but these are still little more than refinements of what you already know. (OK, perhaps not so little!)

However, Swift does more than provide a better syntax for your applications. With this new language, you have the opportunity to change the way in which you tackle problems and write code. With Swift, functional programming techniques become a viable and important part of your programming toolkit.

Functional programming can be a theory-heavy topic, so this tutorial will introduce the topic by example. You’ll work through a number of programming examples using what will likely be the more familiar, imperative style, and then try your hand at solving the same problems using functional techniques.

Note: This Swift functional programming tutorial assumes you already know the basics of Swift development. If you are new to Swift, we recommend you check out some of our other Swift tutorials first.

What is Functional Programming?

Briefly put, functional programming is a programming paradigm that emphasizes calculations via mathematical-style functions, immutability and expressiveness, and minimizes the use of variables and state.

Since there’s minimal shared state and each function is like an island in the ocean of your app, it makes things easier to test. Functional programming has also come into popularity because it can make concurrency and parallel processing easier to work with. That’s one more thing in your toolbox to improve performance in these days of multi-core devices.

Its time to put the fun- into functional programming!

Simple Array Filtering

You’ll start with something quite easy: a simple bit of math. Your first task is to create a simple Swift script that finds all the even numbers between 1 and 10 (inclusive). A pretty trivial task, but a great introduction to functional programming!

Filtering the Old Way

Create a new Swift playground file and save it wherever you like. Replace the contents of the newly created file with the following code:

var evens = [Int]()
for i in 1...10 {
  if i % 2 == 0 {
    evens.append(i)
  }
}
println(evens)

This produces the desired result:

[2, 4, 6, 8, 10]

(If you can’t see the console output, remember that you need to show the Assistant Editor via the View/Assistant Editor/Show Assistant Editor menu option.)

This little script is very simple; the key points of the algorithm are as follows:

  1. You create an empty (and mutable) array.
  2. The for loop iterates over the numbers from 1 to 10 (remember “…” is inclusive!).
  3. If the condition (that the number must be even) is met, you add it to the array.

The above code is imperative in nature. The instructions tell the computer how to locate the even numbers by giving it explicit instructions that use basic control structures, in this case if and for-in.

The code works just fine but the important bit—testing whether the number is even—is buried inside the for loop. There’s also some tight coupling, where the desired action of adding the number to the array is inside the condition. If you wanted to print each even number somewhere else in your app, there’s no good way to reuse code without resorting to copy-and-paste.

It’s fun-ctional time. (Sorry, I’ll stop it with the “fun” puns now!)

Functional Filtering

Add the following to the end of your playground:

func isEven(number: Int) -> Bool {
  return number % 2 == 0
}
evens = Array(1...10).filter(isEven)
println(evens)

You’ll see that the above, functional code creates exactly the same result as the imperative version:

[2, 4, 6, 8, 10]

Let’s look more closely at the functional version. It’s comprised of two parts:

  1. The Array(1...10) section is a simple and convenient way to create an array containing the numbers 1 through 10. The range operator 1...10 creates a Range you pass to the array’s initializer.
  2. The filter statement is where the functional programming magic takes place. This method, exposed by Array, creates and returns a new array that contains only the items for which the given function returns true. In this example, isEven is supplied to filter.

You’re passing in the function isEven as a parameter to filter, but remember functions are just named closures. Try adding the following, more concise version of the code to your playground:

evens = Array(1...10).filter { (number) in number % 2 == 0 }
println(evens)

Again, verify that the results from all three approaches are identical. The above example demonstrates that the compiler infers the type of the parameter number and return types of the closure from its usage context.

If you like your code to be as concise as possible, take it one step further and try the following:

evens = Array(1...10).filter { $0 % 2 == 0 }
println(evens)

The above uses argument shorthand notation, implicit returns, type inference… the works!

Note: The use of shorthand argument notation is a matter or preference. Personally, I think that for simple examples like the one above, shorthand notation is just fine. However, I’d opt for explicit argument names for anything more complicated. Compilers aren’t concerned with variable names, but they can make a world of difference to humans!

The functional version of this code is certainly more concise than the imperative equivalent. This simple example exhibits a few interesting features that are common to all functional languages:

  1. Higher-order functions: These are functions that you pass as arguments to other functions. In this simple example, filter requires that you pass a higher-order function.
  2. First-class functions: You can treat functions just like any other variable; you can assign them to variables and pass them as arguments to other functions.
  3. Closures: These are effectively anonymous functions you create in-place.

You may have noticed that Objective-C also exhibits some of these features through the use of blocks. Swift, however, goes further than Objective-C in promoting functional programming with a mix of more concise syntax and built-in functional abilities such as filter.

The Magic Behind Filter

Swift arrays have a number of functional methods, such as map, join and reduce. What, exactly, goes on behind the scenes in these methods?

It’s time to look behind the magic of filter and add your own implementation.

Within the same playground, add the following function:

func myFilter<T>(source: [T], predicate:(T) -> Bool) -> [T] {
  var result = [T]()
  for i in source {
    if predicate(i) {
      result.append(i)
    }
  }
  return result
}

The above is a generic function that takes as its inputs a source, which is an array of type T, and predicate, a function that takes an instance of T and returns a Bool.

The implementation of myFilter looks a lot like the imperative version you added at the start. The main difference is that you supply the condition being checked as a function rather than hard-code it.

Try out your newly added filter implementation by adding the following code:

evens = myFilter(Array(1...10)) { $0 % 2 == 0 }
println(evens)

Once again, the output is the same!

Challenge: The above filter function is global; why not see if you can make it a method on Array?

Solution Inside: Hint 1 SelectShow>
Solution Inside: Hint 2 SelectShow>

Reducing

The previous example was a simple one, making use of a single functional method. In this section, you’ll build upon the last, showing how you can implement more complex logic using functional techniques.

Create a new Swift playground and get ready for your next assignment!

Manual reduction

Your task in this section is just a little more complicated: Take the even numbers between 1 and 10 and compute their sum. This calls for what is known as a reduce function, which takes a set of inputs and generates a single output.

I’m sure you are more than capable of working this one out yourself, but here it is anyway! Add the following to your playground:

var evens = [Int]()
for i in 1...10 {
  if i % 2 == 0 {
    evens.append(i)
  }
}
 
var evenSum = 0
for i in evens {
  evenSum += i
}
 
println(evenSum)

The Assistant Editor will display the following result:

30

The imperative code above continues in the same vein as the previous example, adding an additional for-in loop.

Let’s see what a functional equivalent looks like!

Functional Reduce

Add the following to your playground:

evenSum = Array(1...10)
    .filter { (number) in number % 2 == 0 }
    .reduce(0) { (total, number) in total + number }
 
println(evenSum)

You’ll see exactly the same result:

30

The previous section covered the array construction and use of filter. The net result of these two operations is an array with five numbers, [2, 4, 6, 8, 10]. The new step in the above code uses reduce.

reduce is a tremendously versatile Array method that executes a function once for each element, accumulating the results.

To understand how reduce works, it helps to look at its signature:

func reduce<U>(initial: U, combine: (U, T) -> U) -> U

The first parameter is the initial value, which is of type U. In your current code, the initial value is 0 and is of type Int (hence U is Int in this case). The second argument is the combine function that is executed once for each element of the array.

combine takes two arguments: the first, of type U, is the result of the previous invocation of combine; the second is the value of the array element that is being combined. The result returned by reduce is the value returned by the last combine invocation.

There’s a lot going on here, so let’s break it down step by step.

In your code, the first reduce iteration results in the following:

Iteration1

The inputs to combine are the initial value, 0, and the first item in the input array, which is 2. combine sums these values, returning 2.
The second iteration is illustrated below:

Iteration2

On the second iteration, the inputs to combine are the result from the previous iteration and the next item from the input array. Combining them results in 2 + 4 = 6.

Continuing this process for all the items in the array gives the following inputs and outputs:

Iteration3

The number highlighted in the bottom-right corner is the overall result.

This is quite a simple example; in practice, you can perform all kinds of interesting and powerful transformations with reduce. Below are a few quick examples.

Add the following to your playground:

let maxNumber = Array(1...10)
            .reduce(0) { (total, number) in max(total, number) }
println(maxNumber)

This code uses reduce to find the maximum number in an array of integers. In this case, the result is rather obvious! Remember that here, total is really just the result of max of the last iteration of reduce.

If you’re struggling to see how this works, why not create a table like the one above where you compute the inputs and output of combine (i.e., the closure) for each iteration?

The examples you’ve seen so far all reduce arrays of integers into single integer values. Of course, reduce has two type parameters, U and T, which can be different and certainly don’t have to be integers. This means you can reduce an array of one type into a completely different type.

Add the following to your playground:

let numbers = Array(1...10)
  	.reduce("numbers: ") {(total, number) in total + "\(number) "}
println(numbers)

This produces the following output:

numbers: 1 2 3 4 5 6 7 8 9 10

This example reduces an array of integers into the string shown above.

With a bit of practice, you’ll find yourself using reduce in all kinds of interesting and creative ways!

Challenge: See if you can use reduce to take an array of digits and convert them into an integer. Given the input array:

let digits = ["3", "1", "4", "1"]

Your reduce method should return an Int with the value 3141.

The Magic Behind Reduce

In the previous section, you developed your own implementation of filter, which was surprisingly simple. You’ll now see that the same is true for reduce.

Add the following to your playground:

extension Array {
  func myReduce<T, U>(seed:U, combiner:(U, T) -> U) -> U {
    var current = seed
    for item in self {
      current = combiner(current, item as T)
    }
    return current
  }
}

The above adds a myReduce method to Array that mimics the built-in reduce function. This method simply iterates over each item in the array, invoking combiner at each step.

To test out the above, replace one of the reduce methods in your current playground with myReduce.

At this point, you might be thinking, “Why would I want to implement filter or reduce myself?” The answer is, “You probably wouldn’t!”

However, you might want to expand your use of the functional paradigm in Swift and implement your own functional methods. It’s encouraging (and important!) to see and understand just how easy it is to implement powerful methods like reduce.

Building an Index

It’s time to tackle a more difficult problem, and that means it’s time to open a new playground. You know want to!

In this section, you’re going to use functional programming techniques to group a list of words into an index based on the first letter of each word.

Within your newly created playground, add the following:

import Foundation
 
let words = ["Cat", "Chicken", "fish", "Dog",
                      "Mouse", "Guinea Pig", "monkey"]

To accomplish this section’s task, you’re going to group these words by their first letters (case insensitive!).

In preparation, add the following to the playground:

typealias Entry = (Character, [String])
 
func buildIndex(words: [String]) -> [Entry] {
  return [Entry]()
}
println(buildIndex(words))

The Entry typealias defines the tuple type for each index entry. Using a typealias in this example makes the code more readable, removing the need to repeatedly specify the tuple type in full. You’re going to add your index-building code in buildIndex.

Building an Index Imperatively

Starting with an imperative approach, update buildIndex as follows:

func buildIndex(words: [String]) -> [Entry] {
  var result = [Entry]()
 
  var letters = [Character]()
  for word in words {
    let firstLetter = Character(word.substringToIndex(
      advance(word.startIndex, 1)).uppercaseString)
 
    if !contains(letters, firstLetter) {
      letters.append(firstLetter)
    }
  }
 
  for letter in letters {
    var wordsForLetter = [String]()
    for word in words {
      let firstLetter = Character(word.substringToIndex(
        advance(word.startIndex, 1)).uppercaseString)
 
      if firstLetter == letter {
        wordsForLetter.append(word)
      }
    }
    result.append((letter, wordsForLetter))
  }
  return result
}

This function has two halves, each with its own for loop. The first half iterates over each of the words to build an array of letters; the second iterates over these letters, finding the words that start with the given letter, to build the return array.

With this implementation in place, you’ll see the desired output:

[(C, [Cat, Chicken]),
 (F, [fish]),
 (D, [Dog]),
 (M, [Mouse, monkey]),
 (G, [Guinea Pig])]

(The above is formatted a little for clarity.)

This imperative implementation has quite a few steps and nested loops that can make it difficult to understand. Let’s see what a functional equivalent looks like.

Building an Index the Functional Way

Create a new playground file and add the same initial structure:

import Foundation
 
let words = ["Cat", "Chicken", "fish", "Dog",
                      "Mouse", "Guinea Pig", "monkey"]
 
typealias Entry = (Character, [String])
 
func buildIndex(words: [String]) -> [Entry] {
  return [Entry]();
}
 
println(buildIndex(words))

At this point, the println statement will output an empty array:

[]

The first step toward building an index is to transform the words into an array that contains only their first letters. Update buildIndex as follows:

func buildIndex(words: [String]) -> [Entry] {
  let letters = words.map {
    (word) -> Character in
    Character(word.substringToIndex(advance(word.startIndex, 1)
      ).uppercaseString)
  }
  println(letters)
 
  return [Entry]()
}

The playground now outputs an array of uppercase letters, each one corresponding to a word in the input array.

[C, C, F, D, M, G, M]

In the previous sections, you encountered filter and reduce. The above code introduces map, another functional method that’s part of the array API.

map creates a new array with the results of calls to the supplied closure for each element in the supplied array. You use map to perform transformations; in this case, map transforms an array of type [String] into an array of type [Character].

The array of letters currently contains duplicates, whereas your desired index has only a single occurrence of each letter. Unfortunately, Swift’s array type doesn’t have a method that performs de-duplication. It’s something you’re going to have to write yourself!

In the previous sections, you saw how easy it is to re-implement reduce and filter. It will come as no surprise that adding a de-duplication method of your own isn’t tricky, either.

Add the following function to your playground before buildIndex:

func distinct<T: Equatable>(source: [T]) -> [T] {
  var unique = [T]()
  for item in source {
    if !contains(unique, item) {
      unique.append(item)
    }
  }
  return unique
}

distinct iterates over all the items in an array, building a new array that contains only the unique items.

Update buildIndex to put distinct to use:

func buildIndex(words: [String]) -> [Entry] {
  let letters = words.map {
    (word) -> Character in
    Character(word.substringToIndex(advance(word.startIndex, 1)
      ).uppercaseString)
  }
  let distinctLetters = distinct(letters)
  println(distinctLetters)
 
  return [Entry]()
}
</pre?
 
Your playground will now output the unique letters:
 
<pre lang="swift">
[C, F, D, M, G]

Now that you have an array of distinct letters, the next task in building your index is to convert each letter into an Entry instance. Does that sound like a transformation? That’ll be another job for map!

Update buildIndex as follows:

func buildIndex(words: [String]) -> [Entry] {
  let letters = words.map {
    (word) -> Character in
    Character(word.substringToIndex(advance(word.startIndex, 1)
      ).uppercaseString)
  }
  let distinctLetters = distinct(letters)
 
  return distinctLetters.map {
    (letter) -> Entry in
    return (letter, [])
  }
}

The second call to map takes the array of characters and outputs an array of Entry instances:

[(C, []), 
 (F, []), 
 (D, []), 
 (M, []), 
 (G, [])]

(Again, the above is formatted for clarity.)

You’re almost done. The final task is to populate each Entry instance with the words that begin with the given letter. Update the function to add a nested filter, as follows:

func buildIndex(words: [String]) -> [Entry] {
  let letters = words.map {
    (word) -> Character in
    Character(word.substringToIndex(advance(word.startIndex, 1)
      ).uppercaseString)
  }
  let distinctLetters = distinct(letters)
 
  return distinctLetters.map {
    (letter) -> Entry in
    return (letter, words.filter {
      (word) -> Bool in
     Character(word.substringToIndex(advance(word.startIndex, 1)
       ).uppercaseString) == letter
    })
  }
}

This provides the desired output:

[(C, [Cat, Chicken]),
 (F, [fish]),
 (D, [Dog]),
 (M, [Mouse, monkey]),
 (G, [Guinea Pig])]

In the second half of the function, there’s now a nested call to filter inside map. That will filter the list of words for each distinct letter, and thus identifies the words starting with the given letter.

The above implementation is already more concise and clear than its imperative equivalent, but there’s still room for improvement: this code extracts and capitalizes a word’s first letter multiple times. It would be good to remove this duplication.

If this were Objective-C code, you would have a few different options at your disposal: You could create a utility method that performs this functionality, or perhaps you could add this method directly to NSString via a class category. However, if you only ever need to perform this task within buildIndex, a utility method lacks semantic clarity and using a class category is overkill.

Fortunately, with Swift, there’s a better way!

Update buildIndex with the following:

func buildIndex(words: [String]) -> [Entry] {
  func firstLetter(str: String) -> Character {
    return Character(str.substringToIndex(
            advance(str.startIndex, 1)).uppercaseString)
  }
 
  let letters = words.map {
    (word) -> Character in
    firstLetter(word)
  }
  let distinctLetters = distinct(letters)
 
  return distinctLetters.map {
    (letter) -> Entry in
    return (letter, words.filter {
      (word) -> Bool in
      firstLetter(word) == letter
    })
  }
}

You’ll see exactly the same output as before.

The above code adds a firstLetter function that is nested within buildIndex and as a result, is entirely local to the outer function. This takes advantage of Swift’s first-class functions that you can treat much like variables, allowing for assignment and scoping.

The new code removes the duplicate logic, but there’s even more you can do to clean up buildIndex.

The first map step that constructs the array of letters takes a closure whose signature is (String) -> Character. You may notice this is exactly the same signature as the firstLetter function you just added, which means you can pass it directly to map.

Making use of this knowledge, you can rewrite the function as follows:

func buildIndex(words: [String]) -> [Entry] {
  func firstLetter(str: String) -> Character {
    return Character(str.substringToIndex(
            advance(str.startIndex, 1)).uppercaseString)
  }
 
  return distinct(words.map(firstLetter))
    .map {
      (letter) -> Entry in
      return (letter, words.filter {
        (word) -> Bool in
        firstLetter(word) == letter
      })
    }
}

The end result is concise, yet highly expressive.
Perhaps you’ve noticed an interesting side effect of the functional techniques you have employed so far. While your imperative solutions have relied on variables (as defined using the var keyword), you’ve defined everything in the functional equivalents as constants (via let).

You should strive for immutability; immutable types are easier to test and aid concurrency. Functional programming and immutable types tend to go hand in hand. As a result, your code will be more concise as well as less error-prone. And it will look cool and impress your friends!

Challenge: Currently, buildIndex returns an unsorted index; the order of the Entry instances depends on the order of the words in the input array. Your challenge is to sort the index into alphabetic order. For the example array of strings, this would give the following output:

[(C, [Cat, Chicken]),
 (D, [Dog]),
 (F, [fish]),
 (G, [Guinea Pig]),
 (M, [Mouse, monkey])]
Solution Inside: Hint SelectShow>

Where To Go From Here?

Here are the finished playgrounds you developed in this Swift functional programming tutorial.

Congratulations, you now have hands-on experience with functional programming in Swift! Not only did you learn how to use functional methods like map and reduce, but you learned how to implement them yourself, and how to think in a functional way.

If you want to learn more about functional programming, check out the full chapter in Swift by Tutorials, where I go a bit further and cover partial application of functions and currying.

I hope to see you experiment with functional programming techniques in your own apps. If you have any questions or comments along the way, please join the forum discussion below!

Swift Functional Programming Tutorial is a post from: Ray Wenderlich

The post Swift Functional Programming Tutorial appeared first on Ray Wenderlich.


Video Tutorial: iOS Animations Part 2: Springs

Operator Overloading in Swift Tutorial

$
0
0
Learn how to overload operators in Swift!

Learn how to overload operators in Swift!

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

As you’ve learned in earlier tutorials in the iOS 8 Feast, Swift offers many powerful modern programming features, such as generics, functional programming, first class enums and structs, and more.

But there’s another new feature of Swift that you should know and love: operator overloading!

This is a fancy way of saying you can make operators like +, -, /, or * to work with any type you’d like! You can even define your own operators if you’re feeling especially creative.

For example, we use operator overloading in our Swift Sprite Kit utility library to add and multiply CGPoints like this:

let pt1 = CGPoint(x: 10, y: 20)
let pt2 = CGPoint(x: -5, y: 0)
let pt3 = pt1 + pt2
let pt4 = pt3 * 100

Handy, eh? Get ready to overload your Swift development powers – to over 9,000!

Note: This Swift functional programming tutorial assumes you already know the basics of Swift development. If you are new to Swift, we recommend you check out some of our other Swift tutorials first.

Operators: An Overview

Note: This section is optional if you would like a review of operators and precedence. If you are already familiar with this, just create an empty playground and proceed to the next section: Overloading.

Begin by creating a new playground to help you explore operators.

Add the following line to your playground:

var simpleSum = 1 + 3

You’ll see the expected result:

4

There are two familiar operators in play here:

  1. First, you define a variable named simpleSum and set its value with the assignment operator (=).
  2. Second, you sum the two integers using the addition operator (+).

You’ll be overriding operators like these in this tutorial. But first, you need to understand the concept of precedence.

Precedence

You may remember from math class in school that rules of precedence apply to operators. These rules give some operators higher priority than others; higher-priority operators are applied first. For instance, you multiply before adding or subtracting.

Enter the following in your playground to confirm Swift operators follow these same rules:

var sumWithMultiplication = 1 + 3 - 3 * 2

You’ll see the following result:

-2

In cases where arithmetic operators have the same precedence, Swift evaluates the operators from left to right. In this example, this means operations are completed in the following order:

  1. 3 * 2: subtraction.
  2. 1 + 3: Because the leftmost operator is applied first for operations with equal precedence.
  3. 4 – 6: This operation is completed upon the results of the prior operations.
Note: If you want to see the full list of precedences rules in Swift, you can find a complete listing of operator precedence here.

Adding Isn’t Just for Ints

Integer arithmetic works as expected. But can you use the + operator for other types as well?

It turns out you can! Try it for yourself by adding this line to your playground:

var sumArray = [1, 2] + [1, 2]

You might expect this to add each element of the same position together. Instead, you’ll see something like this:

[1, 2, 1, 2]

In this case, Swift interprets the + as an append instruction. But what if you did want to add each element by position? This is known as vector addition.

Well, you could add a custom function to do this. Give it a try by adding the following to your playground:

func add(left: [Int], right: [Int]) -> [Int] {
    var sum = [Int]() 
    assert(left.count == right.count, "vector of same length only") 
    for (key, v) in enumerate(left) {
        sum.append(left[key] + right[key]) 
    }
    return sum
}

Here you define a global function that takes two integer arrays as input, checks that they have the same length, sums the values of each vector element and stores the resulting values in a new array.

Now add the following to confirm that your new function works:

var arr1 = [1, 1]
var arr2 = [1, 1]
var arr3 = add(arr1, arr2)

You’ll see the following in the console:

[2, 2]

It works! But rather than having to call a function do this, wouldn’t it be nice to use the + operator instead?

With Swift, this is possible—with the power of operator overloading!

Operator Overloading

Operator overloading allows you to change the way existing operators work with specific structures or classes. This is exactly what you need – you’d like to change the way the + operator works with Int arrays!

Because operator overloading is global to the playground scope, start with a new playground sheet to avoid impacting your earlier examples. Then add the following to your playground:

func +(left: [Int], right: [Int]) -> [Int] { // 1
    var sum = [Int]() // 2
    assert(left.count == right.count, "vector of same length only")  // 3
    for (key, v) in enumerate(left) {
      sum.append(left[key] + right[key]) // 4
    }
    return sum
}

You’ve just defined a global function called + that takes two Int arrays as input and returns a single Int array. Here’s a breakdown of how it works:

  1. Note there’s nothing fancy about this function definition. It’s a normal function definition except you use + for the name!
  2. Here you create an empty Int array.
  3. This sample will only work with input arrays of the same length, and this assert enforces that.
  4. You then enumerate through the left array, and sum each value with the corresponding value in the right array at the same position.

Test this function by adding the following to your playground:

var sumArray1 = [1, 2, 3] + [1, 2, 3]

Finally—the expected results of your vector addition operator! You will see the following in the console:

[2, 4, 6]

Of course, operator overloading isn’t all fun and games. It would be fairly confusing to someone jumping into your code if they were expecting the default behavior. For that matter, there’s nothing to stop you from overriding the + operator to, for example, perform subtraction on integers—the risks are obvious!

OperatorRage

Remember the operator overloading mantra: with great power comes great responsibility.

Typically, you’ll use overloading to extend an operation to a new object while maintaining the original semantics, rather than defining different (and confusing) behavior.

In this example, the behavior override does maintain semantics; vector addition is still a form of addition. But you may still want the ability to append arrays, and you want to avoid confusing yourself months down the road when you’ve forgotten you overrode the default behavior for Int arrays.

Fortunately, Swift lets you create your own custom operators.

Defining Custom Operators

There are three steps to define a custom operator:

  1. Name your operator
  2. Choose a type
  3. Assign precedence and associativity

Let’s go over these one by one.

Naming Your Operator

Now, you have to pick a character for your operator. Custom operators can begin with one of the ASCII characters /, =, -, +, !, *, %, <, >, &, |, ^, or ~, or with one of the Unicode characters. This gives you a broad range of possible characters. Don’t go crazy, though—remember that you’ll have to type these characters repeatedly and the fewer keystrokes, the better.

In this case, you’ll copy and paste the Unicode symbol , a representation of direct sum that fits your purposes nicely.

Choosing a Type

With Swift, you can define binary, unary and ternary operators. These indicate the number of targets involved.

  • Unary operators involve a single target and are defined either as postfix (i++) or prefix (++i), depending on where they appear in relation to the target.
  • Binary operators are infix because they appear in between the two targets, for example 1 + 1.
  • Ternary operators operate on three targets. In Swift, the conditional operator is the only Ternary operator, for example a ? b : c.

You should choose between these based on the number of targets of your operation. You want to add two arrays (i.e. 2 targets), so you will define a binary operator.

Assigning Precedence and Associativity

Because operators are defined globally, you need to choose the associativity and precedence of your custom operator with care.

This can be tricky, so a good rule of thumb is to find a comparable standard operator defined in the Swift language reference and use similar semantics. For example, to define vector addition, it makes sense to use the same associativity and precedence as the + operator.

Coding Your Custom Operator

Back in your playground, enter the following to define your custom operator. You’ll probably want to copy and paste the ⊕ for simplicity.

infix operator ⊕ { associativity left precedence 140 } // 1
func(left: [Int], right: [Int]) -> [Int] { // 2
    var sum = [Int](count: left.count, repeatedValue: 0)
    assert(left.count == right.count, "vector of same length only")
    for (key, v) in enumerate(left) {
        sum[key] = left[key] + right[key]
    }
    return sum
}

This code is similar to your earlier override, aside from section 1, where you do all of the following:

  • Define an infix/binary operator that operates on two targets and is placed in between those targets.
  • Name the operator ⊕.
  • Set associativity to left, indicating that operands of equal precedence will use left associativity to determine order of operation.
  • Set the precedence to 140, which is the same weight as Int addition, as found in the Swift language reference.

The code in section 2 is similar to what you’ve seen so far – it adds the two arrays item by item, based on their order in the arrays. Test the new operator by adding the following to your playground:

var sumArray = [1, 2, 3][1, 2, 3]

You’ll see the same results as the earlier function and override, but this time, you have different operators for different semantics.

Bonus Round!

Now that you have a good idea of how to create a custom operator, it’s time to challenge yourself. You’ve already created a ⊕ operator to perform vector addition, so use that knowledge to create a ⊖ operator for subtracting Int arrays in a similar manner. Give it your best shot, and check your solution against the answer below.

Solution Inside: Solution SelectShow>

Remember Related Operators!

If you define a new operator, don’t forget to define any related operators.

For example, the addition assignment operator (+=) combines addition and assignment into a single operation. Because your new operator is semantically the same as addition, it’s a good idea to define the assignment operator for it, as well.

Add the following to Operator2.playground:

infix operator  ⊕= { associativity left precedence 140 } // 1
func=(inout left: [Int], right: [Int]) { // 2
    left = left ⊕ right
}

Line 1 is exactly the same declaration as for the ⊕ operator, except it uses the compound operator symbol.

The trick is on line 2, where you mark the compound assignment operator’s left input parameter as inout, which means the parameter’s value will be modified directly from within the operator function. As a result, the operator doesn’t return a value—it simply modifies the input.

Test that this operator works as expected by adding the following to your playground:

sumArray ⊕= [1, 1, 1]

You’ll see the following in the console:

[3, 5, 7]

As you can see, defining your own operators is not difficult at all! :]

Defining Operators for More Than One Type

Now imagine that you want to define vector addition for decimal points, too.

One way is to overload a new operator for the types Double and Float, just like you did for Int.

It’s just a couple of lines of code, but you’ll have to use copy/paste. If you’re like me—a clean code addict—then duplicating code is not your first choice, as it makes your code harder to maintain.

Generics to the Rescue!

Luckily, Swift generics can help with exactly this! If you need a refresher on Swift generics, check out our Swift Generics Tutorial released earlier this week.

Start a new playground so you have a clean slate. Add the following to your new playground:

infix operator ⊕ { associativity left precedence 140 }
func ⊕<T>(left: [T], right: [T]) -> [T] { // 1
    var minus = [T]()
    assert(left.count == right.count, "vector of same length only")
    for (key, v) in enumerate(left) {
        minus.append(left[key] + right[key]) // 2
    }
    return minus
}

On line 1, you define a generic function called ⊕ that works with a placeholder type signified by T. The playground isn’t happy. You’ll see a compile error that looks like this: Could not find an overload for '+' that accepts the supplied arguments.

The error comes from line 2, where you’re attempting to use the + operator on the values left and right, which are the placeholder type. Swift doesn’t know how to apply a + operand to those variables, because it has no idea what type they are!

Extending With a Protocol

Erase your old code and replace it with the following:

protocol Number {  // 1
    func +(l: Self, r: Self) -> Self // 2
}
 
extension Double : Number {} // 3
extension Float  : Number {}
extension Int    : Number {}
 
infix operator ⊕ { associativity left precedence 140 }
func ⊕<T: Number>(left: [T], right: [T]) -> [T] { // 4
    var minus = [T]()
    assert(left.count == right.count, "vector of same length only")
    for (key, v) in enumerate(left) {
        minus.append(left[key] + right[key])
    }
    return minus
}

You’re doing quite a lot here, so let’s take a step back and break it down.

  1. You define a protocol called Number.
  2. The Number protocol defines an operator called +.
  3. You create an extension for Double, Float and Int data types that causes them to adopt the Number protocol.
  4. You use a type constraint that requires T to conform to the Number protocol.

Ultimately, you’re telling the compiler that the generic type T understands the + operand. Now that you’ve cleared the compile error, try out the operand with arrays of Doubles and, separately, with Ints by adding the following code:

var doubleArray = [2.4, 3.6][1.6, 2.4]
var intArray = [2, 4][1, 2]

You’ll see the following in your console:

[4.0, 6.0]
[3, 6]

The operand now works with multiple data types and involves no duplication of code. If you wanted to add more numeric types, you could simply add a markup extension conforming to Number.

How Can I Use Overloading in Real Life?

Do you think I’d let you spend your time on this tutorial if I wasn’t convinced of its usefulness? :] This section will employ a practical example to give you a better idea of how to use overloading in your own projects.

Operators and CGPoints

For this demo, you’ll use the SKTUtils library, a collection of handy Sprite Kit helper classes, written for the second edition of our iOS Games by Tutorials book.

You can find the repo of the framework on github. Clone the Swift branch of the repo by typing the following into a Terminal window:

git clone https://github.com/raywenderlich/SKTUtils.git --branch swift

Alternatively, you can download the ZIP of the Swift branch from github.

Note: Since Xcode 6 beta 5, it’s possible to import your own library within a playground sheet. All you need to do is have the framework and playground bundled together in a workspace. If you’d like to know more about this, read my post Playground has never been so fun.

Open SKUTils/Examples/Playground/SKUTils.xcodeworkspace and build the project (you must build the project at least once for the associated framework to be compiled).

Then navigate to MyPlayground.playground from the project navigator. Delete what is currently in the playground and add the following code:

import SKTUtils 
 
let pt1 = CGPoint(x: 10, y: 20)
let pt2 = CGPoint(x: -5, y: 0)
let pt3 = pt1 + pt2 
let pt4 = pt3 * 100

You might be surprised to see that you’re successfully using the + and * operators on a CGPoint without a word of complaint from the compiler.

{x 10 y 20}
{x -5 y 0}
{x 5 y 20}
{x 500 y 2,000}

The magic here is coming from SKTUtils, which you’ve imported up top. Let’s take a closer look.

Overloading in SKTUtils

Navigate to SKTUtils/CGPoint+Extension.swift in the project navigator. You’ll see that this class defines an extension on CGPoint that, among other things, overloads the + operator as well as the corresponding compound assignment (+=) operator.

public func + (left: CGPoint, right: CGPoint) -> CGPoint {
  return CGPoint(x: left.x + right.x, y: left.y + right.y)
}
 
public func += (inout left: CGPoint, right: CGPoint) {
  left = left + right
}

The code is similar to what you did earlier, but notice the access control set to public. Access control restricts access to parts of your code from code in other source files and modules. As SKTUtils is a framework, its utilities need to be accessible from outside its module and it is thus defined as public.

The prestidigitation explained, there is no magic, after all—just smart coding!

Adding, subtracting, and multiplying CGPoints is a very common operation in games, so overloading operators to work on CGPoints greatly simplified the code in the book, making it much more concise and easier to read. I’m sure you can find similar examples in your own projects!

Operator overloading is a powerful feature of Swift that can make development much more efficient, if you do it with care.

Where to Go From Here?

You’ve reached the end of this tutorial—I hope you enjoyed it! You can find copies of the final playground files here and here.

If you’d like to learn more about operator overloading and Swift in general, check out our new book Swift by Tutorials.

I hope you find a way to use operator overloading in your own projects! But remember, with great power comes great responsibility – don’t be Troll Dev! ;]

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

Operator Overloading in Swift Tutorial is a post from: Ray Wenderlich

The post Operator Overloading in Swift Tutorial appeared first on Ray Wenderlich.

Navigating a New Codebase: Tips and tricks for getting up to speed quickly

$
0
0
Learn how to navigate a new codebase effectively.

Learn how to navigate a new codebase effectively.

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

Learning a new codebase can be a daunting task. There are typically many, many parts in any codebase and it can feel overwhelming to understand how everything fits together. After reading this tutorial you’ll be navigating a new codebase effectively.

This tutorial shows you how to expedite the process by offering a selection of techniques that help you associate what you see on the screen with what’s happening in the code. These tricks all have the same goal but work in different ways; you’ll learn how to choose the right tool for the job.

Since this tutorial works with a real-world codebase for an app currently in the App Store, it includes no Swift files. You can take a break from the onslaught of Swift articles out there and work with some Objective-C for a little while.

Note: Exploring code largely relies on debugging. You should have at mimimum a basic knowledge of how to debug your application and use the lldb console. If you need to get up to speed on this, check out Intermediate Debugging With Xcode 4.5 or the debugging video series.

Getting Started

In this tutorial you’ll take on the role of a new hire at Wikipedia, who has a few tickets to address, which are challenges to fix bugs or implement feature requests.

You’ll working with the iOS Wikipedia App, which is an open source repo. This tutorial uses a forked copy which can be found here.

Don’t download a zipped version of the repo; instead, clone it using using your favorite git application or Terminal. If you aren’t familiar how to clone a repo, enter the commands below in Terminal, one at a time:

$ mkdir WikipediaApp 
$ cd WikipediApp
$ git clone git@github.com:DerekSelander/apps-ios-wikipedia.git
$ cd apps-ios-wikipedia
$ open Wikipedia.xcodeproj

Make sure you’re on the master branch — this should be selected by default. To do this, first run the following command:

$ git branch

Check in the output that the asterisk is next to master. It should look like this:

* master

If it is not, then run the following command:

$ git checkout master

Re-check that you’re on the master branch after running this if you wish!

Note: As of this writing, 4.0.1 is the latest Wikipedia App version in the App Store. By the time you read, the version of the Wikipedia app might have changed. The version of the forked repo you’re using in this tutorial, however, will stay frozen at 4.0.1 and won’t contain any future updates from the app’s developers.

Your first task when learning a new codebase has little to do with the code itself — instead, you should learn how the app is structured and how it functions.

Exploring the App

Open the app in Xcode and run it up in a simulator. Without looking at the code, work your way through the app and discover how to navigate to each of the screens shown below:

ScreensList

You’re really just trying to get a feel for how the app functions and how a user would experience the app. While you’re navigating around the app, ask yourself the following questions:

  • How many distinct screens are in the app?
  • If you had to name the screens, what would you name them?
  • How complex are the screens; that is, how many different kinds of UI controls does the app use?
  • Which screen uses the greatest variety of controls?
  • What is the navigational flow that connects one screen to another?
  • Which UI controls and navigation mechanisms are standard to iOS, and which ones appear to be custom or unfamiliar?

The point of these questions is not to answer them all at once. Asking these questions helps you notice far more about the app than if you just absentmindedly swiped through the screens. Exercises like this help you quickly build a mental model of the app based on its visible features such as interface components and UI behaviors.

To complete your mental model, you’ll need to link the visible features of the app to the invisible features of this app — that is, the codebase itself — by investigating the app’s classes, images, and other code-level resources.

Since a real production app like Wikipedia can easily involve hundreds of files, it’s essential to master the Xcode features that let you navigate quickly through the codebase. Otherwise, it’s like trying to learn your way around a new city by crawling around on your hands and knees, examining the streets with a magnifying glass! :]

Navigating around Xcode

Here’s a quick refresher on Xcode’s navigation features:

  • To jump to the location of a method or property definition: ⌘+Click the item with the mouse, or place the cursor somewhere inside the method name and press Ctrl+⌘+J using the keyboard alone.
  • To jump back to where you were, press Ctrl+2 to show the previous history list and choose the first item in the list. An even shorter key combo is Ctrl+⌘+left or a three finger swipe, provided you haven’t already dedicated those shortcuts to Mission Control. This is configurable via System Preferences / Keyboard.
  • Want to find the corresponding Nib/Storyboard file for the current UIViewController? Press Ctrl+1, type User Interface and press Return and then Return again. This is a killer shortcut if you need to know whether the view controller was implemented directly in the code or via Interface Builder. In addition, if you hold option while opening the file, then it opens in the assistant editor.control+1
  • To jump to a particular filename method, press ⌘+Shift+O and type the name of the item you’re looking for.cmd+shift+o
  • To get a bird’s-eye view of all the methods in a file, press Ctrl+6 to bring up a list of all the methods (as shown in the image below), then begin typing to narrow the selection.control+6
  • To jump to a specific line number, press ⌘+L and the line number.cmd+l

For more tips and tricks with Xcode, check out the Supercharging Your Xcode Efficiency tutorial.

It’s time to get down and dirty with the codebase — the most logical place to start is with the various screens of the app and their associated UIViewControllers.

Seeing how Views are Assembled

When view controllers are sensibly named, you can pretty much guess where they appear in the UI and how they’re created. View controllers can be created from NIBs, from Storyboards, or entirely from code. A primitive yet effective way to find the view controllers is to search the codebase for these assets and inspect the results.

Ensure you’re in the Project Navigator tab; if not, press, ⌘+1 to get there quickly. In the lower left corner of the Project Navigator panel, type .xib into the search field and a handful of NIBs will show up. Take a look at each one in Interface Builder; these NIBs seem like they’re designed for UIViews or UITableViewCells, not UIViewControllers.
thesearenttheviews

Perhaps the views you’re looking for live in Storyboards instead. Enter .storyboard in the search bar. Only one item shows up: Main_iPhone.storyboard. Open that file — is there anything of value inside?

Jackpot! This Storyboard houses the majority of the UIViewControllers in this app. Revisit this file if you need to associate a given view controller in the UI with it’s class.

Finally, go to the find navigator (⌘+3) and search for ViewController. Since this codebase has a regular naming convention, the search results highlight code with numerous view controller subclasses. These results don’t provide the valuable instant navigation overview of a Storyboard file, but they might help you never-the-less.

Mapping the Code With Symbolic Breakpoints

Now that you have a basic understanding of the view controllers used in this app, your next step is to see which view controllers pop up when the app runs.

Open up the Debug Navigator — ⌘+7 is a handy shortcut. Click on the + at the bottom left of the screen and then select Add Symbolic Breakpoint…. Type in viewDidLoad; this places a breakpoint in every object that holds a viewDidLoad method.

The image below shows you how to set up this breakpoint.

SymbolicBreakpoint

This breakpoint will help you map which view controllers run when you exercise the app. Every time a view controller loads its view, the app will pause execution and you’ll be able to see the view controller’s name in the main thread stack in the Debug Navigator.

If the view is defined in the code itself, you’ll see the code itself in the editor pane; when it’s Apple’s own framework code, as happens in every call to the UIViewController superclass, you’ll only see an assembly listing.

Launch the app again with the symbolic breakpoint enabled. Although your progress through the app will be a lot slower, this is a good way to get a list of view controllers used when the app starts. If you get tired of hunting for the button to continue debug execution, use Ctrl+⌘+Y to speed things along.

What view controllers pop up when you run the app? Check your results against the list below.

Solution Inside: Solution SelectShow>
Note: The Facebook Chisel library provides a much faster way to build these lists via the pvc lldb command. Check out Using LLDB in iOS Part 8: Using Chisel to learn how to use Chisel.

Now that you’ve gained a bit of knowledge about the app, you can tackle your first ticket!

Ticket #1

Bug: The navbar displays content underneath the status bar when saving content.

  1. Navigate to a wiki page. Press the edit button in any section.
  2. Change some content in the textview then press the Next button.
  3. Content appears underneath the status bar like so:

navbarbug
QA Helper note: this problem is due to the prefersStatusBarHidden property of UIViewController. Because it is currently set to YES, the view controller is positioning the controls incorrectly. Override this method to NO in the appropriate view controller.

For this particular case, you know from the detailed ticket exactly what to do; you just don’t know where to do it. You could, of course, find the view controller’s name by examining the Storyboard, but that would take too long. Instead, you should let the debugger notify you when the appropriate UIViewController loads — that’s your clue that this is probably the view controller you need to modify.

Follow the reproduction steps in the ticket; run up the Simulator and edit a page, but stop just before you press the Next button. Make sure the viewDidLoad breakpoints are enabled. If you don’t want to slog through all of the breakpoints, you can use ⌘+Y to toggle all breakpoints on and off.

Click the Next button in the Simulator, and wait for the debugger to hit the breakpoint. You’ve stopped on a view controller, but is it the right one?

Press Ctrl+6 to bring up the function list, type in prefersStatusBarHidden then press Enter. You’ve stopped at the CaptchaViewController, but this view controller’s prefersStatusbarHidden already returns NO — you’re not there yet.

Continue execution to the next breakpoint. Once you reach PreviewAndSaveViewController, check prefersStatusbarHidden. Does it return YES? Yup, it does — you’ve found the culprit.

To fix the issue, replace the prefersStatusBarHidden method with the following code:

- (BOOL)prefersStatusBarHidden
{
    return NO;
}

Build and run your app; test your changes to make sure that your changes worked as expected. Go through the same steps that you went through when reproducing the bug. You should now see something like this on the final screen:

iOS Simulator Screen Shot 19 Sep 2014 09.41.07

Note: In no way do the patterns, design, or code of the Wikipedia app reflect upon the best practices taught on this site. It does, however, present an incredibly interesting example that is both successful and live in the App Store.

Symbolic breakpoints can really shine when you are trying to find a known method of an unknown class. Good knowledge of the iOS SDK and delegate methods can help you quickly hunt down an item of interest in a new codebase.

In addition, symbolic breakpoints can be surprisingly helpful when debugging properties. For instance, a property called isHidden has both a getter and a setter. You can instruct the debugger to stop only when the property is set by using setIsHidden:. This is ideal for classes whose instances interact with many different classes — such as singletons — and that have public properties which are being modified.

You’ve learned how to find the code behind a view using symbolic breakpoints. Next, you’ll learn how to do the same thing through inspecting the view itself.

Hunting for UIViews and Their Subclasses

Here’s the next ticket in your queue:

Ticket #2

UI Improvement: Change the color of the contents helper background from black to blue.

Make sure to use the predefined UIColor helper macro WMF_COLOR_BLUE (defined in WMF_Colors.h) when setting this particular color. In addition, change the bottom color from light gray to black.
BackgroundColorFeature

Sometimes symbolic breakpoints don’t really help that much. You don’t know if the color above is set in Interface Builder or through code. Furthermore, if it is being set in code, you can’t really rely on a setBackgroundColor: symbolic breakpoint as this could be set through Core Graphics APIs. Trying to visually pair the code with the correct UIViewController in a storyboard isn’t really a viable option as it would be incredibly tedious given the size of the Wikipedia Storyboard file.

The best approach in this case is to find the name of the class which houses the color you want to change and work back from there. Knowing the name of the class helps you as you search through the .m file, and if it’s not found there, can still help you reduce time spent looking for the appropriate item in Interface Builder.

Both Reveal and View Debugging in Xcode 6 can help you associate what is happening on the Simulator or device with the UIView hierarchy in a visual manner. Although Reveal is a much better product, in this tutorial you’ll take advantage of the free Xcode 6 View Debugging feature.

Run the application in iOS 8 (device or simulator). Disclose the side menu by tapping the upper right navbar button with three uneven horizontal lines. Once it’s visible, go to the Xcode menu bar and choose Debug\View Debugging\Capture View Hierarchy. This suspends the process and displays the view hierarchy head-on. It will look something like this:

View debugging

Click and drag to re-orient the view hierarchy into an exploded view. If you need to, use the provided controls to zoom in and out, pull the views farther apart, and filter the hierarchy to see only the subviews above or below a certain depth.

Exploded view debugging

Provided that UIViews are subclassed, clicking on the views themselves will bring up the corresponding class names. Search through the views, and find the one you want to change — it has a black background color. Once you’ve located the view, press ⌘+Option+3 to ensure you’re using the Object Inspector.

viewdebuggingscreen

  1. The view to search for and click on.
  2. The object inspector tab.
  3. The view’s class name and address of the instance.

The view’s name is TOCSectionCellView, so open TOCSectionCellView.m and see if you can find the logic that sets the background color in this cell and change it to WMF_COLOR_BLUE. You can check your work against the solution below.

Solution Inside: Solution SelectShow>

Build and run your application; follow the reproduction steps in the ticket to see that your changes worked.

Fixed ticket #2

It looks like you can use same View Debugging trick described to hunt down the bottom gray portion that needs to be changes. Or can you?

Try it — you’ll quickly find out that you’re looking at a view that belongs to a UIViewController, and as a result, is nameless since there is no subclass for the UIView itself.

As you can see, hunting down UIViews might not be enough. This is when you’ll want to find the UIViewController associated with the UIView in the view hierarchy.

Debugging View Controllers Using Method Swizzling

Since there is no reference linking the UIView back to the corresponding UIViewController subclass, you can’t look this up directly via the debugger even though you’ve identified the exact UIView instance of interest. What you really need here is for every UIView to have a property that points to its view controller, and for every UIViewController to initialize that property on its view.

Fortunately, this is completely achievable! You can create a new property for an instance of UIView using an Associated Object and inject the initialization logic for that property into one of UIViewController’s instantiation methods using Method Swizzling.

This results in all UIView references having a property that points back to the original UIViewController. Although all UIViews will inherit this property, it will only be initialized for those UIViews that belong to a UIViewController.

Note: Detailed explanations of Associated Objects and Method Swizzling are outside the scope of this tutorial, but if you would like to learn more about them, Matt Thompson (the AFNetworking dude) wrote some excellent articles about Associated Objects and Method Swizzling.

To solve this problem, you’ll implement a UIViewController category to show you the corresponding UIVIewController.

In Xcode, click File\New\File\iOS\Objective C File and then click Next. Name it DebuggingViewInjector. Enter Category for the File Type and UIViewController for Class. Also ensure you check the Wikipedia target when prompted to make sure this category gets compiled into the binary.

Open UIViewController+DebuggingViewInjector.m and replace its contents with the following code:

#import <objc/runtime.h> // 1
#import "UIViewController+DebuggingViewInjector.h"
@implementation UIViewController (DebuggingViewInjector)
 
+ (void)load { // 2
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{ // 3
        Class class = [self class];
 
        SEL originalSelector = @selector(viewDidLoad); // 4
        SEL swizzledSelector = @selector(customInjectionViewDidLoad); // 5
 
        Method originalMethod = class_getInstanceMethod(class, originalSelector); // 6
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
 
        method_exchangeImplementations(originalMethod, swizzledMethod); // 7
    });
}
 
- (void)customInjectionViewDidLoad // 8
{
    self.view.debugVC = self; // 9
    [self customInjectionViewDidLoad]; // 10
}
 
@end

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

  1. Make sure you import the runtime headers used to perform this dark and powerful sorcery.
  2. This is the load class method. This is called when the class is loaded into the runtime. It’s a great place to do swizzling so that the method is swizzled before the class is ever used.
  3. Since the load method can be invoked multiple times due to inheritance, you only want the swizzling to occur once.
  4. The SEL variable is basically the string representation of your method. You will be injecting code into the viewDidLoad method.
  5. With the SEL variables, you will get the method implementations of the original and newly defined method.
  6. Fetch the implementations of the two methods that need to be swapped.
  7. method_exchangeImplementations swaps the original method with the new one.
  8. This is the new method you’re swapping in for the original viewDidLoad method.
  9. Here you set a new UIView property you’ll use shortly.
  10. Sharp-eyed readers will note that this looks like it will result in an infinite loop. But since you swapped the method implementations by the time this method runs, this line of code actually calls the original viewDidLoad.

Your code has been injected into each -[UIViewController viewDidLoad] method, but this code won’t compile right now, because UIView doesn’t have a debugVC property.

Add the following code in front of the code you just added above, before the @implementation UIViewController (DebuggingViewInjector) line:

static char kWeakLinkViewControllerKey; // 1
 
@interface UIView ()
@property (nonatomic, unsafe_unretained) UIViewController *debugVC; // 2
@end
 
@implementation UIView (ViewControllerLinker)
 
- (void)setDebugVC:(UIViewController *)debugVC // 3
{
    objc_setAssociatedObject(self, &kWeakLinkViewControllerKey, debugVC, OBJC_ASSOCIATION_ASSIGN); // 4
}
 
- (UIViewController *)debugVC // 5
{
    return objc_getAssociatedObject(self, &kWeakLinkViewControllerKey); // 6
}
 
@end

Taking each numbered comment in turn:

  1. Each associated object requires a unique identifier. This defines a static variable that can be used as the identifier for our associated object.
  2. This declares the debugVC property. It’s unsafe-unretained because you don’t want to hold a strong reference otherwise there would be a retain cycle (view controller owns view which owns the view controller). You’re actually going to override both the getter and setter, so the semantics described by the property are merely a note to the consumer.
  3. This is the setter for the property.
  4. This code sets the associated object. Notice the OBJC_ASSOCIATION_ASSIGN. This defines the `unsafe_unretained` semantics that we described in the property. Sadly there is no way to do a nilling, weak reference with associated objects.
  5. This is the getter for the property.
  6. Fetch the value of the property from the associated object.

Finally, it would be smart to conditionally compile this code when you’re in DEBUG mode.

Surround the entire file — even the #import headers — with the following:

#if DEBUG
    // Original code
#endif

Now it’s time to give this bad-boy category a whirl. Build and run your app; navigate to the part of the app where you previously performed the View Debugging.

Enable the View Debugging using Debug\View Debugging\Capture View Hierarchy. Once the views generate, find the backing view for the side control that holds the gray color. Keep clicking back further and further to hunt down the root UIView that holds all subviews.

When you click on the correct UIView, you’ll see the memory address holding the UIView instance appear in the Utility Area of Xcode. Copy this address to the clipboard, then open up the Xcode console.

Swizzled ViewController Debugging

Type the following commands in lldb:

po [YOURMEMORYADDRESSHERE debugVC]

The console will spit out the resulting viewcontroller that is responsible for that UIView; in this case, it’s TOCViewController.

Open TOCViewController.m in Xcode. Try to find the logic that references a gray color in TOCViewController.m and change it to black. Check your findings against the solution below.

Solution Inside: Solution SelectShow>

Press Ctrl+1 and select User Interface to bring up the file that holds the visual representation of TOCViewController. Use the Search bar in Interface Builder to find TOCViewController, then hunt down the appropriate UIView with the light gray color and change it to black.

Build & run and then navigate to the sidebar again. You should see something like this:

iOS Simulator Screen Shot 19 Sep 2014 10.32.27

Finding Things When You’re Completely Lost

Sometimes you don’t really know where to begin, such as with your third and final ticket:

Ticket #3

Feature Request: toggle the status bar visibility when the screen hides the menu content.

Make sure the status bar animates with the rest of the navbar when animating in and out.

Ticket 3

Depending on your knowledge of UIScrollView‘s delegate, you might have no clue where to start with this feature. All you know is that when you pan up or down on the web content the navbar and toolbar views resize themselves. In order to figure out what’s happening, the best way is to trigger the event when running the app on the device or the simulator and use some intelligent breakpoints to guide your way.

But how do you trigger a breakpoint when you have no clue where to set it? This is where you break out the Where The Heck Am I Breakpoint! :]

With the Wikipedia app running on the simulator, navigate to the same screen illustrated in the ticket. Navigate to the lldb console, pause the debugger, then type the following at the lldb prompt:

rb . -s Wikipedia

This command sets a breakpoint in every single method and function of your app. If you have any long running code (i.e. OpenGL, or background networking) that recurs constantly, this might not be a good option. It works wonders, however, if you’re just lost and need to get a bearing on your location in the code.

Resume the application by pressing the Play button. Start dragging the web view to simulate the action of hiding/displaying the navbar and toolbar. Be sure to use a drag motion; don’t simply just tap on the view or else you’ll break on the wrong event.

You’ll immediately hit a breakpoint from a UIScrollViewDelegate method in WebViewController. Scan the code for anything that looks of interest; there’s nothing here relevant to your interests so continue execution.

After a few more clicks of play, you’ll come across -[WebViewController scrollViewDidScroll]. This UIScrollView delegate method contains code that looks rather interesting due to the aptly named adjustTopAndBottomMenuVisibilityOnScroll method call. Looks like you’re almost there!

Delete the breakpoints in the lldb using the following commands:

br del
About to delete all breakpoints, do you want to do that?: [Y/n] Y
Note: This breakpoint will stop on every single method — and properties are methods. This means you’ll break on every property as well. You can also try rb . -s Wikipedia -o to generate a one-time breakpoint. Alternatively, you can disable the breakpoints in lldb using: br dis and re-enable them using: br en.

Hunt down the correct method using the Cmd-click approach to jump to methods of interest. Check your path to the correct method in the solution below:

Solution Inside: Solution SelectShow>

Navigate to the method provided in the solution above and hunt down the +[UIView animatWithDuration:delay:options:animation:completion] line. It’s here where the changes to the the navbar and toolbar occur.

Insert a call to setStatusBarHidden:withAnimation: into the top of the animation block, so that the beginning of animateTopAndBottomMenuHidden now looks as follows:

-(void)animateTopAndBottomMenuHidden:(BOOL)hidden
{
    // Don't toggle if hidden state isn't different or if it's already toggling.
    if ((self.topMenuHidden == hidden) || self.isAnimatingTopAndBottomMenuHidden) return;
 
    self.isAnimatingTopAndBottomMenuHidden = YES;
 
    // Queue it up so web view doesn't get blanked out.
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
 
        [UIView animateWithDuration:0.12f delay:0.0f options:UIViewAnimationOptionBeginFromCurrentState animations:^{
 
          // *************
          // ADD THIS LINE
          [[UIApplication sharedApplication] setStatusBarHidden:hidden withAnimation:UIStatusBarAnimationSlide];
          // *************
 
  // Remainder of method....

Build and run your app; slide the web content up and down to see how your fix looks.

Fixed ticket #3

Note: Despite the fact that styleguides abound, developers always have unique coding quirks. They’ll typically stick to a specific implementation pattern when dealing with certain scenarios.

For example, a developer might prefer to not hook up any view controllers via segues in Interface Builder and instead rely on Storyboard IDs instantiated through code. It’s the ability to notice these types of patterns and being able to anticipate — without bias — how other developers handle these situations that makes you a great code navigator.

Where to Go From Here?

You can view the changes you made to the Wikipedia repo by checking out the finished-tickets branch in the repository. Use your preferred git check out method or enter the following commands into Terminal:

git stash
git checkout finished-tickets

You have learned how to get a reference point in your codebase while you navigate using symbolic breakpoints. You have learned how to visually associate both UIViews and UIViewControllers — and all their subclasses — using View Debugging.

In addition, you’re leaving here with a nifty lldb command to help you get your bearings when you’re unsure where to start.

Debugging code plays a huge part in navigating code; this tutorial barely covers the basics. If you want to be a better code debugger, check out the videos or Intermediate Debugging tutorial on this site.

In addition, check out Facebook’s Chisel. Chisel is incredibly useful when navigating a new codebase by associating what views are where when navigating code. You may want to check out this tutorial to learn more about Chisel.

Do you have your own tricks and tips for navigating large codebases? Come share it in the forums below!

Navigating a New Codebase: Tips and tricks for getting up to speed quickly is a post from: Ray Wenderlich

The post Navigating a New Codebase: Tips and tricks for getting up to speed quickly appeared first on Ray Wenderlich.

Video Tutorial: iOS Animations Part 3: Transitions

How To Use UIScrollView to Scroll and Zoom Content in Swift

$
0
0
Learn how to use UIScrollViews for paging, zooming, scrolling, and more!

Learn how to use UIScrollViews for paging, zooming, scrolling, and more!

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

UIScrollView is one of the most versatile and useful controls in iOS. It is the basis for the very popular UITableView and is a great way to present content larger than a single screen. In this UIScrollView tutorial you’ll learn all about using this control:

  • How to use a UIScrollView to view a very large image.
  • How to keep the UIScrollView’s content centered while zooming.
  • How to embed a complex view hierarchy inside a UIScrollView.
  • How to use UIScrollView’s paging feature, in conjunction with UIPageControl, to allow scrolling through multiple pages of content.
  • How to make a “peeking” UIScrollView that gives a glimpse of the previous/next page as well as the current page.
  • And much more!

This tutorial assumes some familiarity with Swift and iOS programming. If you are a complete beginner, you may wish to check out some of the other tutorials on this site first.

This tutorial also assumes that you know how to use Interface Builder to add new objects to a view and connect outlets between your code and the Storybard. You’ll want to be familiar with Storyboards before proceeding, so definitely take a look at the Storyboards tutorial on this site if you’re new to Storyboards and/or Interface Builder.

Getting Started

Fire up Xcode and create a new project. Choose File\New\Project…, then choose the iOS\Application\Single View Application template. Enter ScrollViews for the product name, choose Swift for the language, and set devices to iPhone.

Create Project

Click Next and choose a location to save your project.

Then download the resources for this project and drag & drop the extracted files into the project root. Make sure that the “Copy items if needed” checkbox is ticked.

Copy Resources

Since this tutorial is going to illustrate four different things that you can do with scroll views, the project will have a tableview menu with four options from which to select. Each option will open a new view controller to show off a certain aspect of scroll views.

This is what your storyboard will look like when you’re finished:

Storyboard Overall

To build the tableview menu, do the following:

  1. Open Main.storyboard and delete the scene that’s already in there by selecting the view controller (click on it on the storyboard) and then deleting it.
  2. For this tutorial you’re going to disable Auto Layout. From the Utilities panel, choose the File Inspector, and uncheck Use Auto Layout. From the alert that appears, make sure “Keep size class data for:” is set to iPhone. Then choose Disable Size Classes.
  3. Disable Size Classes

  4. Next, add a Table View Controller by dragging one from the Object Library on to the storyboard.
  5. Now select the table you added and choose Editor\Embed In\Navigation Controller.
  6. Select the table view within the table view controller, and set the content type to Static Cells in the attributes inspector (as shown in image below).
  7. Static Cells

  8. Click on the arrow next to Table View in the Document Outline showing the storyboard hierarchy and then select Table View Section. In the inspector, set the number of rows in the section to 4.
  9. UIScrollView table view section

  10. For each row in the table view, set its style to Basic and edit the labels to read:
    • Image Scroll
    • Custom View Scroll
    • Paged
    • Paged with Peeking

Note: As you change each table row’s style to “Basic”, the table row will get an additional sub-component, the label. You might need to again expand the row items to be able to see the sub-component items and to edit them.

Save the storyboard, and build and run. You should see your table view, similar to the image below. Sadly, the table view does absolutely nothing at the moment – but you can fix that!

Scroll View Run 1

Scrolling and Zooming a Large Image

The first thing you’re going to learn is how to set up a scroll view that allows the user to zoom into an image and pan around.

First, you need to set up the view controller. Open ViewController.swift, and change the class declaration at the top of the file so it also conforms to the UIScrollViewDelegate protocol:

class ViewController: UIViewController, UIScrollViewDelegate {

Inside the class declaration, add the following outlet property:

@IBOutlet var scrollView: UIScrollView!

You’ll wire this up to the actual scroll view in the next step.

Open the storyboard and drag a View Controller from the objects library onto the canvas. Select the new view controller and in the Identity Inspector, set its class to ViewController.

View controller class type

This view controller will show the image scroll demo. Control-click and drag from the Image Scroll row of the table view to the new view controller. In the popup menu that appears, select Push under Selection Segue. This will wire things up so the view controller is pushed onto the navigation stack when the user selects that first row.

Drag a Scroll View from the object library to completely fill the view controller.

Add Scroll View

Wire up the scroll view to the view controller by attaching it to the scrollView outlet and setting the view controller as the scroll view’s delegate.

Scroll View Outlets

Now you’re going to get down and dirty with the code. Open ViewController.swift and add a new property to the class:

var imageView: UIImageView!

This will hold the image view that the user will be scrolling around.

Now it’s time to get into the most interesting part of setting up the scroll view. Replace viewDidLoad with the following code:

override func viewDidLoad() {
  super.viewDidLoad()
 
  // 1
  let image = UIImage(named: "photo1.png")
  imageView = UIImageView(image: image)
  imageView.frame = CGRect(origin: CGPoint(x: 0, y: 0), size:image.size)
  scrollView.addSubview(imageView)
 
  // 2
  scrollView.contentSize = image.size
 
  // 3
  var doubleTapRecognizer = UITapGestureRecognizer(target: self, action: "scrollViewDoubleTapped:")
  doubleTapRecognizer.numberOfTapsRequired = 2
  doubleTapRecognizer.numberOfTouchesRequired = 1
  scrollView.addGestureRecognizer(doubleTapRecognizer)
 
  // 4
  let scrollViewFrame = scrollView.frame
  let scaleWidth = scrollViewFrame.size.width / scrollView.contentSize.width
  let scaleHeight = scrollViewFrame.size.height / scrollView.contentSize.height
  let minScale = min(scaleWidth, scaleHeight);
  scrollView.minimumZoomScale = minScale;
 
  // 5
  scrollView.maximumZoomScale = 1.0
  scrollView.zoomScale = minScale;
 
  // 6
  centerScrollViewContents()
}

This might look complicated, so let’s break it down step-by-step. You’ll see it’s really not too bad.

  1. First, you need to create an image view with the photo1.png image you added to your project and you set the image view frame (it’s size and position) so it’s the size of the image and sits at point (0,0) within the superview. Finally, add the image view as a subview of the scroll view.
  2. You have to tell your scroll view the size of the content contained within it, so that it knows how far it can scroll horizontally and vertically. In this case, it’s the size of the image.
  3. Here you’re setting up a gesture recognizer for the double-tap to zoom in. You don’t need a UIPinchGestureRecognizer for zooming, because UIScrollView has one already built-in!
  4. Next, you need to work out the minimum zoom scale for the scroll view. A zoom scale of one means that the content is displayed at normal size. A zoom scale below one shows the content zoomed out, while a zoom scale of greater than one shows the content zoomed in. To get the minimum zoom scale, you calculate how far you’d need to zoom out so that the image fits snugly in your scroll view’s bounds based on its width. Then you do the same based upon the image’s height. The minimum of those two resulting zoom scales will be the scroll view’s minimum zoom scale. That gives you a zoom scale where you can see the entire image when fully zoomed out.
  5. You set the maximum zoom scale as 1, because zooming in more than the image’s resolution can support will cause it to look blurry. You set the initial zoom scale to be the minimum, so that the image starts fully zoomed out.
  6. This calls a helper method to center the image within the scroll view. Where’s the helper method? It’s coming up next!

Add the implementation of centerScrollViewContents to the class:

func centerScrollViewContents() {
  let boundsSize = scrollView.bounds.size
  var contentsFrame = imageView.frame
 
  if contentsFrame.size.width < boundsSize.width {
    contentsFrame.origin.x = (boundsSize.width - contentsFrame.size.width) / 2.0
  } else {
    contentsFrame.origin.x = 0.0
  }
 
  if contentsFrame.size.height < boundsSize.height {
    contentsFrame.origin.y = (boundsSize.height - contentsFrame.size.height) / 2.0
  } else {
    contentsFrame.origin.y = 0.0
  }
 
  imageView.frame = contentsFrame
}

The point of this function is to get around a slight annoyance with UIScrollView: if the scroll view content size is smaller than its bounds, then it sits at the top-left rather than in the center. Since you’ll be allowing the user to zoom out fully, it would be nice if the image sat in the center of the view. This function accomplishes that by positioning the image view such that it is always in the center of the scroll view’s bounds.

Finally, add the implementation of scrollViewDoubleTapped to the class to handle the double-tap gesture:

func scrollViewDoubleTapped(recognizer: UITapGestureRecognizer) {
  // 1        
  let pointInView = recognizer.locationInView(imageView)
 
  // 2
  var newZoomScale = scrollView.zoomScale * 1.5
  newZoomScale = min(newZoomScale, scrollView.maximumZoomScale)
 
  // 3
  let scrollViewSize = scrollView.bounds.size
  let w = scrollViewSize.width / newZoomScale
  let h = scrollViewSize.height / newZoomScale
  let x = pointInView.x - (w / 2.0)
  let y = pointInView.y - (h / 2.0)
 
  let rectToZoomTo = CGRectMake(x, y, w, h);
 
  // 4
  scrollView.zoomToRect(rectToZoomTo, animated: true)
}

This function is called when the tap gesture recognizer detects a double tap. Here’s a step-by-step guide to what’s happening here:

  1. First, you need to work out where the tap occurred within the image view. You’ll use this to zoom in directly on that point, which is probably what you’d expect as a user.
  2. Next, you calculate a zoom scale that’s zoomed in 150%, but capped at the maximum zoom scale you specified in viewDidLoad.
  3. Then you use the location from step #1 to calculate a CGRect rectangle that you want to zoom in on.
  4. Finally, you need to tell the scroll view to zoom in, and here you animate it to look pretty too.

For more information on the different gesture recognizers available in iOS, check out our UIGestureRecognizer tutorial.

Now, remember how you set up ViewController as a UIScrollViewDelegate? Well, now you’re going to implement a couple of needed functions in that protocol. Add the following method to the class:

func viewForZoomingInScrollView(scrollView: UIScrollView!) -> UIView! {
  return imageView
}

This is the heart and soul of the scroll view’s zooming mechanism. You’re telling it which view should be made bigger and smaller when the scroll view is pinched. So, you tell it that it’s your imageView.

Finally, add this delegate method to the class:

func scrollViewDidZoom(scrollView: UIScrollView!) {
  centerScrollViewContents()
}

The scroll view will call this method after the user finishes zooming. Here, you need to re-center the view – if you don’t, the scroll view won’t appear to zoom naturally; instead, it will sort of stick to the top-left.

Now take a deep breath, give yourself a pat on the back and build and run your project! Tap on Image Scroll and if everything went smoothly, you’ll end up with a lovely image that you can zoom, pan and tap. w00t!

Scroll View Run 2

Scrolling and Zooming a View Hierarchy

What if you want more than an image in your scroll view? What if you’ve got some complex view hierarchy which you want to be able to zoom and pan around? Well, there’s a scroll view for that! What’s more, it’s just a small step beyond what you’ve done already.

Create a new file with the iOS\Source\Cocoa Touch Class subclass template. Name the class CustomScrollViewController and set the subclass to UIViewController. Make sure “Also create XIB file” is not checked and the language is set to Swift. Click Next and save it with the rest of the project.

Open CustomScrollViewController.swift and replace the contents with this:

import UIKit
 
class CustomScrollViewController: UIViewController, UIScrollViewDelegate {
  @IBOutlet var scrollView: UIScrollView!
 
}

Next, open Main.storyboard and just as before, add a View Controller that’s wired up with a push segue from the 2nd row of the table. Set the view controller’s class to be the class you just created, CustomScrollViewController.

Also add a Scroll View and connect it to the outlet created and set the view controller as its delegate, just as before.

Then, open CustomScrollViewController.swift and add this property just below your scrollView outlet:

var containerView: UIView!

The difference compared to the previous view controller is that instead of a UIImageView, you’ve got a UIView called containerView. That should be a little hint as to how this is all going to work.

Now, implement viewDidLoad like so.

override func viewDidLoad() {
  super.viewDidLoad()
 
  // Set up the container view to hold your custom view hierarchy
  let containerSize = CGSize(width: 640.0, height: 640.0)
  containerView = UIView(frame: CGRect(origin: CGPoint(x: 0, y: 0), size:containerSize))
  scrollView.addSubview(containerView)
 
  // Set up your custom view hierarchy
  let redView = UIView(frame: CGRect(x: 0, y: 0, width: 640, height: 80))
  redView.backgroundColor = UIColor.redColor();
  containerView.addSubview(redView)
 
  let blueView = UIView(frame: CGRect(x: 0, y: 560, width: 640, height: 80))
  blueView.backgroundColor = UIColor.blueColor();
  containerView.addSubview(blueView)
 
  let greenView = UIView(frame: CGRect(x: 160, y: 160, width: 320, height: 320))
  greenView.backgroundColor = UIColor.greenColor();
  containerView.addSubview(greenView)
 
  let imageView = UIImageView(image: UIImage(named: "slow.png"))
  imageView.center = CGPoint(x: 320, y: 320);
  containerView.addSubview(imageView)
 
  // Tell the scroll view the size of the contents
  scrollView.contentSize = containerSize;
 
  // Set up the minimum & maximum zoom scales
  let scrollViewFrame = scrollView.frame
  let scaleWidth = scrollViewFrame.size.width / scrollView.contentSize.width
  let scaleHeight = scrollViewFrame.size.height / scrollView.contentSize.height
  let minScale = min(scaleWidth, scaleHeight)
 
  scrollView.minimumZoomScale = minScale
  scrollView.maximumZoomScale = 1.0
  scrollView.zoomScale = 1.0
 
  centerScrollViewContents()
}

viewDidLoad sets up a view hierarchy with a single root view, which is your instance variable, containerView. Then you add that single view to the scroll view. That is the key here – just one view can be added to the scroll view if you’re going to be zooming in, because as you’ll recall, you can only return one view in the delegate callback viewForZoomingInScrollView. You set the zoomScale to 1 instead of minScale so that the content view is at normal size, instead of it fitting the screen.

Again, implement centerScrollViewContents and the two UIScrollViewDelegate functions, substituting imageView with containerView from the original versions.

func centerScrollViewContents() {
  let boundsSize = scrollView.bounds.size
  var contentsFrame = containerView.frame
 
  if contentsFrame.size.width < boundsSize.width {
    contentsFrame.origin.x = (boundsSize.width - contentsFrame.size.width) / 2.0
  } else {
    contentsFrame.origin.x = 0.0
  }
 
  if contentsFrame.size.height < boundsSize.height {
    contentsFrame.origin.y = (boundsSize.height - contentsFrame.size.height) / 2.0
  } else {
    contentsFrame.origin.y = 0.0
  }
 
  containerView.frame = contentsFrame
}
 
func viewForZoomingInScrollView(scrollView: UIScrollView!) -> UIView! {
  return containerView
}
 
func scrollViewDidZoom(scrollView: UIScrollView!) {
  centerScrollViewContents()
}

Note: You’ll probably notice the lack of the UITapGestureRecognizer. That is simply to make this part of the tutorial more straightforward. Feel free to add it in afterwards as an additional exercise.

Now build and run your project. This time, select Custom View Scroll and watch in amazement as you can pan and zoom around a beautifully hand-crafted UIView scene!

Scroll View Run 3

Paging with UIScrollView

In the third section of this tutorial, you’ll be creating a scroll view that allows paging. This means that the scroll view locks onto a page when you stop dragging. You’ll see this in action in the App Store app when you view screenshots of an app, for instance.

Create a new file with the iOS\Source\Cocoa Touch Class subclass template. Name the class PagedScrollViewController and set the subclass to UIViewController. Make sure Also create XIB file is not checked and that the language is set to Swift. Click Next and save it with the rest of the project.

Open PagedScrollViewController.swift and replace the contents of the file with the following:

import UIKit
 
class PagedScrollViewController: UIViewController, UIScrollViewDelegate {
  @IBOutlet var scrollView: UIScrollView!
  @IBOutlet var pageControl: UIPageControl!
}

Next, go to Main.storyboard and just like before, add a View Controller that’s wired up with a push segue from the 3rd row of the table. Set the view controller’s class to be the class you just created, PagedScrollViewController.

Set the background color of the main view to be black, so that the page control that you will be adding will be visible – it is white by default, and white on white really doesn’t work!

Add a Page Control element to the bottom of the view and make it fill the width. Wire it up to the pageControl outlet.

Also, add and wire up a Scroll View to the outlet created, and set the view controller as its delegate, just like before. Adjust the size of the Scroll View to fill the view controller, but leave some room for the Page Control.

This time, turn on Paging Enabled for the scroll view via the Attributes Inspector.

Now open PagedScrollViewController.swift and add these properties after the outlets:

var pageImages: [UIImage] = []
var pageViews: [UIImageView?] = []

You’ll notice some differences this time. There’s no container view, and there are two arrays.

  • pageImages: This will hold all the images to display – 1 per page.
  • pageViews: This will hold instances of UIImageView to display each image on its respective page. It’s an array of optionals, because you’ll be loading the pages lazily (i.e. as and when you need them) so you need to be able to handle nil values from the array.

Next, implement viewDidLoad as follows:

override func viewDidLoad() {
  super.viewDidLoad()
 
  // 1
  pageImages = [UIImage(named: "photo1.png"),
    UIImage(named: "photo2.png"),
    UIImage(named: "photo3.png"),
    UIImage(named: "photo4.png"),
    UIImage(named: "photo5.png")]
 
  let pageCount = pageImages.count
 
  // 2
  pageControl.currentPage = 0
  pageControl.numberOfPages = pageCount
 
  // 3
  for _ in 0..<pageCount {
    pageViews.append(nil)
  }
 
  // 4
  let pagesScrollViewSize = scrollView.frame.size
  scrollView.contentSize = CGSize(width: pagesScrollViewSize.width * CGFloat(pageImages.count),
                                  height: pagesScrollViewSize.height)
 
  // 5
  loadVisiblePages()
}

Breaking that down, this is what’s happening:

  1. First, you set up the page images. You’ve added five photos to the project and so you just make an array containing all of them.
  2. The page index starts at zero, so you set the page control to the first page and tell it how many pages there are.
  3. Next, you set up the array that holds the UIImageView instances. At first, no pages have been lazily loaded and so you just fill it with nil objects as placeholders – one for each page. Later on, you’ll use optional binding to check if that page is loaded or not.
  4. The scroll view, as before, needs to know its content size. Since you want a horizontal paging scroll view (it could just as easily be vertical if you want), you calculate the width to be the number of pages multiplied by the width of the scroll view. The height of the content is the same as the height of the scroll view.
  5. You’re going to need some pages shown initially, so you call loadVisiblePages, which you’ll implement soon.

Add the following method to the class:

func loadPage(page: Int) {
  if page < 0 || page >= pageImages.count {
    // If it's outside the range of what you have to display, then do nothing
    return
  }
 
  // 1
  if let pageView = pageViews[page] {
    // Do nothing. The view is already loaded.
  } else {
    // 2
    var frame = scrollView.bounds
    frame.origin.x = frame.size.width * CGFloat(page)
    frame.origin.y = 0.0
 
    // 3
    let newPageView = UIImageView(image: pageImages[page])
    newPageView.contentMode = .ScaleAspectFit
    newPageView.frame = frame
    scrollView.addSubview(newPageView)
 
    // 4
    pageViews[page] = newPageView
  }
}

Remember each page is a UIImageView stored in an array of optionals. When the view controller loads, the array is filled with nil. This method will load the content of each page:

  1. First, you’re using optional binding to check if you’ve already loaded the view. If pageView contains a UIImageView then do nothing and ignore the rest of this function.
  2. If pageView is nil, then you need to create a page. So first, work out the frame for this page. It’s calculated as being the same size as the scroll view, positioned at zero y offset, and then offset by the width of a page multiplied by the page number in the x (horizontal) direction.
  3. This creates a new UIImageView, sets it up and adds it to the scroll view.
  4. Finally, you replace the nil in the pageViews array with the view you’ve just created, so that if this page was asked to load again, you would now not go into the if statement and instead do nothing, since the view for the page has already been created.

Next, add the following method to the class:

func purgePage(page: Int) {
  if page < 0 || page >= pageImages.count {
    // If it's outside the range of what you have to display, then do nothing
    return
  }
 
  // Remove a page from the scroll view and reset the container array
  if let pageView = pageViews[page] {
    pageView.removeFromSuperview()
    pageViews[page] = nil
  }
}

This function purges a page that was previously created via loadPage(). It first checks that the object in the pageViews array for this page is not nil. If it’s not, it removes the view from the scroll view and updates the pageViews array with nil again to indicate that this page is no longer there.

Why bother lazy loading and purging pages, you ask? Well, in this example, it won’t matter too much if you load all the pages at the start, since there are only five and they won’t be large enough to eat up too much memory. But imagine you had 100 pages and each image was 5MB in size. That would take up 500MB of memory if you loaded all the pages at once! Your app would quickly exceed the amount of memory available and be killed by the operating system. Lazy loading means that you’ll only have a certain number of pages in memory at any given time.

The two functions you defined above are tied together via a function called loadVisiblePages(). Add the implementation of that method to the class:

func loadVisiblePages() {
  // First, determine which page is currently visible
  let pageWidth = scrollView.frame.size.width
  let page = Int(floor((scrollView.contentOffset.x * 2.0 + pageWidth) / (pageWidth * 2.0)))
 
  // Update the page control
  pageControl.currentPage = page
 
  // Work out which pages you want to load
  let firstPage = page - 1
  let lastPage = page + 1
 
  // Purge anything before the first page
  for var index = 0; index < firstPage; ++index {
    purgePage(index)
  }
 
  // Load pages in our range
  for index in firstPage...lastPage {
    loadPage(index)
  }
 
  // Purge anything after the last page
  for var index = lastPage+1; index < pageImages.count; ++index {
    purgePage(index)
  }
}

Here you work out what page the scroll view is currently on, update the page control and then load or purge the relevant pages. The calculation of what page you’re on looks a bit scary, but it’s not too bad. You can convince yourself it’s correct by plugging some numbers in. (Note that the floor() function will round a decimal number to the next lowest integer.)

You choose to load the current page and the page on either side of it. This is so that as the user starts scrolling, they can see the next page before it becomes the central one. You could load the previous and next two or even three pages if you wanted, but this would increase memory usage and serves no useful purpose.

The final thing to do is to implement part of the UIScrollView delegate. This time you just need to implement scrollViewDidScroll(). Add this to PagedScrollViewController.swift:

func scrollViewDidScroll(scrollView: UIScrollView!) {
  // Load the pages that are now on screen
  loadVisiblePages()
}

All this does is ensure that as the scroll view is scrolled, the relevant pages are always loaded (and that unnecessary pages are purged).

Build and run the project, select Paged and marvel at the wonderful paged scroll view you’ve just created!

Scroll View Run 4

Viewing Previous/Next Pages

For the final addition to this project, I’m going to show you how you can make a scroll view that looks a lot like the screenshot viewer when browsing apps on the App Store app. You get to see parts of the previous and next pages, and it’s a great technique because the user can immediately see there’s extra content they can scroll through.

Create a new file with the iOS\Source\Cocoa Touch Class subclass template. Name the class PeekPagedScrollViewController and set the subclass to UIViewController. Make sure Also create XIB file is not checked and that the language is set to Swift. Click Next and save it with the rest of the project.

Open PeekPagedScrollViewController.swift and replace its contents with the following:

import UIKit
 
class PeekPagedScrollViewController: UIViewController, UIScrollViewDelegate {
  @IBOutlet var scrollView: UIScrollView!
  @IBOutlet var pageControl: UIPageControl!
 
  var pageImages: [UIImage] = []
  var pageViews: [UIImageView?] = []
}

Then implement viewDidLoad, which is the same as in the previous section’s paged scroll view example.

override func viewDidLoad() {
  super.viewDidLoad()
 
  // Set up the image you want to scroll & zoom and add it to the scroll view
  pageImages = [UIImage(named: "photo1.png"),
    UIImage(named: "photo2.png"),
    UIImage(named: "photo3.png"),
    UIImage(named: "photo4.png"),
    UIImage(named: "photo5.png")]
 
  let pageCount = pageImages.count
 
  // Set up the page control
  pageControl.currentPage = 0
  pageControl.numberOfPages = pageCount
 
  // Set up the array to hold the views for each page
  for _ in 0..<pageCount {
    pageViews.append(nil)
  }
 
  // Set up the content size of the scroll view
  let pagesScrollViewSize = scrollView.frame.size
  scrollView.contentSize = CGSizeMake(pagesScrollViewSize.width * CGFloat(pageImages.count), pagesScrollViewSize.height)
 
  // Load the initial set of pages that are on screen
  loadVisiblePages()
}

Then, implement loadVisiblePages, loadPage:, purgePage:, and the scrollViewDidScroll: UIScrollView delegate function, which are also identical to the previous section, except for a slight difference in loadPage, explained below.

func loadVisiblePages() {
  // First, determine which page is currently visible
  let pageWidth = scrollView.frame.size.width
  let page = Int(floor((scrollView.contentOffset.x * 2.0 + pageWidth) / (pageWidth * 2.0)))
 
  // Update the page control
  pageControl.currentPage = page
 
  // Work out which pages you want to load
  let firstPage = page - 1
  let lastPage = page + 1
 
  // Purge anything before the first page
  for var index = 0; index < firstPage; ++index {
    purgePage(index)
  }
 
  // Load pages in our range
  for index in firstPage...lastPage {
    loadPage(index)
  }
 
  // Purge anything after the last page
  for var index = lastPage+1; index < pageImages.count; ++index {
    purgePage(index)
  }
}
 
func loadPage(page: Int) {
  if page < 0 || page >= pageImages.count {
    // If it's outside the range of what you have to display, then do nothing
    return
  }
 
  // Load an individual page, first checking if you've already loaded it
  if let pageView = pageViews[page] {
    // Do nothing. The view is already loaded.
  } else {
    var frame = scrollView.bounds
    frame.origin.x = frame.size.width * CGFloat(page)
    frame.origin.y = 0.0
    frame = CGRectInset(frame, 10.0, 0.0)
 
    let newPageView = UIImageView(image: pageImages[page])
    newPageView.contentMode = .ScaleAspectFit
    newPageView.frame = frame
    scrollView.addSubview(newPageView)
    pageViews[page] = newPageView
  }
}
 
func purgePage(page: Int) {
  if page < 0 || page >= pageImages.count {
    // If it's outside the range of what you have to display, then do nothing
    return
  }
 
  // Remove a page from the scroll view and reset the container array
  if let pageView = pageViews[page] {
    pageView.removeFromSuperview()
    pageViews[page] = nil
  }
}
 
func scrollViewDidScroll(scrollView: UIScrollView!) {
  // Load the pages that are now on screen
  loadVisiblePages()
}

The only difference in the above functions from those implemented in the earlier sections is the addition of the following line of code in loadPage:

frame = CGRectInset(frame, 10.0, 0.0)

This line sets the frame of the image view to be slightly inset horizontally, such that the pages don’t touch. It makes it look pretty similar to the screenshots viewer in the App Store app.

Now go to Main.storyboard, and just as in the previous example, add a View Controller that’s wired up with a push segue from the 4th row of the table. Set the view controller’s class to be the class you just created, PeekPagedScrollViewController.

As before, set the main view background to black, and add a Page Control element and wire it up. Also add and wire up a “Paging Enabled” Scroll View to the outlet created, and set the view controller as its delegate.

Make the scroll view smaller than the screen – my suggestion is 240×312 – and center it on the screen. It should end up looking like this:

Peek paged scroll view

Next, turn off Clip Subviews for the scroll view. This will allow it to draw outside of its view, which is important for the peeking of pages.

Clip subviews

Build and run, choose Paged with peeking, and there you have it! Well done!

Scroll View Run 5

Detecting Touches Outside a Scroll View

You may have just noticed with the peeking pages that you now can’t tap outside of the scroll view region. That’s not ideal now, is it? But we can fix it!

The problem is that the scroll view only gets the touches if they occur within its bounds, and now that the bounds are smaller than the area it draws into (because Clip Subviews is off), it will miss some touches. You’re going to fix it by wrapping the scroll view in a container view whose job it is to intercept touches and hand them off to the scroll view.

Create a new file with the iOS\Source\Cocoa Touch Class subclass template. Name the class ScrollViewContainer and make it a subclass of UIView. Make sure the language is set to Swift and click Next and save it with the rest of the project.

Open ScrollViewContainer.swift and replace its contents with the following:

import UIKit
 
class ScrollViewContainer: UIView {
  @IBOutlet var scrollView: UIScrollView!
 
  override func hitTest(point: CGPoint, withEvent event: UIEvent!) -> UIView? {
    let view = super.hitTest(point, withEvent: event)?
    if let theView = view {
      if theView == self {
        return scrollView
      }
    }
 
    return view
  }
}

That’s simple, right? I bet you thought there’d be lines and lines of code. Well, not today. All this does is hand control over to the scroll view for any touches that occur within the container view’s bounds.

Now you need to actually use the new container view you’ve created.

Go to Main.storyboard and back to the Peek Paged Scroll View Controller for this example. Select the scroll view and then choose Editor\Embed In\View. This should have created a view that the scroll view now sits within.

Make this new view the width of the screen and the height of the scroll view. Then set its class to ScrollViewContainer. Also wire up the scrollView outlet of the container to the scroll view. It should then look like this:

Embed in container

Also remember to set the background color for the container view to Clear Color, since it sits on top of the main view, and the container view will, by default, have a white background.

Build and run. Choose Paged with peeking. Notice you can now tap outside the scroll view’s bounds as you desire. w00t! How cool is that and all done with just a few lines of code!

Scroll View Run 6

Where to Go From Here?

Here is an example project with all of the code from this tutorial.

You’ve delved into many of the interesting things that a scroll view is capable of. If you feel confident about what you’ve done here, you might want to attempt the following extras:

  • Create a vertically paging scroll view.
  • Embed a zoomable scroll view within a paging scroll view so that each page can be zoomed and panned individually.
  • Embed a series of vertically paging scroll views within a horizontally paging scroll view to give the illusion of a 2D grid.

Now go make some awesome apps safe in the knowledge that you’ve got mad scroll view skills!

If you run into any problems along the way or want to leave feedback about what you’ve read here, join in the discussion in the comments below.

How To Use UIScrollView to Scroll and Zoom Content in Swift is a post from: Ray Wenderlich

The post How To Use UIScrollView to Scroll and Zoom Content in Swift appeared first on Ray Wenderlich.

Viewing all 4373 articles
Browse latest View live


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