IntroductionWelcome| 00:04 | Hi! This Simon Allardice, and
welcome to iOS SDK Essential Training.
| | 00:09 | Here you'll see how to build
applications that run on the iPhone and the iPad,
| | 00:13 | using Apple's free iOS SDK,
or software development kit.
| | 00:17 | In this course we'll work with Xcode 4,
the main application for creating,
| | 00:22 | testing, debugging, and managing our apps.
| | 00:24 | You see a lot of Objective-C, the
programming language we use to create iOS applications.
| | 00:30 | But apart from the tools and the
language, we're going to explore the
| | 00:33 | conventions and guidelines
of programming iOS devices,
| | 00:36 | essential concepts like model
ViewController, target action, and delegation.
| | 00:42 | And we'll see how to build an iOS
user interface using the most recent
| | 00:47 | features of the iOS 5 SDK,
like ARC and Storyboards.
| | 00:51 | We'll work with the most
important controls and controllers in iOS.
| | 00:56 | We'll talk about testing and
debugging and even see what's different when
| | 00:59 | developing for the iPad.
| | 01:01 | So let's get started.
| | Collapse this transcript |
| What you should know| 00:01 | So what should you know to
make the most of this course?
| | 00:03 | Well, it is an introduction to
programming on the iPhone and the iPad, but it's
| | 00:07 | not an introduction to programming in general,
| | 00:10 | so I do expect that you can program.
| | 00:12 | You can write code in some other language.
| | 00:14 | You're comfortable with the core skills
of programming: functions, conditions,
| | 00:18 | variables, loops, and so on.
| | 00:20 | Now if this is all brand-new to you,
this is not the best course to begin.
| | 00:25 | So take a look at our Foundations
of Programming Fundamentals course.
| | 00:29 | Next, you should know a little
Objective-C, and the more you know the better.
| | 00:33 | If you've only dabbled in, or if it's
been a while, I am going to have a short
| | 00:38 | refresher/introduction to the language
here, but it is just the basics, because
| | 00:43 | we have a full Objective-C Essential
Training Course in the lynda.com library,
| | 00:48 | and I am not going to just
duplicate that course inside this one.
| | 00:51 | And that let's us focus
here on the iOS side of things,
| | 00:55 | what's specific about iPhone an iPad
development, instead of things like how do
| | 00:59 | you make an integer?
| | 01:00 | So if that's the case, what
should you expect with this course?
| | 01:04 | Well, I had three rules for myself
when I was putting this course together.
| | 01:08 | Number 1, I was going to
focus on the most important 20%.
| | 01:11 | There are thousands of pages, dozens of
documents on Apple's developer site alone.
| | 01:17 | There is a lot of iOS information
for you to try and cram into your brain, but
| | 01:21 | only about 20% of that is immediately
worthwhile, and we're going to focus on that 20.
| | 01:27 | It's iOS SDK Essential Training here,
the fundamentals, the things you will need
| | 01:32 | in every iOS app you make.
| | 01:35 | Number 2, the rules, not the exceptions.
| | 01:38 | This is programming, so yes, there are
always multiple ways to accomplish the
| | 01:42 | same result and the geekier
you are, the more you can find.
| | 01:46 | So if it makes you happy, assume
that yes, there are other ways to do
| | 01:50 | everything I am going to show.
| | 01:52 | But also assume that I am
going to show you the simplest one.
| | 01:55 | Number 3, this is not an exam.
| | 01:57 | I'm not interested in you doing a
memory test of long method names and
| | 02:01 | obscure parameters,
| | 02:02 | so focus on the concepts, on the
approach here, rather than memorizing
| | 02:07 | the tiniest pieces.
| | 02:08 | Because we are also going to get
familiar with the help systems and the
| | 02:11 | documentation, so that when you do
forget something--and you will--you can just
| | 02:16 | find it when you need it.
| | 02:17 | So those are my three items for how I am
putting together this course. What about you?
| | 02:22 | Well, I do have three suggestions for you too.
| | 02:25 | One, realize that you're in another world now.
| | 02:29 | You may have a ton of experience in
Java or .NET or PHP or Ruby On Rails, but
| | 02:35 | leave that at the door.
| | 02:36 | Objective-C and iOS development is
different, often very different, and this is
| | 02:41 | more than just a few syntax changes.
| | 02:44 | Apple development has a substantial
history, and it has its own customs and
| | 02:48 | ways of doing things.
| | 02:49 | If you try to force everything here
into an exact equivalent of something you
| | 02:53 | do in Java or C++ or JavaScript, you're
likely to find this journey very painful indeed.
| | 02:59 | So number two, embrace
confusion, at lease for a while.
| | 03:04 | There are a thousand things to learn with the
iOS SDK, and you can't learn them all at once.
| | 03:10 | In a few minutes we are going to
create your first iOS project and some code
| | 03:14 | will appear, and you'll
have no idea what it means.
| | 03:17 | And your personality may be such that
you think, well, I need to have that
| | 03:19 | explained before I move forward, and I
will say, no, you don't, we are going to
| | 03:23 | move on and come back to that later.
| | 03:25 | So there will be things that
won't make sense for a little while.
| | 03:29 | So number three, experiment and have fun.
| | 03:32 | If you don't already have an app
in mind, come up with something,
| | 03:36 | anything to help you use the examples
here in your own way, and it will help you
| | 03:40 | make all the connections.
| | 03:41 | So realize you're in another world,
embrace a little confusion, and experiment
| | 03:45 | and have fun with it.
| | 03:46 | If you keep this in mind throughout
the course, you'll have a much better
| | 03:49 | time learning it all.
| | Collapse this transcript |
| What's new in this version of the course| 00:00 | In 2009, we released our first course
on iPhone development called iPhone
| | 00:06 | SDK Essential Training.
| | 00:08 | Now back then, the operating system on
the device was still so-called iPhone OS,
| | 00:12 | not iOS, because there was no iPad yet.
| | 00:15 | It was iPhone OS Version 3 and we used the
iPhone SDK Version 3 to program our apps.
| | 00:21 | A lot has changed since then.
| | 00:23 | New hardware of course; we have the
iPad, the iPad 2, the iPhone 4 and 4S.
| | 00:28 | But more importantly for developers, we
have much that has been added and improved.
| | 00:32 | So since then, we've released many iOS
courses at lynda.com, covering features in
| | 00:37 | Version 4 of the SDK and iPad
development, the release of Xcode 4, even iOS 5
| | 00:43 | SDK, game development and so on, but
the original course was falling behind.
| | 00:47 | So this is a completely new version of the
Essential Training course to bring it up to date.
| | 00:53 | This course has been recorded from
scratch using the latest version of the iOS
| | 00:57 | SDK and Xcode, but more importantly,
the newest features and the current best
| | 01:02 | practices for iOS development.
| | 01:04 | Because we now have technologies like
multitasking, Grand Central Dispatch,
| | 01:08 | blocks, storyboards, Automatic Reference
Counting, none of which were available
| | 01:13 | when I wrote the first course, all of
which I'll cover in this one, and while
| | 01:17 | they might sound a little intimidating,
all of them make creating an iOS app
| | 01:21 | better and easier than it ever was before.
| | 01:24 | So what does up to date mean?
| | 01:26 | I'm recording this course in early 2012,
and right now the version of the iPhone
| | 01:31 | and iPad operating system is iOS 5,
released in October 2011. And in this course,
| | 01:36 | we'll be using the iOS SDK Version 5.
| | 01:40 | And our main application is Xcode 4,
specifically Xcode 4.3, although any
| | 01:46 | version from Xcode 4.2 upwards will work.
| | 01:49 | Now if you don't yet have the SDK, or if
you're not quite sure which version you
| | 01:53 | have, we'll get to that in a moment.
| | Collapse this transcript |
| Using the exercise files| 00:00 | If you're a Premium member of lynda.com
or if you're watching this tutorial on a
| | 00:04 | DVD, you have access to some
exercise files used in this title.
| | 00:08 | I have them here on my desktop, and they
are in a folder just called exercise files.
| | 00:12 | Inside that, any of the relevant
chapters will have its own folder, and there are
| | 00:17 | some simple files that you'll find
inside some of these folders that will help
| | 00:20 | you build the exercises.
| | 00:22 | And we will point out any of these
files at the relevant time, just by showing
| | 00:25 | your path to the file location.
| | 00:27 | And there are also some finished
examples if you want to compare and contrast
| | 00:31 | what you've done. But these
are all just for convenience.
| | 00:34 | If you don't have access to the
exercise files, you can follow along from
| | 00:37 | scratch or create your own assets.
| | Collapse this transcript |
|
|
1. Getting StartedRequirements: installing the SDK| 00:00 | So let's say you've got a great idea for an
iPhone or iPad application. What do you need?
| | 00:05 | Well, first things first: you are
going to need a Mac. The development tools
| | 00:08 | are not cross-platform.
| | 00:10 | You need an Intel-based Mac, which
really means any Mac released after late 2006.
| | 00:14 | And it should be running
Lion, Mac OS 10.7 or later.
| | 00:20 | Now let's say you just borrowed a Macintosh
and you don't know for sure what it is running.
| | 00:23 | If you click your Apple menu at the
top-left and select About This Mac, this
| | 00:27 | will give us the version of the
operating system that were using.
| | 00:31 | In my case it's 10.7.2, which is fine.
| | 00:34 | You can install the tools on Snow
Leopard, which is Mac OS 10.6, but being on
| | 00:40 | the latest operating system is
highly recommended if you're going to be
| | 00:43 | developing on any Apple platform.
| | 00:46 | So I'll be using Lion as
my operating system here.
| | 00:49 | Now I can also see the word Intel
here in my Processor section, which means
| | 00:54 | we're fine. As far as our hardware requirements go,
| | 00:57 | we are completely ready.
| | 00:59 | Because technically, you don't
actually need an iPhone or iPad to write iOS
| | 01:05 | applications, as there is a Simulator in
the SDK that you are going to download.
| | 01:11 | But realistically, I expect that you
do have either an iPhone or an iPad or
| | 01:16 | both, so that you can test
your apps on a real device.
| | 01:19 | But to get this simulator and all the
other tools that we need, we need to go
| | 01:23 | ahead and get Xcode and the iOS SDK.
| | 01:26 | You can't do any development
without installing the SDK first.
| | 01:30 | If you have Lion as your operating
system, you can just get Xcode directly
| | 01:34 | from the Mac App Store.
| | 01:35 | If you go to the Developer
Tools category, you'll find it there.
| | 01:41 | This one Xcode download
is about 1.4 GB currently.
| | 01:46 | Now the reason it's so big,
that it's not just Xcode.
| | 01:50 | That's a bit of a lie.
| | 01:51 | It's Xcode plus a whole bunch of other
programs and tools and supporting files,
| | 01:55 | the iPhone and iPad Simulator, the
SDKs, or software development kits,
| | 02:00 | all bundled together.
| | 02:01 | Everything you need for creating iOS
apps and Mac desktop apps is all here.
| | 02:07 | Now I've gone ahead and installed it
already, which is why I see the Install button.
| | 02:12 | And I'm looking currently at
Version 4.3, released mid-February 2012.
| | 02:16 | Now Xcode is a free download from the
app store, but as of today, that's only if
| | 02:22 | you have Lion or a later operating system.
| | 02:24 | If you have Snow Leopard as your OS,
right now you have to get Xcode from the
| | 02:28 | developer.apple.com web site.
| | 02:31 | Up until February 2012, if you
downloaded Xcode from the App Store or from the
| | 02:36 | Developer site, what you actually
got was an installer application and you
| | 02:40 | would run that. It would install
Xcode and all the other SDK files under a
| | 02:44 | folder called Developer, at
the root of your hard drive.
| | 02:48 | Now with the release of Xcode 4.3, in
February 2012, Xcode is now installed like
| | 02:54 | other applications directly in
your normal Applications folder.
| | 02:58 | And the real test of course is, can you open it?
| | 03:01 | And once it's open, either from the
Welcome screen or you go to the Xcode About
| | 03:06 | menu, you need to see at least Version 4.2.
| | 03:10 | This course will work with any
version of Xcode from 4.2 upwards.
| | 03:14 | Now Apple releases updates to their developer
tools frequently, usually every few months.
| | 03:19 | So you could well have a later
version than I have, and that's fine.
| | 03:23 | I am a big believer in always
having the latest version of Xcode.
| | 03:26 | Though if you do, you may have some
small changes, and part of being an Apple
| | 03:30 | developer is rolling with
these frequent incremental changes.
| | Collapse this transcript |
| Becoming a registered Apple Developer| 00:00 | If you haven't already, you should
sign up with Apple to become a registered
| | 00:04 | Apple Developer before you go much
further, and this will give you access to
| | 00:09 | documentation and sample code and
videos and other good stuff, and it's free.
| | 00:13 | To do this, point a web
browser at developer.apple.com.
| | 00:20 | From this page, you can get to the three
different main Developer Centers that Apple has.
| | 00:24 | It's the iOS Dev Center.
| | 00:26 | That's the one we're obviously
interested in. And there's two more links for the
| | 00:30 | Mac Dev Center and Safari Dev Center.
| | 00:32 | So click that link.
| | 00:33 | That takes us here, the iOS Dev Center.
| | 00:36 | This is a useful link to have, so bookmark it.
| | 00:39 | You're going to use it a lot.
| | 00:40 | But you need to register
with Apple in order to log in.
| | 00:43 | Now, there's multiple ways that you
can sign up as an Apple Developer.
| | 00:47 | Some of them cost money; some of them are free.
| | 00:49 | The most basic is free.
| | 00:51 | You can just click that Register link,
if you haven't already signed up, and you
| | 00:54 | get all this information about what you
get. But I can just go ahead and click
| | 00:58 | the Get Started button, and it will
step me through creating an Apple ID if I
| | 01:02 | don't already have one,
or using an existing one.
| | 01:05 | And once you've filled all this
information out, you can go back and log in
| | 01:09 | to the iOS Dev Center.
| | 01:11 | And for now this is the place
that you need that has the most
| | 01:13 | current documentation.
| | 01:14 | It has sample code, and it will be very useful.
| | 01:17 | And not only that, we'll often access
it using Xcode, to make sure that we have
| | 01:22 | all the most up-to-date help information.
| | 01:24 | But signing up as a registered Apple
Developer isn't the only thing that we're
| | 01:28 | likely to do, and in a moment I'll
talk about the other developer programs
| | 01:32 | that Apple has.
| | Collapse this transcript |
| Joining the iOS Developer Program| 00:00 | So Apple gives us Xcode and the iOS SDK for
free, and it is the full complete version.
| | 00:06 | It's everything you need to write and
test your iOS applications using your Mac
| | 00:11 | and using the iPhone and iPad Simulator.
| | 00:14 | But there are a couple of
restrictions to know about.
| | 00:17 | If all you've done so far is sign up
with Apple as a registered Apple Developer,
| | 00:23 | what you won't yet be able to do is
plug in your own iPhone or iPad and copy
| | 00:28 | your applications from Xcode to that
device. And you also can't yet publish your
| | 00:33 | apps to the App Store.
| | 00:35 | If you want to do either of these things--
and hopefully you will want to--you'll
| | 00:38 | need to join the iOS Developer Program.
| | 00:41 | That's one step up from just being a
registered Apple developer, and it does cost money.
| | 00:46 | On the same page that you can get
information about being a registered
| | 00:49 | developer, down towards the bottom is
another link for more information about
| | 00:54 | the Developer Programs.
| | 00:55 | Well, there's an iOS Developer
Program that lets us release apps in the iOS
| | 01:00 | App Store, and a separate Mac Developer
Program to release apps in the Mac Desktop App Store.
| | 01:06 | Now, there are a couple of different
ways to join, depending on if you're trying
| | 01:09 | to sign up as an Enterprise Program
or with the university, but the classic
| | 01:14 | individual developer would be $99 a year.
| | 01:17 | It's 60 pounds in the UK, and so on.
| | 01:20 | Now, you don't get new software.
| | 01:22 | It's the same Xcode. It's the same SDK.
| | 01:24 | There is nothing changing about the
tools. But after joining what you will get
| | 01:29 | is the ability to do what's called
provisioning your devices, and that allows
| | 01:34 | you to copy your programs directly
from Xcode to your devices to test them,
| | 01:38 | which is much better than
only having a simulator.
| | 01:41 | And you'll be able to take your
finished applications and sell them on the App
| | 01:46 | Store, and there really is no other
way of getting your applications sold.
| | 01:49 | You can't do it privately.
| | 01:51 | You need to do it through the App Store.
| | 01:53 | You do not need to be in the iOS
Developer Program for this course, but you
| | 01:57 | certainly should know about it.
| | 01:59 | Do be aware that if you haven't joined
and you're just holding off until you
| | 02:03 | absolutely need to, the process
of doing this is not immediate.
| | 02:07 | You can't just pay your $99 and than
instantly copy across to your devices or
| | 02:11 | submit to the App Store.
| | 02:13 | Some information needs to be verified,
and you may have to wait a couple of days
| | 02:18 | after starting the sign-up process
before everything gets turned on.
| | Collapse this transcript |
| Creating a simple iOS application| 00:00 | So of course we want to dive right in
and start building iOS applications.
| | 00:04 | I am going to open up Xcode.
| | 00:06 | It's the icon that looks like
the blueprint with a hammer on top.
| | 00:10 | Now when you learn a new computer
language there is of course the tradition of
| | 00:13 | creating the simple "hello world" application.
| | 00:16 | Now the idea usually is that by
writing this really simple program, you'll
| | 00:20 | actually learn a lot about how the
new language or system works and how it
| | 00:24 | all hangs together.
| | 00:25 | Now with iOS development, you might have
a few more questions than answers after
| | 00:30 | you do this, but still we need to see why.
| | 00:33 | So I have the welcome screen for Xcode here.
| | 00:36 | If I'd had any recent projects,
I'd see them on the right-hand side.
| | 00:40 | On this left-hand side, I have a few
clickable areas for creating a new Xcode
| | 00:44 | project or connecting to a
source control repository.
| | 00:48 | I am going to go ahead and
create a new Xcode project.
| | 00:50 | We could also get to this through the File menu.
| | 00:53 | And right now just think
project equals application.
| | 00:57 | Whenever you want to make an app in
Xcode, you're going to make a project.
| | 01:00 | It's a way of keeping all
the relevant files together.
| | 01:03 | So I have this New Project window open.
| | 01:06 | And we actually have a lot of choices
if we start clicking around, because of
| | 01:11 | course Xcode isn't just used for iOS
development; it's also used for developing
| | 01:15 | programs on the Mac desktop.
| | 01:17 | So we actually have two
main sections for projects:
| | 01:19 | the Mac OS X section and the iOS section.
| | 01:23 | And the place we want to live is here,
clicking the Application beneath iOS, and
| | 01:29 | with that selected, we will see several
templates for creating different kinds
| | 01:34 | of iPhone and iPad applications.
| | 01:36 | We're going to come back to these,
but the one I'm interested in is this
| | 01:39 | Single View Application.
| | 01:41 | So again, under iOS on the left, we
have Application selected and then
| | 01:46 | Single View Application.
| | 01:48 | We click Next and now we have to
provide some names for our application.
| | 01:52 | The first one, the main
one, is this Product Name.
| | 01:55 | You can call it anything you want.
| | 01:57 | We're just making casual projects here.
| | 01:59 | So Demo is fine; Example is
fine, or in our case, HelloWorld.
| | 02:05 | Here, don't use spaces, or if you
have multiple words, just capitalize
| | 02:10 | the subsequent ones.
| | 02:11 | Now for Company Identifier, you need a
name here, because the Product Name won't
| | 02:16 | be enough to guarantee this was unique
if you were to sell it on the App Store.
| | 02:20 | There's over half a
million applications up there.
| | 02:23 | But by combining it with the
Company Identifier that's unique to your
| | 02:27 | organization, even if that organization
is just you as a solo developer, we can
| | 02:32 | be pretty sure that it's unique.
| | 02:33 | Now, by convention, this is usually
your domain name in reverse, so for me,
| | 02:38 | it might be com.lynda.
| | 02:40 | This address isn't actually followed,
so I could type whatever I wanted here.
| | 02:44 | It's just a way of making a unique name,
because as you see, what it's doing is
| | 02:49 | combining the Product Name and the
Company Identifier into what's called a
| | 02:53 | Bundle Identifier, which should make this unique.
| | 02:56 | Don't worry too much about
the Bundle Identifier right now.
| | 02:59 | Now there's also this
section that says Class Prefix.
| | 03:01 | Now whatever you type here will be
inserted by Xcode at the start of any class
| | 03:07 | or class files it makes for you.
Don't worry too much about this.
| | 03:10 | We're making casual projects.
| | 03:12 | Now, however, we do have to look
at this section, the Device Family.
| | 03:16 | What's this iOS application for?
| | 03:19 | Mostly we'll use iPhone in this
course because it's the simplest.
| | 03:22 | You can also make an iPad-specific
application or a universal application.
| | 03:27 | And universal simply means one iOS app
that can change its appearance based on
| | 03:33 | what device it's running on.
| | 03:34 | Now that adds some complexity to the
situation, so we won't do that here.
| | 03:38 | I'm going to choose iPhone.
| | 03:41 | And below, we have check
boxes for three extra features.
| | 03:44 | Now all of these features are great,
but two of them would add some complexity
| | 03:49 | to our simple little Hello World project
and one of them removes complexity from it.
| | 03:54 | So I want to have Storyboard
unchecked and Include Unit Tests unchecked.
| | 04:00 | But this is the one option I am
going to have checked, Use Automatic
| | 04:04 | Reference Counting.
| | 04:06 | Automatic Reference Counting, or ARC, is a
new feature in version 5 of the iOS SDK.
| | 04:11 | We'll talk more about this later, but in
short, it makes memory management easier.
| | 04:16 | It makes you write less code, and we
are going to have ARC checked for every
| | 04:21 | single project in this course. So, click Next.
| | 04:25 | Now we have to say where
to save the project files.
| | 04:29 | Now you can put this stuff anywhere you want.
| | 04:31 | There is no magic location for
storing your projects from Xcode.
| | 04:35 | You can put them in your Documents
folder, on your Desktop, however you'd
| | 04:39 | like to manage them.
| | 04:40 | I am going to just save them on my Desktop.
| | 04:42 | Now Xcode understands both git and
subversion for source control, if you work with those.
| | 04:47 | But this course is not about source
control, so I am going to leave this option
| | 04:52 | at the bottom unchecked and hit Create.
| | 04:54 | Now when you create this project, Xcode
is going to make several files for you.
| | 04:59 | On the left, we have a section
called the Project Navigator.
| | 05:03 | We'll get into this in a moment, but
it's basically a view of the different
| | 05:06 | files in the project.
| | 05:07 | If I single-click the individual files,
I'll see them open up in the editor here.
| | 05:13 | So we have some code files, some of
which might look pretty complex if you've
| | 05:17 | never seen this before.
| | 05:18 | If I like this one, ViewController.xib,
that's actually a user interface file.
| | 05:23 | So I'll get a user interface editor
with a blank canvas that seems to represent
| | 05:29 | an iPhone, which is what it does, even
with the battery bar up at the top.
| | 05:33 | Now like many other programming IDEs,
Xcode let's me write code, test code,
| | 05:38 | design interfaces all in the same app.
And like many IDEs, it lets me drag and
| | 05:44 | drop user interface elements.
| | 05:46 | Now in Xcode, the place to find
your user interface elements is what's
| | 05:49 | called the Object Library.
| | 05:51 | Now mine is open right here, but if it
wasn't, I could get to it from the View
| | 05:55 | menu, down to Utilities,
and say Show Object Library.
| | 05:59 | I am going to go through this and just find
the label, drag it across to the interface.
| | 06:06 | I should see the Plus button here.
| | 06:08 | I can position it anywhere that I want,
and then I'm going to double-click it
| | 06:12 | and just type the words "Hello World."
| | 06:15 | We will see more about how to change this later.
| | 06:18 | I could roughly click it
to select and position it.
| | 06:21 | If you see as I am dragging it around,
you can see little guideline markers on
| | 06:25 | the left, in the middle, on the
right; in the middle will do just fine.
| | 06:29 | I am going to leave it at that and then
just take my mouse up to the Run button
| | 06:33 | up here on the toolbar and click it.
| | 06:37 | What it's going to do is
compile and run our iOS application.
| | 06:42 | It's going to automatically open up
the iPhone Simulator, which is this little
| | 06:45 | cut-down version of an iPhone.
| | 06:47 | It's going to load our
program into it and run it.
| | 06:50 | So we get the remarkable words
here, Hello World showing up here.
| | 06:54 | I can actually hit the Home button on
the Simulator, jump back out onto this
| | 06:58 | simple menu, go back into my
Hello World program, and see it again.
| | 07:02 | A simple app to be sure, but it
is running in our iPhone Simulator.
| | 07:07 | So I'm going to quit out of the
Simulator and return back into Xcode.
| | 07:11 | Okay, that was easy enough,
and it was simple enough.
| | 07:15 | But you're probably starting to
form a whole bunch of questions.
| | 07:18 | We haven't even touched any code yet
but still, what do all these code files
| | 07:23 | represent? Some of them seem to
have a lot of content inside them.
| | 07:27 | Why do we have this many
code files? What do they mean?
| | 07:29 | What are the different parts of this
user interface view? What do these icons
| | 07:33 | over here represent, like
File's Owner and First Responder?
| | 07:37 | How would I hook a button up?
| | 07:39 | How is the Simulator
different from a real device?
| | 07:42 | In short, what's
immediately important, and what's not?
| | 07:45 | And we're going to get to all of this.
| | 07:47 | But what we're first going to do is
take our perspective up a level about the
| | 07:52 | best way to approach this all.
| | Collapse this transcript |
| The four pillars of iOS application development| 00:00 | A lot of people get introduced to
the world of iOS development and become
| | 00:04 | immediately overwhelmed by this massive
amount of terminology, all these tools
| | 00:08 | and technologies to learn.
| | 00:10 | You first come across Xcode and
Objective-C, but then hear terms like Cocoa
| | 00:14 | Touch, frameworks, memory management,
view controllers, delegation, MVC,
| | 00:19 | categories, versioning, push
notifications, and it's tough to figure out
| | 00:23 | what's important here, what's the right
order, what should I do first, and how
| | 00:27 | do they support each other,
| | 00:28 | and why you can't learn it by just
throwing yourself into the deep end.
| | 00:32 | What I find is a bit more useful is to
approach your application development
| | 00:37 | on the iPhone as being supported by
four pillars, four areas of content that
| | 00:42 | you need to have all together in order to
build the applications that you want to make.
| | 00:48 | The first pillar is the
tools we use to build these apps.
| | 00:52 | You're going to start off with
Xcode and the iPhone and iPad Simulator.
| | 00:56 | Now later, you will see
another program called Instruments.
| | 00:59 | You already have it.
| | 01:01 | It is part of the SDK and the instruments
will let you view and analyze diagnostics
| | 01:05 | about how well your app is performing.
| | 01:07 | The second pillar is the language.
| | 01:09 | You need to know Objective-C, and you
need to know the coding patterns, the
| | 01:14 | design patterns we use inside it, like
MVC and delegation and the supporting
| | 01:19 | frameworks that Apple provide.
| | 01:20 | The third one is the Design.
| | 01:23 | Not just making your application look
good, but how to flow through streams
| | 01:27 | correctly, how to choose the right kind
of user interface elements to create for
| | 01:32 | the right kind of application.
| | 01:33 | Because using the wrong elements the
wrong way can actually cause your app to be
| | 01:37 | rejected from the App Store.
| | 01:39 | Apple have what are called the Human
Interface Guidelines that you need to be aware of.
| | 01:44 | And just as important as all
of this is the overall process.
| | 01:49 | You're in a very formalized
process now, working with Apple's rules.
| | 01:53 | So when you're testing your app, when
you're provisioning your devices, signing
| | 01:57 | and submitting to the application store,
you need to know the process to follow.
| | 02:01 | When you keep in mind that these
pillars all need to be there to support your
| | 02:06 | application development, you can
avoid getting buried in one specific area
| | 02:10 | or neglecting another.
| | 02:12 | You can stay conscious of the whole
process, that it's not just about Objective-C
| | 02:16 | and it's not just about Xcode.
| | 02:18 | And as you learn more and more,
understand where the different pieces fit
| | 02:22 | into this picture.
| | Collapse this transcript |
|
|
2. The ToolsUsing Xcode| 00:00 | So let's get to the tools that
we use and our main one, Xcode.
| | 00:04 | We'll spend most of our time here.
| | 00:06 | Xcode is an IDE, an integrated
development environment, like Visual Studio
| | 00:11 | or Eclipse or Aptana.
| | 00:12 | And this just means it does more than one thing.
| | 00:15 | You organize your application in Xcode.
| | 00:17 | You write your code here.
| | 00:18 | You design your interfaces in Xcode.
| | 00:20 | You compile your applications there.
| | 00:22 | You use it to test and debug. You use it
to browse documentation and to find help.
| | 00:27 | But at its core, it's there to
organize all the files in your applications.
| | 00:32 | And it groups them together
into what it calls projects.
| | 00:35 | Projects are just a way of taking a bunch
of files together and giving them a name.
| | 00:39 | Now when you create a new project in
Xcode--again you can do it from the welcome
| | 00:43 | screen or from the File menu--be make
sure to select New Project, not New File.
| | 00:48 | We can start that process.
| | 00:50 | Once again, we want to have the
Application section selected under iOS,
| | 00:55 | and the one we're interested in
right now is the Single View Application.
| | 00:59 | Now this won't always be the one you want.
| | 01:01 | But while we're learning Xcode and
building straight forward iOS applications,
| | 01:05 | this is the Goldilocks
project type: it's not too complex;
| | 01:09 | it's not too simple; it's just light.
| | 01:11 | With that selected, I click Next.
| | 01:14 | Again, it asks me for the naming information.
| | 01:16 | I am going to call this one DemoXcode.
| | 01:18 | I am going to leave my Company
Identifier as com.lynda, make sure my Device
| | 01:24 | Family is iPhone, and have
everything unchecked except to Use Automatic
| | 01:29 | Reference Counting.
| | 01:31 | Click Next. It asks us
where we're going to save it.
| | 01:33 | I'm going to just select to save to my desktop.
| | 01:37 | You can put them wherever you want.
And Xcode opens properly with our
| | 01:41 | project loaded inside it.
| | 01:44 | But before we go exploring, I'm going
to go and take a look at what was just
| | 01:47 | created when we did that.
| | 01:48 | I am just going to minimize this down.
| | 01:50 | I am going to notice that here on my
Desktop, which is where I saved it, I have a
| | 01:53 | folder called DemoXcode, and
this was just created by Xcode.
| | 01:58 | If I go into this folder--and I am going to
change it, just so I can see this a little better--
| | 02:04 | I can see that I have quite a few
different files that have been created.
| | 02:08 | Opening Xcode back up, just to compare
them, I can see that some of the files
| | 02:14 | that I have in Finder match the ones in Xcode.
| | 02:17 | I have an AppDelegate.h file in
Finder. I have AppDelegate.h in Xcode.
| | 02:23 | But where I have a supporting files
folder in Xcode, I don't have one here in
| | 02:28 | the Finder. Nor do I have one
that says frameworks or products.
| | 02:32 | And that's because the folders you
see in Xcode won't exactly match the
| | 02:36 | folder on the hard drive.
| | 02:38 | Don't worry about that.
| | 02:39 | What's happening is that Xcode is
giving us more ways of grouping our files
| | 02:43 | together than just the
physical folders on the hard drive.
| | 02:47 | However, in Finder there is one
important file worth talking about, which is this
| | 02:51 | one, the one that ends in .xcodeproj.
| | 02:55 | It's the Xcode project file.
| | 02:57 | Now this is a file that contains all
the settings for this particular project.
| | 03:01 | In fact, if Xcode was closed, double-
clicking this Xcode project file would be
| | 03:05 | the quickest way to open up Xcode
with this project loaded inside it.
| | 03:10 | We're going to let Xcode manage these files.
| | 03:13 | We're not going to use Finder to do it.
| | 03:15 | But to do that, we really
need to know our way around.
| | 03:18 | So let's talk about the best way
around the Xcode for interface.
| | 03:21 | We are of course in a programming environment,
| | 03:24 | so everything is oriented around
this middle section, the editor.
| | 03:28 | Whether that's letting us edit code,
if I select a code file or whether
| | 03:32 | that's letting us edit a user interface, if I
select a file that represents a user interface.
| | 03:37 | Now, the text here is a little small.
| | 03:41 | I am going to change that in just a minute.
| | 03:42 | Up at the top of Xcode we have
this toolbar which will let me run the
| | 03:46 | application by clicking this Play
button here and select how to run it.
| | 03:50 | So I can choose to run it on the iPhone
Simulator or the iPad or an iOS device
| | 03:55 | if I have one connected.
| | 03:56 | Now this center section of the toolbar
looks a little bit like an LED display,
| | 04:01 | and it will actually show messages
about anything that Xcode is doing as we
| | 04:04 | work with our project.
| | 04:06 | It's kind of like how iTunes displays
messages when you're copying or syncing.
| | 04:10 | And over here at the top-right of the
toolbar you have two sections of three buttons:
| | 04:15 | Editor and View.
| | 04:17 | Right now the first button of Editor is
pressed in, and that means we're looking
| | 04:21 | at the standard editor.
| | 04:23 | There are different ways to
edit, but we will see them later.
| | 04:26 | Now in the second section, we have
three buttons: one with a dark left section,
| | 04:31 | one with a dark bottom section,
and one with a dark right section.
| | 04:34 | All these buttons do is toggle
sections of Xcode on and off. That's it.
| | 04:41 | Unlike some other applications, in
Xcode you don't rearrange or detach and drag
| | 04:46 | and drop different panels
from one area to another.
| | 04:49 | The layout of Xcode is the layout of Xcode.
| | 04:52 | The section that's on the left here
stays on the left. You can choose to make it
| | 04:56 | visible or not, but it stays on the left.
| | 05:00 | And this left-hand
section is called the navigator.
| | 05:03 | The navigator is our way to navigate, to
get around everything in and everything
| | 05:08 | about the project, all the files, the
settings, the configuration options.
| | 05:12 | I can expand folders that I am looking at.
| | 05:15 | And if I single-click on a file that
can be edited, it will open up in that
| | 05:20 | middle editor section.
| | 05:21 | If I double-click one of these
files, it will actually open up in a
| | 05:25 | separate editor window.
| | 05:27 | I typically use single-clicking all the time.
| | 05:29 | Now this left section actually
contains seven different navigators.
| | 05:34 | You can move between them by
clicking the buttons at the top here.
| | 05:38 | Now there's not much to see yet now in
the other navigators, but you'll be able
| | 05:42 | to view things like issues or log
messages using these different sections.
| | 05:46 | And sometimes Xcode will switch you
to a different navigator if useful.
| | 05:51 | But you don't need to memorize all of them.
| | 05:53 | You can hover over them
to find out what they are.
| | 05:56 | And note that the most important one
of the seven navigators is the Project
| | 06:00 | navigator, the first button,
the one that looks like a folder.
| | 06:04 | And a useful shortcut for this is Command+1.
| | 06:07 | That will open the Project Navigator even if,
for example, that left section is closed.
| | 06:12 | I hit Command+1, we open right back up
to this view. And it is a view not just of
| | 06:18 | all the files in your project, but
also of the project settings itself.
| | 06:23 | Clicking the top icon underneath our
different navigators will actually let me
| | 06:28 | view the top-level settings of the
project, not just one file in the project.
| | 06:32 | And having that selected, we can
say things like, what are the supported
| | 06:36 | orientations for this application,
what are my icons for the application?
| | 06:41 | And this will come in very useful later.
| | 06:43 | Now just as the left side can be turned
on or off--and I might do that because
| | 06:48 | I don't have a lot of screen real estate--the
right-hand side can be turned on or off as well.
| | 06:54 | I am going to just select a code file
to make it a bit more obvious where the
| | 06:57 | right-hand side is. Now this side
contains two different sections, what are
| | 07:03 | called Inspectors at the top
and Libraries at the bottom.
| | 07:08 | Now the arrangement of
these things is not random.
| | 07:11 | There is a point to how
everything is grouped together.
| | 07:14 | If we can think of the Navigator
section as showing everything in the project
| | 07:19 | and the Editor is showing the one thing
that I'm working on, while the inspectors
| | 07:23 | at the top of the right-hand
section are context sensitive.
| | 07:27 | Like many applications, they change based on
the file I am working on or what I have selected.
| | 07:32 | So as I select different files, you
can see the Inspectors on the right-hand
| | 07:37 | side actually change.
| | 07:39 | If I'm working on a user interface file,
they change even more significantly.
| | 07:44 | Like the navigators on the left, you
will find that the inspectors on the
| | 07:48 | right-hand side have different options.
| | 07:51 | There are several inspectors.
| | 07:53 | You can mouse over the individual ones
to find out what the inspectors are, and
| | 07:57 | again, we'll come back to these.
| | 07:59 | Now, sometimes you'll see six
inspectors, such as when editing a user interface.
| | 08:04 | Whereas if I have a code file
selected, I might only see two.
| | 08:08 | Again, don't worry about memorizing that.
| | 08:11 | It will become familiar as
you start to move through it.
| | 08:14 | And last for right now, we've got the
Libraries down at the bottom section, and
| | 08:17 | we can actually move this up a little bit.
| | 08:20 | The libraries are the simplest section,
and these do not change based on what you
| | 08:24 | have selected. So it doesn't matter
what I'm clicking on, whether it's a code
| | 08:28 | file or a user interface, we have
the same four libraries available:
| | 08:32 | File Template Library, Code Snippet
Library, Object Library, and Media Library.
| | 08:38 | These just contain collections of
things you might want to add to your project,
| | 08:42 | like having the library of user
interface element so I could drag and drop, or
| | 08:48 | a library of code snippets that I
can drag and drop into my code files.
| | 08:52 | That's the basic breakdown of the layout.
| | 08:54 | We'll get more into it as we go
through and start to create some code.
| | 08:58 | Now Xcode, like any other application,
has preferences, things you can customize
| | 09:02 | about this app to make it work better for you.
| | 09:04 | I am going to leave it pretty
much as is, straight out of the box,
| | 09:07 | but I will make two small changes.
| | 09:09 | Now you don't have to do this,
but you'll see why I'm going to.
| | 09:11 | So from the Xcode menu I select
Preferences, and I am going to do two things here:
| | 09:17 | first jump to Fonts & Colors and then I'm
going to change the theme to Presentation.
| | 09:24 | You have a whole bunch of
different options you can select from.
| | 09:27 | I am selecting presentation to
make our code a bit easier to read.
| | 09:32 | And then in my Preferences panel over
here on Text Editing, I'm also going to
| | 09:37 | select Line Numbers so that we get the
line numbers show in the Gutter here, and
| | 09:42 | that will make it easier for me to
explain which line of code I'm talking about.
| | 09:46 | Closing this down and going into one of
these code files, I can immediately see
| | 09:50 | the like most modern IDEs, we get
automatic indentation. We get color coding of
| | 09:55 | the different pieces of syntax,
showing the difference between comments and
| | 09:59 | keywords and variables.
| | 10:02 | We also get Code Sense, which is
Xcode's auto-completion feature.
| | 10:07 | If I start typing, for example, I will
start typing the letters NSR, we will see
| | 10:12 | this window starts to pop up and filter
down and as I type more information, it's
| | 10:18 | going to actually start to
bring it even closer to what I want.
| | 10:21 | I can move up and down with my cursor
keys and select a different option and
| | 10:25 | then hit Return to select it.
| | 10:28 | That helps us a lot because Objective-C
in general has a lot of very long names
| | 10:33 | for its functions and its methods.
| | 10:34 | Now, I don't actually need to use
this piece of code at the moment so I am
| | 10:39 | going to delete it.
| | 10:39 | But I'll notice already that I have
this exclamation mark popping up here on
| | 10:43 | the left-hand side.
| | 10:44 | That's because Xcode 4 will try to
highlight issues with your code as you're
| | 10:48 | typing it, and that's often a little bit
quick, and you haven't even finished a
| | 10:52 | line before it starts
complaining about that line.
| | 10:54 | But you will see that a lot.
| | 10:56 | Now, of course, there's
much more to this application.
| | 10:58 | Xcode has options to connect to source
control repositories and help you with
| | 11:03 | debugging, and it has code snippets and
ways to help you manage your projects.
| | 11:06 | But this basic layout is enough to help
us get going, because some of these other
| | 11:10 | options really aren't worth bothering
with until we've got a bit more code.
| | Collapse this transcript |
| Using the iOS Simulator| 00:00 | The iOS Simulator can work as either an
iPhone or an iPad, and is just a way to
| | 00:06 | test our applications without having to
copy all the files to a physical device.
| | 00:10 | Now, there are some things that can
only be tested with a real iPhone or iPad,
| | 00:15 | so it doesn't remove the need for
one during the process, but it's a very
| | 00:19 | convenient thing to have, and we'll
mostly be using the Simulator in this course.
| | 00:23 | You can start up the iOS Simulator by
itself, but usually you just let Xcode
| | 00:28 | launch it when you need it. And
Xcode will take care of copying over your
| | 00:32 | application to the Simulator and starting it up.
| | 00:35 | But there are a few things
to know about this Simulator.
| | 00:39 | Number one, it doesn't have a camera,
and it doesn't just use, say, a camera on a
| | 00:44 | laptop or a display.
| | 00:45 | Now, this might not be a problem, but
if your application needs to access the
| | 00:49 | camera, well, it's something to be aware of.
| | 00:51 | Now, remember, it is perfectly
legitimate for an iOS device to not have a camera.
| | 00:56 | For example, the third-generation iPod touch
will run iOS 5 but does not have a camera.
| | 01:01 | The first iPad does not have a camera.
| | 01:04 | The next thing is we don't
have a real accelerometer.
| | 01:07 | That's the part of the iPhone that
detects the position that it's being held in,
| | 01:11 | and can even detect G force,
whether it's being swung around or shaken.
| | 01:15 | Again, that might not be important
for your application, but if you have an
| | 01:18 | app that needs to be controlled by tilting,
you're going to need to use a real device.
| | 01:22 | However, built into the iOS Simulator
is the ability to change orientation.
| | 01:28 | There is a Hardware menu where you can
rotate the phone left and right and see
| | 01:33 | if your application correctly
shifts from one perspective to another.
| | 01:37 | And you can even kick off a shake gesture.
Though you don't see that being animated,
| | 01:42 | you can respond to it.
| | 01:43 | The Hardware menu is also where I can change
this to an iPad or iPhone with a Retina display.
| | 01:50 | And you can also do a couple of other
things from this, such as toggle the
| | 01:56 | in-call status bar, if you want to see
how your application is going to look, if
| | 02:01 | somebody phones while the app
is in use. Just dismiss that.
| | 02:05 | And you can also trigger
simulated memory warnings.
| | 02:08 | Other than that, it behaves quite like
an iPhone or iPad, except for the fact
| | 02:11 | that, as you can see,
there are not a lot of applications installed.
| | 02:15 | If I switch screens here, I've got my
simple Hello World application, which will
| | 02:20 | start up, but back on the main screen
there is no mail application, no music
| | 02:24 | app, no calendar, no camera.
| | 02:26 | What's quite common is you'll end up
with a lot of testing applications.
| | 02:31 | If you want to delete them, you can do
it the same way you would on a normal
| | 02:34 | iPhone, which is, you hold down until
the machine goes into the shaky mode, and
| | 02:40 | you can just delete that application.
| | 02:42 | Or alternatively, if you have quite a
lot of them, what you can also do is go to
| | 02:48 | the iOS Simulator menu and say Reset
Content and Settings, to take it back to
| | 02:54 | the original way that it was,
just the basic applications.
| | 02:57 | So while there are a few limitations
and features, one thing to be aware of is
| | 03:01 | this is not a substitute for real
performance. checking on a real device. Because
| | 03:06 | we are running the Simulator that's on
the CPU on our laptop or our desktop and
| | 03:10 | you're going to have different
capabilities on the iPhone itself.
| | 03:13 | It's very convenient.
| | 03:15 | It's often quicker to boot up the
Simulator to test an app rather than copy it
| | 03:19 | to a device, and you'll be using it a
lot as you write your iOS applications.
| | Collapse this transcript |
|
|
3. Objective-C RefresherObjective-C basics| 00:00 | As I mentioned, this course does expect
at least basic familiarity with reading
| | 00:04 | and writing Objective-C,
even if it's been a while.
| | 00:07 | If you are coming from expert-level Java
or C++ or C#, and you are thinking, how
| | 00:12 | different can it be?
| | 00:13 | Well, it is very different.
| | 00:15 | If you have not seen Objective-C
before, I highly suggest doing at least
| | 00:19 | the first few chapters of the Objective-C
Essential Training course, here at lynda.com.
| | 00:24 | These next few movies are not intended
to be enough if you are brand-new to the
| | 00:28 | language. But here is a recap of the basics.
| | 00:31 | Objective-C is a language that is not
influenced by C, or inspired by C; it is
| | 00:37 | the C programming language with
extra pieces added to it, to make it an
| | 00:41 | object-oriented language.
| | 00:42 | So the core flow of the language, if
statements, for and while loops, switch,
| | 00:48 | case, break, return, int, float, basic
operators, that's all straight C. I could
| | 00:54 | copy and paste a bunch of C code from
the 70s into an Objective-C program and
| | 00:59 | expect it to compile without any changes.
| | 01:02 | That's very different from languages
like Java or JavaScript or C# that are just
| | 01:07 | influenced by C. But why is that
important? Well because it is the reason why
| | 01:12 | Objective-C can look a little strange.
| | 01:14 | You have this newer language that's
built on top of an older language, and we
| | 01:18 | need some way to indicate which parts
are C and which are the newer Objective-C
| | 01:22 | pieces. And we have clues
by marking these new pieces.
| | 01:26 | So you'll have a lot of @ signs and
square brackets that you wouldn't find in
| | 01:30 | regular, C because these are
the added Objective-C pieces.
| | 01:34 | A specific example might be exception handling.
| | 01:37 | A lot of languages have keywords like
"try" and "catch" and "finally," but straight C
| | 01:42 | does not have these keywords.
| | 01:44 | Objective-C does, but instead,
you write @catch, @try, @finally.
| | 01:51 | These Objective-C keywords are mixed
in with the straight C keywords like "if"
| | 01:55 | and "while" and "for," and there are other
Objective-C keywords which we will see
| | 02:00 | like @synthesize, @interface,
@property to tell the compiler we want to do
| | 02:05 | things that aren't allowed in regular C.
And in the square brackets will see a lot of these.
| | 02:10 | This use of square brackets is
how we call methods in Objective-C.
| | 02:14 | So almost all of these additions are to
do with the object-orientation features
| | 02:18 | of Objective-C, the ability to have classes
and objects that straight C does not have.
| | 02:24 | Let's take a look at a real Objective-C program.
| | Collapse this transcript |
| Objective-C structure| 00:00 | I'm going to open up Xcode and
create a very simple project.
| | 00:04 | This time instead of selecting one
that's an iOS application, I'm going to come
| | 00:08 | down to the Mac OS X selection, select
Application there, and choose Command Line tool.
| | 00:13 | I'm going to make the simplest
Objective-C program possible, an old-school
| | 00:17 | command-line or console
application with no user interface.
| | 00:21 | So selecting Command Line tool, I'll
click Next. I'll call this one BasicCode.
| | 00:25 | And I want to make sure that my type
is Foundation, not Core Foundation or C,
| | 00:31 | but just Foundation. We'll talk
about what that means in a minute.
| | 00:35 | I'm going to leave Use Automatic
Reference Counting checked, as we're going to
| | 00:39 | do with every project in this course.
| | 00:41 | Click Next and then we'll choose
where to save it. I'm just going to save it
| | 00:44 | out to my Desktop again. And we have a
simple Objective-C command-line project.
| | 00:50 | I've got several files over here in my
Project Navigator, but only one that's
| | 00:55 | important. We're looking for
Objective-C, and we'll find it in .m files.
| | 01:00 | We've got one here called
main.m, and let's take a look at it.
| | 01:04 | Well, from line 1 through 7 we have
comments. They are of course C style. Two
| | 01:08 | forward slashes makes the line of
comment and Xcode makes it show up in green.
| | 01:12 | On line 9 we have this #import,
and that's pointing to the foundation
| | 01:17 | framework header file.
| | 01:18 | Now that doesn't cause anything to
happen in our program, but it's telling the
| | 01:22 | compiler that yes, this code that I'm
about to write can use the foundation
| | 01:27 | framework and anything inside it.
| | 01:29 | Now frameworks are simply collections
of prewritten code that have been bundled
| | 01:32 | up and given a name, and the foundation
framework is the most common Objective-C
| | 01:37 | framework, and we always use it.
| | 01:39 | Now next, to line 11. As in C, Java, C#,
C++, to run an Objective-C program that
| | 01:46 | might be thousands of lines across
dozens or hundreds of files of Objective-C,
| | 01:50 | it needs to know where to start.
| | 01:52 | Objective-C expects somewhere in your
code that there is a function called main, and
| | 01:56 | that's where all Objective-C programs begin.
| | 01:58 | Now if you're curious, yes, that is
still the case with iOS projects, and
| | 02:03 | there is a main.m file in all your iOS
projects, although you typically won't
| | 02:09 | ever need to touch it.
| | 02:10 | It's considered a supporting file,
not one you need to edit, because it
| | 02:14 | already contains the code to stop the
lifecycle of an iOS program, but yes,
| | 02:18 | it always will be there.
| | 02:20 | main of course is written lowercase.
Objective-C is a case-sensitive language.
| | 02:25 | Very important to remember if you're
coming from a case-insensitive language.
| | 02:29 | Now this first line on line 14 inside
main, is @autoreleasepool,
| | 02:35 | and that's an Objective-C keyword
to do with memory management.
| | 02:38 | We'll explore this more later on.
For now, we can just let it pass.
| | 02:41 | So, on line 17, we pretty much have the
one line that actually does anything here.
| | 02:46 | This is an output message using the
function NSLog, which is part of that
| | 02:51 | foundation framework we're linking to on line 9.
| | 02:54 | The letters NS stand for next step
and this is part of the next computer's
| | 02:59 | legacy that's hugely
impactful in Apple development.
| | 03:02 | NS is one of the most common things
you'll type in Objective-C, and it's always
| | 03:07 | written in uppercase, as is the following letter.
| | 03:10 | So we're going to write a Hello, World!
| | 03:12 | string out to the console.
| | 03:14 | In Objective-C, we don't just use
double quotes, because that would make a C-
| | 03:18 | style character array.
| | 03:20 | Instead, we put an at sign before this,
which turns this into an Objective-C-
| | 03:25 | style NS string object. It's a true
object with methods and properties we could
| | 03:30 | access, instead of just an array of characters.
| | 03:33 | Now Objective-C is not whitespace
sensitive, so it doesn't really matter what
| | 03:38 | kind of white space or tabs you
put here, whatever makes it readable.
| | 03:42 | The only place it does matter are of course
spaces inside a string, which are impactful.
| | 03:48 | I could go ahead and just run this
directly. If you wanted to be a bit
| | 03:52 | more specific about this, we could go to
the Product menu and come down and say Build.
| | 03:57 | Build is the term we use here that
other languages might say compile. We are of
| | 04:01 | course compiling and linking
and creating an application here.
| | 04:04 | I saw the message Build Succeeded.
| | 04:06 | I can also see that in the little LED-
style display up on the top of the toolbar
| | 04:11 | here, and I could just go ahead and run this.
| | 04:15 | We don't get an amazing amount of
information; what I do get here is the third
| | 04:19 | section that we can turn on or off
an Xcode, which is this Debug area.
| | 04:24 | I can toggle that on or off
by this button on the toolbar.
| | 04:27 | This itself, as we'll see, is useful for
debugging information that's split into
| | 04:32 | two main panes, and you can use the
similar buttons here to decide which parts
| | 04:36 | of it you want to actually show.
| | 04:38 | So, just outputting the messages here,
I can see that I've got my Hello, World!
| | 04:43 | from the NSLog message. And
this is the basic structure on an
| | 04:47 | Objective-C program.
| | 04:49 | Now that's as simple as it possibly gets,
but we're not doing much with objects
| | 04:54 | in this example, and we're in an
object-oriented language, so that's up next.
| | Collapse this transcript |
| Creating variables| 00:00 | Let's just recap basic variable creation.
| | 00:03 | In Objective-C we create simple
primitive variables as in many other languages.
| | 00:08 | We use the data type--in this case I'll
have int--and a space, then the name of the
| | 00:14 | variable--I'll call it minutes--and
then you can just use a semicolon to finish
| | 00:17 | this off, or of course use the equals
sign to actually give it a value while
| | 00:22 | you're declaring it.
| | 00:23 | I'll create a couple
more integer variables here.
| | 00:29 | Now as I'm typing, what you're
probably seeing is over in the gutter section
| | 00:33 | here, I've got these little pop-up
warning messages and if I click any of them,
| | 00:38 | it'll tell me what is the detecting,
which in this case is its unused variable.
| | 00:42 | Well, that is correct. I haven't
actually had a chance to use it yet, so I'm
| | 00:46 | going to ignore that warning for now,
but it's always good practice to get into
| | 00:50 | to figure out exactly
what it's complaining about.
| | 00:52 | Now we have the usual suspects: ints,
floats, unsigned and signed. We have charge.
| | 00:58 | We also have a Boolean variable type,
| | 01:00 | although that's a little unusual.
It's uppercase for BOOL. When we name it
| | 01:06 | we typically use the Pascal casing or
Camel casing in Objective-C, but the value
| | 01:11 | of a Boolean variable is not true or
false as it is in many other languages, but
| | 01:16 | instead yes or no, and these
must be written as all uppercase.
| | 01:26 | We can of course create variables based
on calculations of other variables and
| | 01:31 | so on. And if we want to take some of
these variables and output them in our log
| | 01:36 | messages, we can use C-style format strings.
| | 01:40 | What that means is we can construct a
message, such as this one, where we have a
| | 01:48 | placeholder format that represents a
value that will be filled in at runtime.
| | 01:52 | We can have percent sign I for an
integer, percent sign f for a floating-point
| | 01:56 | variable, percent sign c for single characters,
percent sign at sign for objects, and so on.
| | 02:02 | What I need to do is follow the
closing quote of that string with a comma and
| | 02:06 | then the variable that I want to fill in
here, which in my case is minutes in a year.
| | 02:11 | As I start typing, I get code sense
come up. I select what I want hit Return.
| | 02:16 | I'm just going to tuck the right-
hand side out of the way here, so I can
| | 02:19 | view this more easily.
| | 02:21 | And the only thing it's now
complaining about is line 20, that I'm declaring a
| | 02:25 | Boolean variable, which I'm not using.
That's what it's complaining about.
| | 02:29 | So I could just comment that out.
| | 02:31 | Warnings won't stop my program from
compiling, it won't stop it from running,
| | 02:35 | but it's always good practice to be aware of
exactly any issue that's happening in your code.
| | 02:40 | If I wanted to build this before I ran
it, I can do this from the Product menu,
| | 02:45 | or I can just select Command+B. I get
Build Succeeded, no issues and then no
| | 02:50 | surprise, I could run it either by
pressing the button up here or hitting
| | 02:53 | Command+R. Now I had manually hidden at
the lower section all Xcode, so I'm going
| | 02:59 | to manually turn it back on. And it
saying here that yes, there are 52,560 minutes
| | 03:05 | in a year, which sounds about right.
| | 03:07 | Again very basic stuff; we're creating
and using simple primitive variables. But
| | 03:13 | objects are going to be a little different.
| | Collapse this transcript |
| Using pointers| 00:00 | So there is a key difference when
creating simple primitive variables as to when
| | 00:04 | we're creating objects.
| | 00:06 | In Objective-C, all objects are accessed
using pointer types, using the asterisk
| | 00:11 | when we're declaring the variables.
| | 00:13 | If you want to explicitly make a
variable that represents an object, even from
| | 00:17 | a simple class like NSString, that
variable is a pointer type. So we use that
| | 00:22 | asterisk every single time that we make a
variable that represents a pointer to an object.
| | 00:27 | Now here is the key difference
between needing one and not needing one.
| | 00:31 | When you create a simple integer
variable using, say, int highscore=100, the
| | 00:37 | variable is holding that value directly.
| | 00:40 | It holds 4 bytes, and it
holds the value of that integer.
| | 00:43 | However, when you create an object variable,
the variable does not hold the object itself.
| | 00:49 | It does not hold the contents of the
object, in this case the word Hello;
| | 00:52 | instead it holds an address, a
reference, a pointer. That variable points to a
| | 00:59 | different area of memory
where that object exists.
| | 01:02 | Now you don't need to know exactly
what that address is--with Objective-C it
| | 01:06 | doesn't matter--but you do need
to know that that's what happening.
| | 01:10 | So when declaring pointer variables,
you can put the asterisk anywhere.
| | 01:14 | It's most common to see it right
before the name of the variable.
| | 01:19 | But it's not part of the variable name.
| | 01:21 | You could put it in between with spaces
or even right by the class name itself.
| | 01:26 | The asterisk is not part of the variable name.
| | 01:28 | We're not making a variable called
asterisk message. The variable is called
| | 01:32 | message and it is a
pointer to an NSString object.
| | 01:36 | Now this is the way that most object-
oriented languages work with pointers. Even
| | 01:41 | languages like Java and C# work this way;
| | 01:44 | they just hide the asterisk away.
| | 01:46 | In Objective-C it's explicit.
| | 01:48 | All objects are accessed
using explicit pointer types.
| | 01:52 | Now can this get a bit more involved?
| | 01:54 | Well, like everything else
in programming, of course.
| | 01:56 | We can have pointers to
pointers. We can de-reference pointer.
| | 01:59 | We can arrays of pointers.
| | 02:01 | We could find out the actual memory addressm
though that's rarely necessary in Objective-C.
| | 02:05 | If you new to explicitly working with
pointers, do realize they're not likely to
| | 02:10 | feel comfortable until you've made a
bunch of them, created themm and used them.
| | Collapse this transcript |
| Sending messages and calling methods| 00:00 | So we are in Objective-C, an object-
oriented language, and most of the code that
| | 00:04 | we are going to write or use will be
contained inside classes. We will create
| | 00:09 | objects based on those classes, and we
will tell those objects to do things.
| | 00:13 | We will call methods of those objects.
| | 00:15 | If I were to show you a few of the
classes that we have available to us, because
| | 00:19 | Apple has written them already,
that might include something like the
| | 00:23 | AVAudioPlayer class.
| | 00:25 | This is an existing class that has
methods like play and pause and stop and the
| | 00:30 | kind of things you can probably guess
an audio player would have, and we can
| | 00:33 | create an object of this
class and call those methods.
| | 00:36 | But even NSString, our basic string
object in Objective-C, has plenty of methods.
| | 00:42 | It has dozens, and if we have an
NSString object, we have methods like
| | 00:46 | lowercaseString and
uppercaseString and hasPrefix and hasSuffix.
| | 00:51 | We can do all sorts of
things with that string object.
| | 00:54 | And when it comes time to creating
your own classes, we can write things, say,
| | 00:57 | like a BankAccount class, and we could
have methods like deposit and withdraw
| | 01:01 | and open and close.
| | 01:02 | So it's how we are describing
what it is these classes can do.
| | 01:06 | Now this of course is common object-
oriented stuff, but the question is, well,
| | 01:10 | how do we call these methods in
Objective-C? Because that is a little different
| | 01:15 | than most other languages.
| | 01:16 | In most languages, you would call a
method by using something called dot syntax.
| | 01:21 | You'd use the name of the object, dot,
then the name of the method, and then any
| | 01:26 | parentheses that would say, does
this method take any arguments in?
| | 01:31 | This is not going to work in Objective-C.
| | 01:34 | We don't use dot syntax in
Objective-C to call methods;
| | 01:37 | we use square brackets.
| | 01:39 | Square brackets is one of those
indicators to the compiler that this is
| | 01:43 | Objective-C, not regular straight C.
| | 01:46 | So in this case, we are sending a message here.
| | 01:48 | We are sending the message some
method to the object, myObject.
| | 01:53 | It's all enclosed in square brackets, and
there is no dot between the object name
| | 01:57 | and the method name.
| | 01:58 | Now some developers get really weirded
out by the square brackets, but it is
| | 02:02 | just a syntax change.
| | 02:04 | It's a slight change. The concept is
the same, but let's take it a little step
| | 02:08 | further: What happens if
this method returns a value?
| | 02:12 | Well, if you are familiar with dot syntax,
you'd expect to write something like this.
| | 02:16 | You would have a receiving variable
called result and set it equal to whatever
| | 02:20 | comes back from myObject.someMethod.
| | 02:22 | It's exactly the same in Objective-C.
| | 02:25 | You just replace the dot syntax with
the square brackets and call it that way.
| | 02:30 | But if that method returned a
value, this would work just fine.
| | 02:34 | Now moving on one more step, what happens if
you want to pass an argument into that method?
| | 02:39 | So the method has been defined with
parameters. We are passing arguments into it.
| | 02:44 | While in dot syntax, you would typically
put the argument inside the parentheses,
| | 02:49 | Object.method and in parentheses the
arguments. And the concept is the same in
| | 02:55 | Objective-C, but instead of
the parentheses we use a colon.
| | 02:59 | So it's object name, space, method
name, colon, argument, all within the square
| | 03:05 | brackets, and that's how we
pass an argument into that method.
| | 03:08 | Now next up is where it
gets a little bit more complex,
| | 03:11 | if we have multiple arguments--because
that is the first-place where it is quite
| | 03:16 | different. And giving me analogy again
of the dot syntax way, you'd pass in
| | 03:21 | multiple arguments separated by
commas inside the parentheses.
| | 03:26 | Well, that's not going to work in Objective-C.
| | 03:28 | The big difference in Objective-C is
that if you have a method that takes
| | 03:32 | multiple arguments, the method name
becomes split apart into multiple pieces;
| | 03:37 | the actual name of the method changes.
| | 03:40 | So let me show you an example.
| | 03:42 | This is a real method
that's available in Objective-C.
| | 03:45 | It is the method insertString atIndex.
| | 03:49 | More properly, it's read as insertString:
| | 03:52 | atIndex. And the way we would write it
is we'd use the object name--in this case
| | 03:57 | myObject--then the first part of
the method name, which is insertString:,
| | 04:01 | and the first parameter, then a
space, then the second part of the method
| | 04:05 | name, which is atIndex:
and the second parameter.
| | 04:09 | So the actual method name is different.
| | 04:12 | Each argument represents a
different piece of the method name.
| | 04:15 | And what this leads to is something
that Objective-C is notorious for,
| | 04:19 | particularly when people are new to
it, which is method names that are
| | 04:22 | really, really long.
| | 04:25 | Because what this means is any method
name that takes multiple parameters has to
| | 04:29 | be defined to have multiple parts to
the name of it. And that leads us to, for
| | 04:33 | example, a real method called
replaceItemAtURL: withItemAtURL:
| | 04:39 | backupItemName: options: resultingItemURL:
| | 04:44 | error. And yes, that doesn't exactly
roll off the tongue, and you will find in
| | 04:48 | Objective-C and in some of the classes
that Apple provide, there's ones they are
| | 04:53 | even bigger than that.
| | 04:54 | Now I am not going to even
attempt to read this one.
| | 04:56 | And the big benefit of this is even
though it can give you a lot more code to
| | 05:01 | read--and you can of course split the
single method call across multiple lines to
| | 05:06 | become more readable--well your code
becomes more understandable in an actual
| | 05:10 | program, because instead of a smaller
method call where you are passing multiple
| | 05:15 | parameters, all squeezed into one set of
parentheses, but you don't really know
| | 05:20 | what those parameters are, they
are all named here in your code.
| | 05:23 | It's obvious what they are, and that's
one of the benefits of having a really
| | 05:26 | long method names in Objective-C.
| | 05:28 | And most of the developers I know that
have spent some time with Objective-C,
| | 05:32 | including myself, actually begin to
prefer it this way, because while it makes
| | 05:36 | for a longer writing of code and
figuring out what those methods are, it makes
| | 05:40 | for much more readable and
maintainable code after the fact.
| | 05:43 | Now the final piece here.
| | 05:45 | Yes, we can have nested method calls,
just as in dot syntax, where you could
| | 05:50 | instead of passing in an argument
directly, you could just put in a call to
| | 05:55 | another function or method.
| | 05:56 | Well, you can do the same thing in
Objective-C. Instead of the standard
| | 06:00 | Objective-C way where I have been using
the argument after the colon, we can add
| | 06:06 | another set of square brackets
and nest one call inside another.
| | 06:11 | The interior one will be evaluated first,
in this case calling another method of
| | 06:16 | another object, and the result of that
will be fed into the exterior one, the
| | 06:21 | myObject someMethod call.
| | 06:23 | So while the syntax is different and
can take a little bit of getting used to,
| | 06:27 | the concepts are exactly the same as
in other object-oriented languages.
| | Collapse this transcript |
| Creating objects| 00:00 | NSString is an easy class to use when we
are talking about the left-hand side of
| | 00:05 | the equals sign. We are talking about
creating the variable, the pointer that
| | 00:08 | points to an object, but we
haven't really talked about the other half.
| | 00:12 | What actually happens when we create an object?
| | 00:15 | Now here, I'm just using the
Objective-C that means I want an NSString object
| | 00:19 | with the world Hello in it, using that
at sign in front of a double quotes, but
| | 00:24 | usually there is a bit more
to object creation than this.
| | 00:27 | I am going to show the more typical way
of doing it by creating an NSDate object.
| | 00:32 | NSDate is another class defined in the
foundation framework, and we use it a lot.
| | 00:37 | Now to create an object in
Objective-C, we have two explicit stages.
| | 00:43 | The first stage is allocation, and what
this means is Objective-C is going to go
| | 00:48 | out to an area of memory and carve out
a space big enough to hold this object.
| | 00:53 | It does that when we call the
alloc method of the NSDate class.
| | 00:58 | And then it's returning the address
in memory of that object, which is what
| | 01:02 | this pointer variable myDate will hold.
| | 01:05 | So I now have a myDate that
represents a pointer to an NSDate object.
| | 01:10 | And I can use that pointer to do the
second part of creating an object, which is
| | 01:15 | initialization, where it's going to go
through the object, figure out what it's
| | 01:20 | made of, and initialize variables internally.
| | 01:22 | Now initialization could
be really, really simple.
| | 01:25 | It could be really complex.
| | 01:27 | It depends on how complex
the class definition is itself.
| | 01:30 | But these are the two stages of actually
having an object allocated and initialized.
| | 01:35 | And because this is such a common thing
to do, you typically don't see it spread
| | 01:39 | across two lines because you don't have to.
| | 01:42 | You can nest one inside the other.
| | 01:45 | We have the internal call to the alloc
method of the NSDate class, and that will
| | 01:50 | return an instance of NSDate,
and then we call init on that.
| | 01:54 | And you'll see this all over the place,
| | 01:56 | this general pattern of allocation and
initialization: Class alloc init, Person
| | 02:02 | alloc init, Dog alloc init, Customer alloc init.
| | 02:05 | However, as with other languages, you
don't always want to just create and
| | 02:09 | initialize an object the same way;
sometimes it's nice to pass in some
| | 02:13 | information when it's being created.
| | 02:15 | And that's what init is really for,
because you can have custom initializers.
| | 02:20 | Instead of just the straight init
method, we often have a bunch of methods
| | 02:24 | that start with init.
| | 02:26 | So we might have a method called
initWithName that we can pass in a name and
| | 02:31 | make sure that when our class is allocated
and initialized it's initialized with some data.
| | 02:35 | An example of this for NSSting is that
NSString has an init with contents of
| | 02:41 | file, an init with contents of URL.
| | 02:44 | We can just give it some contents
to start initializing that string.
| | 02:48 | The NSDate object has an init with the
time interval since 1970 that just expects
| | 02:53 | some seconds to be passed into it.
| | 02:55 | There are often multiple ways to control
the allocation and initialization of an
| | 02:59 | object apart from just alloc init.
| | 03:02 | Now, before iOS 5 came along in late 2011,
creating your object was only half of the picture.
| | 03:10 | You had your alloc and init, and then
you would use that object, call methods on
| | 03:16 | it, use it, pass it in and out of other objects,
| | 03:19 | but you also had to be explicit about
when you were finished with that object,
| | 03:24 | so that the memory could be reused.
| | 03:26 | You had to issue retain and release calls
to say when you were done with that object.
| | 03:32 | But with the arrival of Automatic
Reference Counting in iOS 5, we don't have
| | 03:38 | to worry about that.
| | 03:39 | We'll talk about that next.
| | Collapse this transcript |
| Understanding Automatic Reference Counting (ARC)| 00:00 | Automatic Reference Counting, or ARC, is
a developer feature that was added with
| | 00:05 | iOS 5 and Xcode 4.2 in the late 2011.
| | 00:08 | And I'm going to talk about it here
because in my original Objective-C course
| | 00:12 | ARC did not yet exist, but
here's the great thing about it:
| | 00:16 | ARC is not yet another thing to think
about, something else you have to learn;
| | 00:21 | it's actually something less to think about,
| | 00:23 | something less to worry about,
because Automatic Reference Counting is not
| | 00:27 | something you do as a developer.
| | 00:29 | It's something the compiler does.
| | 00:31 | You don't have to become an expert on
ARC; you just need to know what it is so
| | 00:36 | that you can let it make your life easier.
| | 00:38 | ARC means you will write less code and
the code that you won't have to write
| | 00:43 | anymore is the tedious code
you didn't want to write anyway.
| | 00:46 | So Automatic Reference Counting is all
about simplifying memory-management code.
| | 00:51 | This is the most difficult, the most
tedious, the largest cause of bugs in any
| | 00:55 | Objective-C program.
| | 00:56 | And if you learned Objective-C
prior to ARC, you know we use reference
| | 01:00 | counting in this language.
| | 01:01 | We create objects using alloc
and init or other variants of that.
| | 01:06 | Those objects have a retain count on them.
| | 01:09 | We use the object, and then we better
take care of releasing that object once
| | 01:14 | we're done so that memory
can actually be reclaimed.
| | 01:17 | Now with one object in three lines
of code this is not a huge problem.
| | 01:22 | But when you have dozens, hundreds,
thousands of objects being created,
| | 01:26 | manipulated, and passed around,
you have to keep track of them all.
| | 01:30 | You'd have to call retain on an object
when you pass it around so they don't get
| | 01:34 | released too soon and match that
with a release call as soon as possible.
| | 01:39 | You really have to envision every
possible path through the logic of your app,
| | 01:43 | so that the lifetime of your
objects can be managed correctly.
| | 01:46 | And this is very difficult to do.
| | 01:48 | There is multiple ways it can go wrong,
the two classics being that you create
| | 01:53 | an object, you use it, and
then you release it too soon.
| | 01:57 | You have something
referred to as a dangling pointer.
| | 02:00 | Try and use that after you've
released it and you can crash your program.
| | 02:04 | On the other hand, if you create an
object and you release too late, or you
| | 02:09 | don't release at all,
| | 02:10 | you are then leaking memory.
| | 02:13 | And the bigger your apps
get, the harder this gets.
| | 02:16 | The memory-management code is the
main reason why a lot of people give up
| | 02:20 | learning Objective-C.
| | 02:21 | It's the main reason apps take longer
to develop or don't get finished at all.
| | 02:25 | It's the main reason that finished
apps crash, which itself is the main reason
| | 02:28 | why apps are rejected from the App store.
| | 02:30 | But with ARC, the question of when to
retain and when to release pretty much goes away.
| | 02:37 | You don't write release calls anymore.
| | 02:40 | You don't write retain calls anymore.
| | 02:42 | You don't think about it.
| | 02:43 | You create your objects as usual with alloc
and init, and you just use them. That's it.
| | 02:49 | ARC takes care of cleaning
things up. Because here's the thing:
| | 02:53 | it's not that the idea of retain and
release calls have disappeared--it hasn't--
| | 02:58 | Objective-C still uses reference counting.
| | 03:02 | The difference is you don't write the retain
and release calls anymore, the compiler does.
| | 03:08 | ARC takes the fact that compilers have
gotten so good that anytime you build
| | 03:12 | your project, the compiler--in this
case LLVM 3.0, which is what Xcode uses
| | 03:17 | behind the scenes--is able to scan
through your code, determine all the
| | 03:21 | possible pass through it, figure out
where your objects are being used and
| | 03:24 | where they're not, and synthesize the
retain and release calls at the best
| | 03:28 | point in the program.
| | 03:29 | The compiler is effectively generating
the same code you would write yourself if
| | 03:34 | you were really, really good at
writing memory-management code.
| | 03:37 | Okay, you won't actually see these lines, so
| | 03:39 | it doesn't physically change your
source code files, but this is effectively
| | 03:43 | what it's doing when you compile a project.
| | 03:45 | So with ARC turned on--and yes, you
can turn it off, but it is on for new
| | 03:49 | projects by default in Xcode 4.2--
| | 03:52 | you never need to write a release call
again, never write a retain call again, or
| | 03:56 | an auto-release call.
| | 03:58 | You'll never have to create a dealloc
method that's simply full of code to release
| | 04:01 | all the instance variables in an object.
| | 04:03 | That just goes away.
| | 04:05 | Well, not only do you not write this code,
with ARC turned on, you can't write this code.
| | 04:11 | You try and write a simple release
call and the compiler will reject it and
| | 04:16 | make you take it out.
| | 04:18 | So for most existing iOS developers,
learning ARC is simply learning what
| | 04:23 | you don't do anymore.
| | 04:25 | And in fact you could take what I've
told you in the past few minutes and just
| | 04:26 | make a new project and run with it;
you're good to go. That's it.
| | 04:31 | Okay, there are a few
other pieces worth knowing.
| | 04:35 | Later in the course, I'm going to talk
about some extra things about ARC that
| | 04:36 | might be useful and some gotchas to
know about, but you now know the impact
| | 04:42 | of day-to-day use of ARC, which is pretty much,
don't worry about these retain and release calls.
| | 04:45 | Create your objects, use them, you're done.
| | 04:48 | And I find the best thing about ARC is
that it lets you concentrate your mental
| | 04:52 | effort on your actual problem, on the
interesting stuff about your app, instead of
| | 04:56 | the headaches of my memory management.
| | 04:58 | ARC is really good at this, and you
should be using it in every Xcode project
| | 05:03 | you ever create from now on.
| | Collapse this transcript |
| Using existing classes| 00:00 | One of the challenges when you're still
fairly new to Xcode and to Objective-C
| | 00:04 | is finding out what's available, finding
the right classes, finding the methods.
| | 00:09 | Let's take a look at how.
| | 00:11 | I'm going to go ahead and just
create another simple Xcode project.
| | 00:14 | This will be a Mac OS X
application, and again a command-line tool.
| | 00:18 | I'll call it ExampleClasses, and I'll
make sure that it's a type of foundation,
| | 00:23 | and that yes, we Use
Automatic Reference Counting.
| | 00:26 | Clicking Next I'll just save
it to my Desktop and create it.
| | 00:30 | Now we've only got one Objective-C
file over here, main.m, so I'll select that
| | 00:35 | because here's where we can write some code.
| | 00:37 | Now we've already worked with things
like NSStrings and NSDates, and hopefully
| | 00:41 | quite a few more, but if I hadn't
done anything with them, how would I find
| | 00:45 | information about this?
| | 00:46 | Well, we've already seen
that as we start to type,
| | 00:48 | we've got CodeSense,
| | 00:49 | this automatic code completion that
helps me find classes and it helps me
| | 00:54 | find the different names.
| | 00:56 | And it is a good thing, particularly if
you don't remember the case sensitivity
| | 01:00 | as CodeSense doesn't care.
| | 01:01 | I can start typing another S and an S,
now I'm actually typing lowercase, but
| | 01:06 | it's showing me whatever matches. And it
will correct it if, for example, I then
| | 01:10 | type a T and an R and an I,
and yes, NSString is what I want.
| | 01:15 | I hit Return and I have
the correct casing for that.
| | 01:17 | I'm going to create something very simple here.
| | 01:23 | Because I'm not actually interested in
the contents of the string object. I'm
| | 01:28 | just interested in the fact I have a
string object at all, and I want to find
| | 01:32 | out what it is and what it can do.
| | 01:35 | So if I want to find out what's
available to me I have two options.
| | 01:38 | One is if I have the Utility section
on the right-hand side open--and I can
| | 01:43 | just toggle that on and off over here--
that if I click anywhere in the class
| | 01:46 | name NSString and I have the wavy lines
selected up here, this is the Quick Help section.
| | 01:52 | And it will show me an introductory
paragraph where it's declared, point me
| | 01:56 | to the NSString Class Reference.
| | 01:58 | I've got point just to the
String Programming Guide and so on.
| | 02:02 | I mean you want to get comfortable
with looking up class references, so I'm
| | 02:05 | going to click NSString Class Reference.
| | 02:08 | It's going to open up this other
window of Xcode, the Organizer window, which
| | 02:12 | is actually taking me to the
Documentation section and to the NSString Class
| | 02:17 | Reference, and there is a lot of
information when you look in the Reference library.
| | 02:21 | But what we can do is start to come
down here, start to read about the
| | 02:25 | string object, understanding characters,
and sub-classing notes, and all sorts of stuff.
| | 02:30 | But what we're really probably mostly
interested in are the different tasks we can do.
| | 02:34 | In Creating and Initializing Strings, I
can see that I have options for Creating
| | 02:39 | and Initializing a String from a File,
Creating and Initializing a String from a
| | 02:43 | URL, Getting the Length of a String,
Writing to a File or a URL. There is whole
| | 02:48 | bunch of stuff going on here.
| | 02:50 | In any one of them I can take a look,
say, in the Changing Case section and find
| | 02:55 | something like this Lowercase String
and click that to find a bit more about
| | 02:59 | that particular method.
| | 03:00 | It tells me it's a method called
lowercaseString that will return a pointer
| | 03:06 | to an NSString object, and the dash
at the start of it is telling me that
| | 03:10 | this is an instance method.
| | 03:11 | It needs an instance of the NSString
object to work on, which is what I have.
| | 03:16 | So what else could we do?
| | 03:17 | Well, let's say we are working with a
different kind of object, maybe one we're
| | 03:20 | not so familiar with like, NSDate.
| | 03:23 | Also notice as I'm typing here that
I have a bunch of different options
| | 03:27 | in different letters in the
CodeSense we have Ks and Ts and Vs and a C,
| | 03:32 | which represents a class.
| | 03:34 | So NSDate, this is fine.
| | 03:36 | It represents a class.
| | 03:37 | We're making an object, so I need a pointer.
| | 03:39 | I'll just call it myDate.
| | 03:41 | Now I'm thinking well, now maybe I
don't know what to do, because I can't just
| | 03:45 | create a date and use say that @ sign and the
string. Maybe I don't know how to create a date.
| | 03:50 | So again I could select this by
selecting NSDate and over here in Quick Help,
| | 03:56 | I can see some more information.
But let's say Quick Help isn't open.
| | 03:59 | Another option I can do, and I'm very
fond of this one is holding down my Option
| | 04:04 | key on the keyboard.
| | 04:05 | I can hover over different class
names, and you'll see it turned into a hand
| | 04:09 | symbol with a question mark.
| | 04:11 | I can click that and get this little pop-
up of a NSDate, introductory paragraph,
| | 04:16 | where it's declared, Class Reference,
Date and Time Programming Guide. Again the
| | 04:21 | Class Reference is what I immediately need.
| | 04:24 | Coming down, there's a lot
of information about it.
| | 04:26 | What I'm really most interesting in is the
tasks, Creating and Initializing Date Objects.
| | 04:31 | I have several options here, but the
first one is just Date, so I'll click
| | 04:35 | that and take a look.
| | 04:36 | It says this Creates and returns a new
date set to the current date and time.
| | 04:41 | That looks about right, and in fact it
even gives me a little code sample here
| | 04:45 | that I could highlight and copy.
| | 04:47 | By going back up a little bit, notice
that all of these methods begin with
| | 04:51 | either a Plus sign or a Minus sign.
| | 04:54 | Now if you coming from something like
C# or Java, you'll be forgiven for
| | 04:58 | thinking that this might mean
public or private, but it doesn't.
| | 05:01 | And the Minus sign, which is much more
common with most classes, means these
| | 05:06 | are instance methods.
| | 05:08 | You will call these methods using an
instance of a class, an object which
| | 05:12 | already needs to have been created.
| | 05:13 | Whereas the Plus sign means that these
are class methods, so I use the name of
| | 05:19 | the class, like NSDate to call this.
| | 05:22 | So, for example, in this case, pasting
any code that I've just copied, we're
| | 05:26 | calling the date method of the NSDate class.
| | 05:30 | This is a class-level method.
| | 05:33 | But as I've just created an instance, I
could now use the instance to call any
| | 05:38 | of the instance-level methods, such as
dateWithCalendarFormat. And CodeSense of
| | 05:43 | course will help me fill this out with the
different parameters that this method needs.
| | 05:48 | Now I don't actually need to do
that right now, so I'm just going to go
| | 05:50 | ahead and delete it.
| | 05:52 | But of course there are other ways to
go through documentation and get help.
| | 05:56 | These are very too quick, very easy ways
to find the methods and the tasks and
| | 06:01 | the classes that are
available to you using Objective-C.
| | Collapse this transcript |
| Creating custom classes and methods| 00:00 | In Objective-C, classes are written
in two separate sections, an interface
| | 00:06 | and an implementation.
| | 00:07 | The interface is the simplest part.
| | 00:09 | This is the public face that the class
is presenting to the world, or at least to
| | 00:14 | other parts of your application.
| | 00:16 | It's announcing what this class is
promising to do, what methods, what
| | 00:20 | properties are available.
| | 00:22 | It doesn't say how any of them are done;
| | 00:24 | it just says what's available.
| | 00:26 | Now the second part, the
implementation, that's where the work is done.
| | 00:30 | The implementation must live up
to the promises of the interface.
| | 00:34 | The implementation is
the main code of the class.
| | 00:37 | So here is how we do it.
| | 00:39 | I am just going to jump over to Xcode,
where I'm going to make another very basic
| | 00:43 | Command Line tool application, just
call this CustomClasses, and make sure to
| | 00:49 | select a foundation type and then
Automatic Reference Counting is on.
| | 00:53 | I will save this again to my desktop.
| | 00:56 | So I want to create a new class, and
there is a couple of different ways to
| | 01:01 | do this, but the most basic is going up to
the File menu in Xcode and saying New File.
| | 01:06 | Just as we have templates for projects,
we have templates for files as well, all
| | 01:12 | sorts of different ones, but what I'm
interested in here is Objective-C class,
| | 01:17 | and I'm selecting that in the
Cocoa section under Mac OS X.
| | 01:21 | I will click Next, and it's going to
ask, what do you want to call this?
| | 01:25 | Now classes should begin as a
rule with an uppercase letter.
| | 01:28 | It's one of the few things that does
begin with an uppercase letter in Objective-C.
| | 01:32 | So I am going to create a
new class called Player.
| | 01:34 | Now this dropdown is asking,
what is this class a subclass of.
| | 01:39 | Depending on which object-oriented
language you are used to, you might be
| | 01:43 | thinking of this as your
parent class or your base class.
| | 01:46 | But what we are asking is is there an
existing class out there that this new
| | 01:50 | one should be based on?
| | 01:52 | And we have a few choices, but yes,
we are always going to inherit from at
| | 01:56 | least one other class, and the default one
that we are going to inherit from is NSObject.
| | 02:00 | In fact, every class you are ever going
to work with within Objective-C ends up
| | 02:05 | inheriting from NSObject.
| | 02:07 | It's the base class, the super class,
the parent at the top of the tree, the
| | 02:12 | very top class, and it
will work just fine for us.
| | 02:15 | So I click Next, and it's going to ask, do I get
added to this project folder? Yes, that's fine.
| | 02:21 | So I will just Create, and it creates
two classes for me that I can see over
| | 02:27 | here in the Project
Navigator, a .h and a .m file.
| | 02:31 | Now classes don't actually have to
be done in separate .h and .m files.
| | 02:35 | They can be combined, but this is typical.
| | 02:38 | The .h, or header file, is your
interface. The .m is your implementation.
| | 02:44 | And in fact, if I switch between the
two, you can see that the .h is using the
| | 02:48 | Objective-C keyword interface and
the .m file is using implementation.
| | 02:54 | As in other object-oriented languages,
every class we make is really defining
| | 02:58 | two pieces: behavior and
data, methods and properties.
| | 03:02 | So I need to describe, say, what it is
that this class is going to do, describing
| | 03:07 | the methods of this class.
| | 03:09 | And I will do this in the interface here.
| | 03:11 | Let's say I just want to create a
method with the name of simpleMethod.
| | 03:16 | I then have to say, does this method take
any parameters and does it return a value?
| | 03:21 | Well, to say that this method returns
void, meaning returns nothing, I'm going
| | 03:26 | to use parentheses in
front of it and just say void.
| | 03:29 | And I do that at the start of the method name.
| | 03:32 | If I wanted this method to be defined
with parameters, I'd put a colon in here
| | 03:37 | and start to describe them. I don't.
| | 03:39 | I am going to say this method takes
no parameters and returns nothing,
| | 03:42 | so I am just going to put a semicolon here.
| | 03:45 | Now if you remember when we looked at
some of the class reference libraries, we
| | 03:48 | would see either a Plus
sign or a Minus sign that says
| | 03:51 | this method is for the instance, or
it's a method for the entire class, and
| | 03:55 | we do this here too.
| | 03:57 | So I am going to add the Minus sign here.
| | 03:59 | Now it's not whitespace-sensitive.
| | 04:01 | I could put spaces in between there, but this
is the default way you will see this written.
| | 04:06 | So I am going to say here, this is an
instance method called simpleMethod that
| | 04:11 | returns void and takes no parameters,
which is why I am just finishing the line
| | 04:16 | off with a semicolon.
| | 04:17 | A little bit later on we'll see how
to define more complicated methods.
| | 04:21 | Now you might be thinking, where is
the opening and closing curly brace?
| | 04:24 | Where is all the functionality?
| | 04:26 | But again, we don't do any of that
inside the interface part of this class.
| | 04:31 | All we are saying is this method should exist.
| | 04:35 | Other code can now look at this
interface and say, okay, you have a Player
| | 04:40 | class and it has a method called
simpleMethod that takes no parameters and
| | 04:45 | returns void, okay.
| | 04:46 | Now what will happen here is if I
save this and then hit Command+B to build
| | 04:51 | this application, it's going to succeed
technically, but it'll point out there
| | 04:56 | is an issue with it.
| | 04:57 | I am using the Issues section of the
Navigator, which is the middle section with
| | 05:00 | the exclamation mark.
| | 05:01 | There is that semantic issue, an
incomplete implementation, basically letting me
| | 05:07 | know that my interface said I had a
method called simpleMethod, but my
| | 05:12 | implementation doesn't
actually do it, so I need to.
| | 05:16 | Now there are multiple ways to be in
this file. Of course, we can get to it just
| | 05:19 | by single clicking in the Project Navigator.
| | 05:22 | Another option that we could use, if I
had enough screen real estate, is with
| | 05:26 | either of them selected, I could come
up to the toolbar and click the button to
| | 05:30 | say Show the Assistant editor.
| | 05:33 | Selecting that, I am just going to
turn off the Utilities panel to get a bit
| | 05:38 | more screen real estate.
| | 05:39 | This editor gives us two
views of complementary classes.
| | 05:43 | So if I have the .h file selected, it
will also show me the .m. We can actually
| | 05:47 | switch them the other way around as well.
| | 05:49 | But if you have a large monitor, it's a
good way to get both the interface and
| | 05:53 | the implementation onscreen at the same time.
| | 05:56 | So I just want to prove that this works.
| | 05:57 | I am going to go ahead and provide the
implementation for this, so I am going to
| | 06:02 | match the signature that was in my
interface, although this time around I do
| | 06:07 | have to have the opening and closing
curly braces because I have to provide an
| | 06:11 | implementation for this method.
| | 06:13 | I am just going to put in a very
straightforward NSLog message here.
| | 06:21 | Now if I were to save and build this,
we would see Build Succeeded, no issues,
| | 06:25 | no semantic problems.
| | 06:27 | Well, let's prove that this works.
| | 06:29 | I have created a new class called
Player. I now want to use it.
| | 06:32 | I jump over to main.m and I am going
to write some code to create it here.
| | 06:37 | Well, I know how to make an NSString,
so let's try and see if it's the same
| | 06:41 | thing for the Player object.
| | 06:43 | And it's actually going to have a problem here.
| | 06:45 | It doesn't know where the
Player class is defined.
| | 06:48 | We get access to things like NSStrings
and NSDates because we are importing the
| | 06:52 | foundation framework header files.
| | 06:55 | I also need to have an import statement
here for that new Player class that I did.
| | 07:02 | Now if my class is in my own project,
as opposed to one of the system ones, I
| | 07:06 | don't use the Less Than sign.
| | 07:08 | I just use the double quotes.
| | 07:10 | So here I am going to start to type
Player and even as you can see, it's pulling
| | 07:13 | it up for me. I will just hit Return and we are
importing the header file of the Player Class.
| | 07:19 | Now I should be able to create an instance here.
| | 07:22 | I will create a Player called bob = and
we are just going to use this standard
| | 07:27 | way of doing it, which is Player alloc,init.
| | 07:29 | Now although I have the Assistant
editor opened here, there is no actual
| | 07:34 | assistant counterpart file, so I
will just switch back to the standard
| | 07:37 | editor and see this.
| | 07:39 | And you might be wondering,
where do I have the Player alloc and
| | 07:42 | init functionality from?
| | 07:43 | Well, that's all coming because of NSObject.
| | 07:45 | I am inheriting from that superclass,
so I automatically have that information.
| | 07:50 | The only thing it's complaining about
right now is that I am instantiating a new
| | 07:54 | object and I am never using it.
So I better use it.
| | 07:57 | Use the name of the object and then as
I start typing, I should see my defined
| | 08:03 | methods appear. In this case,
there is only one, simpleMethod.
| | 08:07 | Hit Return, close the square bracket,
semicolon to end the line, save and build,
| | 08:12 | and let's run this and check that it works.
| | 08:18 | Zoom out so I can see my full output, and I
get my CustomClasses, Yes, this method works!
| | 08:23 | So it seems to be working just fine.
| | 08:25 | So this is a super-simple class being
defined here, but most classes don't just
| | 08:31 | contain behavior; they are going to contain data.
| | 08:34 | So let's see next how to do that.
| | Collapse this transcript |
| Creating properties| 00:00 | So what if we want to add a couple of
pieces of information to our Player class,
| | 00:04 | so that every instance we create of
this class has its own set of data?
| | 00:08 | I am going just switch to the interface
by itself and just put on the standard
| | 00:13 | editor so I have a bit more space here.
| | 00:15 | Now in previous years the way we would
describe the data in Objective-C classes
| | 00:20 | is to define instance variables or
ivars, and these are just variable
| | 00:24 | definitions that are wrapped in a
pair of braces inside the interface but
| | 00:30 | outside where you have declared the methods.
| | 00:32 | And you just write pretty
normal variable declarations.
| | 00:35 | Let's say we have an integer called age,
or I could have objects to. I will have
| | 00:40 | an NSString pointer called name and
you just start to fill out your instance
| | 00:45 | variables like this.
| | 00:46 | But in Objective-C, these aren't
accessible from outside the class.
| | 00:50 | So if you wanted another part of your
program to be able to reach in and either
| | 00:55 | read a value or change a value. You
would have to start wrapping these up in
| | 00:59 | Accessor methods, writing one getter
method and a separate setter method for
| | 01:03 | every single instance variable.
| | 01:04 | Now this is kind of tedious
and it's pretty prone to errors.
| | 01:07 | So a few years ago the concept of
properties was introduced with Objective-C 2.0.
| | 01:13 | Properties can generate, or synthesize is
the term we use, these getter and setter
| | 01:18 | methods, and allows access to these
ivars from outside of this class.
| | 01:23 | So instead of writing separate getter
and setter method declarations here, I
| | 01:28 | would say @ sign and I'd use the word property.
| | 01:31 | I would say what kind of
property this is, what is the type.
| | 01:34 | In this case, it's an int
and call it age. That's it.
| | 01:39 | And there is one important piece,
which I need to match this @property in my
| | 01:44 | interface with an equivalent
synthesize statement in my implementation.
| | 01:49 | So let me quickly just open up the
Assistant Editor, so I've got my interface on
| | 01:53 | the left and my implementation on the
right, and in here I am going to add,
| | 01:58 | inside implementation--
| | 01:59 | I usually put them at the top--
synthesize and give it a name.
| | 02:03 | Well, what's the name of it? It was age.
| | 02:05 | Save that, Build, Build Succeeded, no issues.
| | 02:10 | So the property statement in my interface
matches the synthesize statement in my implementation.
| | 02:16 | Now here's the thing.
| | 02:18 | While properties started off being used
together with instance variables because
| | 02:22 | everybody was used to writing these ivars,
| | 02:24 | it's actually kind of redundant to
have both, because the information that I
| | 02:29 | provide here to define a property is
enough to allow it not just to synthesize
| | 02:34 | the getter and setter methods, but
it's enough to allow it to synthesize the
| | 02:38 | instance variable as well.
| | 02:39 | So in the last couple of years the
shift has actually been to move away from
| | 02:43 | bothering with explicitly defined
instance variables and just use properties,
| | 02:47 | and in fact, that's what
we are using in this course.
| | 02:50 | So I'm going to add another property that
represents the name, so we have the word property.
| | 02:55 | This will be an NSString *name. Bery
similar to the declaration here, but I
| | 03:02 | don't need to do this anymore.
| | 03:04 | I'm going to remove my instance
variables and because of that, I'm also going
| | 03:08 | to remove the braces.
| | 03:10 | I don't need that, and it becomes a
much more straightforward interface.
| | 03:13 | We have got two properties
and one method right now.
| | 03:17 | There is one extra thing I am going to
add. When we are working with objects for
| | 03:21 | properties you typically add some
attributes, and that's after the word property
| | 03:26 | surrounded in parentheses. And I'm
going to add these two: nonatomic, strong.
| | 03:34 | So what is this?
| | 03:35 | Well, when defining properties that are
objects, there is usually a bit more to it.
| | 03:40 | And nonatomic here means that I'm not
worried about multiple threads trying to
| | 03:44 | access this object at the same time,
and it means that Objective-C doesn't have
| | 03:49 | to synthesize thread-safe
code for my getters and setters.
| | 03:52 | Now if I'd said atomic or just
actually left this out because atomic is
| | 03:57 | actually the default, it would
generate that thread-safe code.
| | 04:01 | So nonatomic is actually a little
faster, and it's much more common to see in
| | 04:06 | iOS, and pretty much this is a habit for me
to write nonatomic unless I know other ones.
| | 04:11 | Strong, on the other hand, is one of
the few changes that comes along with
| | 04:15 | Automatic Reference Counting.
| | 04:17 | And what strong is doing here is
telling the compiler that I want this Player
| | 04:22 | class to hold a strong reference to
this name property. We are saying yes.
| | 04:27 | We own it. It's ours.
| | 04:29 | As long as a Player object exists, the
string object inside it that holds the
| | 04:34 | name of the Player object should also exist.
| | 04:36 | That's pretty typical for this kind
of data, for this kind of property.
| | 04:40 | Now before ARC, it was quite common
to see the word retain being used here.
| | 04:45 | But strong is more usual now that we
have ARC, and in some circumstances you can
| | 04:49 | use the word weak, but that comes later.
| | 04:52 | Now the final step here, what it's
still complaining about, is I am not
| | 04:57 | synthesizing this property in my implementation.
| | 05:00 | I can do that on another line, but
you can also just synthesize multiple
| | 05:05 | properties by separating them with a comma.
| | 05:08 | So synthesize age, name.
| | 05:11 | Save that. Command+B to build it.
| | 05:13 | Build Succeeded, no issues.
| | 05:15 | So these are my classes.
Let's go ahead and use them.
| | 05:18 | I am going to jump across to main.m
and open up the regular Standard Editor.
| | 05:23 | Here is where I had earlier created
an instance of this class and called a
| | 05:27 | method on it, but what I should now have
is new synthesize methods for getting and
| | 05:33 | setting the age and name of that object.
| | 05:36 | Now I mentioned that Properties
will generate two methods, a getter and a
| | 05:40 | setter, and these methods are generated
with different names, which may strike
| | 05:43 | you as unusual, depending on
the language you are coming from.
| | 05:46 | The getter method by default
has the same name as the property.
| | 05:51 | So I should be able to use something like name.
| | 05:53 | We can actually see here there
is a name that returns a string.
| | 05:57 | However, the setter method is different.
| | 05:59 | It has the word set in front of it.
| | 06:02 | And notice here with CodeSense, I
actually have two ones here, setAge and
| | 06:07 | setName, and these both are the synthesized
setters for my properties in my custom class.
| | 06:13 | So I am going to bob setAge:
| | 06:15 | 54, bob setName, and this takes an NSString.
| | 06:24 | We can just pass in an NSString
literal object using @", and we are using
| | 06:33 | those synthesized setter methods.
| | 06:35 | And if I wanted to prove at least one of them
was working, we could write on an NSLog message
| | 06:41 | that Bob's age is--we use a
placeholder for where we are going to put the age
| | 06:49 | and that is an integer, so I will use
the %i placeholder comma, and I need to use
| | 06:53 | now the getter method to go and
grab that age. It's a method.
| | 06:57 | We are going to use the square brackets.
| | 07:00 | The object we are working with was bob
and the method just has the same name as
| | 07:05 | the property, which is age.
| | 07:07 | So it's not getAge and setAge.
| | 07:09 | It's age and setAge.
| | 07:11 | Don't need that second NSLog,
so I will just comment that out.
| | 07:15 | Save this and build it
and go ahead and run this.
| | 07:19 | Drag that up a little bit and we
can see, yes, Bob's age is 54, so we're successfully
| | 07:26 | both setting and getting
information using synthesize properties.
| | 07:31 | A one last note here: along with the
@property keyword, Objective-C 2.0 added
| | 07:37 | something called dot syntax.
| | 07:39 | Now this is a really common way to access
this kind of information in other languages.
| | 07:44 | What it means is instead of saying bob
age inside the square brackets, I could
| | 07:50 | say bob.age, and it also works for the setter.
| | 07:55 | Instead of using this format
where we have bob setAge: 54,
| | 08:02 | I could instead say, bob.age = 54.
| | 08:06 | And with dot syntax we don't use the word set.
| | 08:11 | Save that, run it again, and
we can see that it still works.
| | 08:15 | If you are coming from a language like
C# or Java, this may look great to you.
| | 08:19 | This is a much more
familiar way for most people.
| | 08:22 | However, while I find dot syntax to be
a nice little addition, in the rest of
| | 08:27 | the course I am going to be going back
to using the standard Objective-C square-
| | 08:33 | bracket ways of accessing things,
whether that's a setter or a getter.
| | 08:38 | There are a couple reasons for this,
and it's not that I dislike dot syntax.
| | 08:43 | I am perfectly fond of it in other
languages, but in Objective-C, I like to use
| | 08:48 | square brackets because then I don't
have to stop and think about whether I
| | 08:52 | can use dot syntax in a particular
place, because it does only work for
| | 08:58 | synthesize properties.
| | 08:59 | You can't use this dot syntax for method
calls, but square brackets works for everything.
| | 09:05 | So it keeps me conscious that I am in
Objective-C and I stay with that one.
| | 09:09 | It's completely up to you of course.
| | 09:11 | There is no impact performance-wise
on whether or not you use dot syntax
| | 09:15 | for synthesize properties or square brackets,
but I rarely use dot syntax in Objective-C.
| | 09:21 | Okay, crash course over.
| | 09:23 | We are going to of course see a lot
more Objective-C, but we were going to
| | 09:27 | see that along the way.
| | 09:28 | Let's get back to some iOS.
| | Collapse this transcript |
|
|
4. Core iOS Project SkillsUsing the different iOS project types| 00:00 | So let's get back to actually
creating some iOS applications.
| | 00:04 | As we've seen when I make a new project
in Xcode, I have several iOS choices, as
| | 00:09 | long as I have the correct area
selected on the left-hand side.
| | 00:12 | Because I have iOS Application, I do also
have Framework & Library, which would let
| | 00:18 | us create shared libraries of code,
which we're not doing in this course, and
| | 00:21 | another section, which lets us
make a completely empty project.
| | 00:25 | But I don't want that either.
| | 00:27 | I don't want the raw simplicity
of a command-line tool anymore.
| | 00:31 | Now we want some provided
code. We want a structure.
| | 00:35 | So we're going to work with
these iOS application project types.
| | 00:39 | There are seven options available for us here.
| | 00:41 | I'm going to talk just briefly
about what each of them mean.
| | 00:44 | Now this first one here, if you've used
your iPhone or iPad for more than about
| | 00:48 | a day you will have used a
master-detail application.
| | 00:52 | It's a classic iOS application style.
| | 00:55 | Many built-in apps on the iPhone or
iPad use this, like the Settings application
| | 01:01 | and the Mail application.
| | 01:02 | They all use this master-detail structure.
| | 01:05 | It's the ones where screens will scroll
from the left to the right as you drill
| | 01:09 | down into different parts.
| | 01:10 | Sometimes it's one level,
sometimes it's multiple levels.
| | 01:13 | And use the bar at the top
to navigate back up the stack.
| | 01:17 | Now with the master-detail application
on the iPhone we switch between multiple
| | 01:22 | screens, whereas on the iPad you often
have what's called a split view where we
| | 01:26 | can keep two sections on
screen at the same time.
| | 01:28 | Now this project
template will actually for both.
| | 01:33 | Next, we have the OpenGL Game template.
| | 01:36 | This is the one that has the icon that
looks like the icon for the Game Center
| | 01:40 | on an iPhone, and we're not going
to touch this one in this course.
| | 01:43 | This is using OpenGL, a graphical library,
which really is its own skill set for
| | 01:48 | developing games and anything
that's really heavy on graphics.
| | 01:51 | So we'll leave this one alone
and move on to the next one.
| | 01:54 | This is the page-based
application. We'll see this later.
| | 01:58 | But as you might guess from the icon,
what this allows us to do is switch between
| | 02:02 | multiple screens but instead of the
scrolling left to right with a master-detail
| | 02:07 | we're using this animated page flip,
and it takes care of doing that for us.
| | 02:15 | The fourth template type is
the Single View Application.
| | 02:18 | This is a very common one to use.
| | 02:20 | I've hold it the
Goldilocks of iPhone project types.
| | 02:22 | It's not too complex, not too simple.
| | 02:25 | It doesn't enforce something like a
master-detail structure or a page flip, but
| | 02:29 | it's enough structure to be
considered a complete app.
| | 02:32 | It's a single view, which means it
gives us a screen of our user interface.
| | 02:36 | One blank canvas. We can come
along and add our stuff to it.
| | 02:40 | Next we have the Tabbed Application.
| | 02:42 | This is another classic iOS model.
| | 02:46 | It's the one that has the tab bar down
at the bottom that allows us to switch
| | 02:51 | between different sections of the application.
| | 02:53 | This can be divided into two,
sometimes three, four, or even five options.
| | 02:57 | You shouldn't go beyond the five on an
iPhone because it's tough to use if you do.
| | 03:01 | Many applications actually
combine both this tab bar idea and the
| | 03:05 | master-detail view.
| | 03:07 | Things like the iTunes app
and the music app will do this.
| | 03:12 | Next to last is the
Utility Application template.
| | 03:15 | This really just has two views:
a main view and a flipside view.
| | 03:20 | Things like the built-in Stocks
application and the Weather app used this model.
| | 03:26 | The main view is the main screen of
your application, whatever that may be.
| | 03:30 | And then you usually have a little
information icon button towards the
| | 03:34 | bottom-right with a little dotted i,
and when you click it, it will handle
| | 03:38 | flipping the screen to another view,
very often used for the settings of the
| | 03:42 | application. And you just flip back and
forth and the flip is animated between
| | 03:46 | the two for you, and
that's the Utility Application.
| | 03:49 | And the final one is the Empty Application.
| | 03:51 | Now this isn't completely empty.
| | 03:54 | This template still provides the
necessary code to launch an iPhone app, but
| | 03:58 | nothing more than that essential code,
not even a single screen for basic user
| | 04:02 | interface, and you'd have to provide
all that before this app would work.
| | 04:06 | Now this Empty template can be useful
later on, after you're familiar with
| | 04:11 | everything that's needed in the iOS application.
| | 04:13 | But when you're first learning it,
it's the other project types that give us
| | 04:17 | more of a structure we can immediately use.
| | 04:20 | We're going to see the Utility
Application, the Tabbed Application, and the
| | 04:23 | Master-Detail Application a little later.
| | 04:25 | But the issue with these right now is
that until you've done a couple of simpler
| | 04:29 | projects, what Apple will immediately
provide for you with these project types is
| | 04:33 | a bit too complex, and it's not going
to make a whole lot of sense until we've
| | 04:37 | done some simple application types.
| | 04:39 | So we're going to concentrate, just
for a little while, on the single-view
| | 04:42 | application and talk about this one
before we go back to the other ones.
| | Collapse this transcript |
| Using the Model-View-Controller (MVC) design pattern| 00:00 | MVC, or Model/View/Controller is a
fundamental part of iOS development.
| | 00:05 | Now this isn't just for iOS.
| | 00:07 | MVC is a software design patent, meaning
it's an idea, and it has been around for
| | 00:12 | a long time, since the late 70s.
| | 00:13 | You can do MVC with Java, you can do it
with C#, you can do it for the web,
| | 00:17 | and you can do it for desktop applications,
| | 00:20 | but the core of MVC, it needs the
objects that represent your data and the
| | 00:24 | objects that represent your
user interface are kept apart.
| | 00:27 | You should be able to change
one without affecting the other.
| | 00:31 | So the word model in MVC represents
your data, your information, the stuff your
| | 00:36 | app needs to store and manipulate
objects that represent contacts in the
| | 00:41 | contacts app or emails in the mail application.
| | 00:44 | But model objects do not
define a user interface.
| | 00:48 | They don't say whether they should show
up with a text field or a button or what
| | 00:51 | font they use. That doesn't matter,
because on the other side of things you have
| | 00:55 | View objects. These are your user
interface, what the user actually sees.
| | 01:00 | Buttons and sliders and text fields,
these are all view objects, and they can
| | 01:05 | be generic and reused.
| | 01:07 | A text field should know
how to draw itself onscreen.
| | 01:10 | It should know if it's been tapped on
or edited, but it wouldn't do the job of
| | 01:14 | retrieving or storing or processing
any data; that would be the model's job.
| | 01:20 | So these two things are very separate,
and between them we have the controller.
| | 01:24 | The controller is the glue
that hooks one side to the other.
| | 01:27 | The controller talks to view, the
controller talks to the model, but the model
| | 01:32 | and the view don't talk directly to each other.
| | 01:35 | And the idea with pure MVC is that
every object in your program would fall into
| | 01:40 | one of three roles, either
model, view, or controller.
| | 01:43 | That doesn't mean you only have three
objects, you could have hundreds, but each
| | 01:47 | one is clearly model or view or controller.
| | 01:51 | And in practice, you don't always create
perfectly clean and independent objects.
| | 01:56 | In iOS the view and controller are more
tightly connected and the core building
| | 02:01 | block in iOS is creating something
called a ViewController class, which as it
| | 02:05 | might sound, wants to claim a little
bit of both view and controller. But as
| | 02:10 | you'll see, even if you create these
together, there is still a separation between them.
| | 02:15 | The Controller side of things is an
Objective-C header and implementation
| | 02:19 | files are .h and .m file.
| | 02:21 | And the user interface view objects are
in a .xib file, and that's the one that
| | 02:26 | gives us the visual user interface builder.
| | 02:29 | But one of the things you do
have to define very well is the
| | 02:32 | relationship between them.
| | 02:34 | It's not automatic.
| | 02:35 | Let me show you what I mean.
| | 02:37 | Let's say we've built a simple user
interface in Xcode, and we've dragged on a
| | 02:43 | text field and a button and a label.
| | 02:47 | Now these are all considered view
objects, and we have to define very
| | 02:51 | specifically the connections between
these view objects in our interface file,
| | 02:56 | and the controller code,
which will be in a .h and .m file.
| | 03:01 | You can't do what you might be able to do
in other environments, which is drag on
| | 03:05 | a button, double-click it, and write your code.
| | 03:08 | It doesn't work that way here.
| | 03:10 | We have to look at each view object and
think about what kind of connection it
| | 03:14 | needs to our controller code.
| | 03:16 | So, for example, if we have a button here,
we want this button to cause a method
| | 03:21 | to be run in the controller code.
| | 03:23 | Well, we need to define that button
as causing an action in the controller.
| | 03:28 | On the flip side of that, we have to define
our text field as being what's called an outlet.
| | 03:33 | We want to reach from our
controller code into the text field and grab
| | 03:39 | the contents of it.
| | 03:40 | We also want to be able to reach from
our controller code into, say, a label, so
| | 03:45 | that would also be considered an outlet.
| | 03:47 | So when you're building your
applications, you're defining very
| | 03:50 | specifically actions where a
view object triggers a method in the
| | 03:55 | controller, and then defining outlets
where something in the controller needs
| | 04:00 | to affect the view and reach into that.
| | 04:02 | Now some elements can be
both actions and outlets, but
| | 04:06 | you'll need to build a lot of
these connections in your iOS code, so let's
| | 04:10 | see an example of this in practice.
| | Collapse this transcript |
| Creating basic interaction| 00:00 | Let's get some real interaction happening
between our user interface and our code.
| | 00:05 | I am going to create a new project in Xcode.
| | 00:07 | It will be an iOS single-view application.
| | 00:10 | I will just call this BasicInteraction,
make sure its Device Family of iPhone,
| | 00:17 | and it's only using
Automatic Reference Counting.
| | 00:19 | Click Next and I will save it on my desktop.
| | 00:23 | What I am really interested in here are
three files that Xcode has created for
| | 00:27 | me that represent one complete
ViewController, both parts of it: the view that
| | 00:33 | we'll see when the application
loads and the controller code behind it.
| | 00:38 | Now it's made of one Objective-C
class called ViewController.h and
| | 00:42 | ViewController.m for the
interface and implementation, and one user
| | 00:47 | interface file, the .xib file.
| | 00:50 | Now you will hear these referred to as
ZIP files, which kind of makes sense for
| | 00:54 | .xib, but also sometimes as
a NIB files, which might not.
| | 00:59 | And that's because until a few years
ago the file extension for these UI files
| | 01:03 | was .nib, which stood for the
Next Step Interface Builder.
| | 01:08 | We used to have to use a separate
program called Interface Builder to work with
| | 01:12 | these files, and that was to up actually
until Xcode 4 when Interface Builder was
| | 01:17 | integrated into Xcode.
| | 01:19 | Now they have been called .xib files
for a few years, but some developers
| | 01:24 | will still talk about the nib and adding
things to the nib and customizing the NIB file.
| | 01:29 | And that's what I'm going to do right now.
| | 01:31 | So with that selected, we
should see it in our editor.
| | 01:34 | And I'm going to make sure that I have
my Object Library open, which I can get
| | 01:39 | from the View Utilities menu.
| | 01:41 | I know it is open, but we have got it there.
| | 01:43 | I am going to drag three very
simple user interface elements over.
| | 01:47 | This is a Label and a Text
Field and a Round Rect Button.
| | 01:52 | I am going to put the Text Field up at the top.
| | 01:55 | You notice as I drag these around,
we get the little helper guidelines.
| | 01:59 | When any of them are selected, I
also have the grab handles I can use to
| | 02:03 | drag this a little wider.
| | 02:04 | I will do the same with the Label,
position it to the left and drag it to full width.
| | 02:11 | And I will use the button and use the
guideline to put it somewhere in the middle.
| | 02:16 | I don't like the default value of Label,
so I can just double-click that and hit
| | 02:20 | Delete to clear it out.
| | 02:22 | And also, I can double-click the button
to put in, say, a simple word like
| | 02:27 | touch. So a text field, a label, and a button.
| | 02:32 | Not the most remarkably impressive user
interface, but it's something that will
| | 02:37 | support some interaction.
| | 02:39 | People can tap the text field.
| | 02:41 | They can type something in.
| | 02:42 | They can touch the button.
| | 02:43 | I can take that value and
change the contents of the label.
| | 02:48 | But how do I do that?
| | 02:50 | Well, we have to now be very explicit
about how exactly these user interface
| | 02:54 | elements connect to our code files.
| | 02:57 | We have to say what do we want the
relationship to be between the text field and
| | 03:01 | our code, and the label and our
code, and the button and our code?
| | 03:05 | Well, with the button, for example, we
want to touch this and have a method occur.
| | 03:10 | The phrase we use is we
want an action to happen.
| | 03:14 | We are driving some behavior in
the code from our user interface.
| | 03:19 | On the flipside, at some point, I
want to write some code that actually can
| | 03:23 | change the value of a label or
look at the value of a text field.
| | 03:28 | In that case, that's being driven from the
code, and those would be referred to as outlets.
| | 03:32 | So the way we describe the
connection between our views and our code is by
| | 03:37 | defining these different elements as
actions and outlets wherever necessary.
| | 03:41 | I am going to show you two ways of doing this,
| | 03:43 | first the older slow way
and then the new quick way.
| | 03:46 | And I am showing you the slow way
first so that you understand what the
| | 03:49 | quick way is doing.
| | 03:51 | So I am going to give myself a bit
more real estate here. And understand that
| | 03:55 | every connection is a handshake.
| | 03:58 | There are two parts to this.
| | 04:00 | Something needs to be done in the code
file and something needs to be done in
| | 04:04 | the user interface file to hook the two up.
| | 04:07 | So code first. I am going to jump
across into my ViewController.h file.
| | 04:12 | I can see this is a normal Objective-C class.
| | 04:15 | I have got the @interface keyword here and
the name of the class, which is ViewController,
| | 04:21 | is inheriting from
UIViewController rather than NSObject.
| | 04:25 | UIViewController is a class part of
the UI kit framework, and it provides all
| | 04:31 | the base functionality for behaving in this role
as a ViewController and what that means in iOS.
| | 04:37 | We don't have to worry
about that too much right now.
| | 04:40 | We just have to know how to extend it.
| | 04:42 | Well, here is where I would usually
put the declaration of some simple
| | 04:46 | methods or some properties.
| | 04:48 | I might define a method like myMethod,
takes no parameters, returns void.
| | 04:55 | It's perfectly legitimate, but if I
want this method to be directly connectable
| | 05:01 | to a user interface element, I have
to do something slightly different.
| | 05:04 | Instead of defining it as void, I will
define a new method and I will use this
| | 05:09 | keyword, IBAction, as the return type.
| | 05:14 | Selector is just the name of the
method, which for me can be changeLabel.
| | 05:18 | Let's call it that. It can be whatever you want.
| | 05:21 | And the one parameter I will accept
when it's presented to me here, which is
| | 05:24 | (id)sender, meaning an
object that will call sender.
| | 05:28 | But what does IBAction means?
| | 05:30 | Well, the IB here is from the
old Interface Builder program.
| | 05:34 | And it's how we're telling Interface
Builder, or now that part of Xcode that
| | 05:39 | used to be Interface Builder, that this
method can be hooked up directly to a
| | 05:44 | user interface element.
| | 05:45 | IBAction is not actually a genuine return type.
| | 05:49 | It's actually the same as void. But it's
a way of marking this method so that we
| | 05:54 | can allow that connection to happen.
| | 05:56 | But of course if I have defined a
method in my interface, I also need to have a
| | 06:01 | matching code in my implementation, or
we will get it complaining about this.
| | 06:06 | Once again, it just needs
to match that signature.
| | 06:09 | So (IBAction)changeLabel, and I would
put my implementation code in here.
| | 06:17 | Now this would be considered
just one side of this connection.
| | 06:22 | I have got a method defined
and it's defined as IBAction.
| | 06:24 | It can be connected to a user
interface element, but it isn't yet.
| | 06:29 | So I am just going to save this and to
do the other side, I am going to jump
| | 06:32 | back into my interface file.
| | 06:36 | I will click to the standard editor
just because I don't have a lot of room and
| | 06:38 | here's how I connected from this end.
| | 06:41 | And it's all to do with this icon on
the left-hand side called File's Owner.
| | 06:46 | That's a little bit cryptic.
| | 06:47 | What does File's Owner actually mean?
| | 06:50 | This icon represents the connection
between the purely visual file here of our
| | 06:55 | .xib and the code files that are behind it.
| | 07:00 | So File's Owner here, we could almost
imagine a dotted line going from this icon
| | 07:06 | to the code files of ViewController.h
and ViewController.m. It's the visual
| | 07:11 | representation of that class
in our user interface file.
| | 07:15 | Okay, so what's the point?
| | 07:17 | Well, I want this button
to connect to that code.
| | 07:21 | I can't drag the button over to the
Project Navigator, but what I can do is
| | 07:26 | make a connection between the button
here and this File's Owner icon, which
| | 07:31 | represent those code files. How do I do that?
| | 07:33 | I am going to right-click or Ctrl+click--
both work--the button, and Xcode offers
| | 07:39 | me a selection of events, different
things that can happen to this button, and
| | 07:43 | offers me the choice of
which one am I interested in.
| | 07:46 | Well, the classic event with buttons
in iOS, because we don't have a Click
| | 07:49 | event, but we do have Touch Up Inside,
not Touch Drag Inside or Outside, Touch
| | 07:55 | Up Inside, meaning someone has touched
the button and they have let go with the
| | 07:59 | finger still inside the button.
| | 08:01 | As I mouse over these little circle
icons, they change to a Plus sign.
| | 08:06 | So I mouse over Touch Up Inside, I click
it, and I drag it over here to File's Owner.
| | 08:13 | And what's going to happen is when I
let go, Xcode will scan the File's Owner
| | 08:19 | classes, which is ViewController.h and
.m let me know if any methods there have
| | 08:24 | been defined with IBAction.
| | 08:26 | I let go and yes, one of them is
there, changeLabel. I select that
| | 08:31 | and this is how we define a connection between
our user interface elements and our code file.
| | 08:37 | And I can see now that there is even a
representation of that in the menu that I get.
| | 08:42 | I could bring that up again by right-
clicking the button. Touch Up Inside points
| | 08:47 | to File's Owner and to the changeLabel method.
| | 08:50 | You can actually drive this two ways.
| | 08:52 | I could have done it by right-
clicking File's Owner and I will see there is
| | 08:56 | another view of that. changeLabel points
to the button Touch Up Inside event.
| | 09:02 | And the third way of getting
to it is using the Inspector.
| | 09:07 | The last section here, with, say, the
button selected, is the Connections
| | 09:11 | Inspector that shows me Touch Up
Inside on the button is connected to
| | 09:15 | changeLabel and File's Owner.
| | 09:17 | All of them can be used.
| | 09:19 | They all stay in sync with each
other, so it's whatever one you're
| | 09:22 | more comfortable with.
| | 09:23 | Well, how about we prove this works?
| | 09:26 | Well, at the moment, the
implementation all of that changeLabel method
| | 09:29 | doesn't really do anything.
| | 09:30 | Let's just do a simple little NSLog
message, because we haven't yet set up the
| | 09:37 | other two pieces of it.
| | 09:39 | So I am going to save that.
| | 09:41 | I am going to hit Run.
| | 09:43 | It will build it all together,
copy it across to the Simulator.
| | 09:47 | And when I click the touch button, I
am not changing the contents of the
| | 09:51 | label yet, but if I drag over here, I can see
that I'm getting my message come out that yes,
| | 09:56 | it works. And in fact I should be
able to do that multiple times.
| | 10:00 | I am going to quit out of the
Simulator and back into Xcode.
| | 10:05 | The missing pieces now are that we haven't
got connections between our code and the
| | 10:11 | text field or the label.
| | 10:12 | So I am going to add that next, but
I'm going to use the quicker way of doing it.
| | Collapse this transcript |
| Creating quick connections| 00:00 | Let's see how to quickly make connections
between our user interface and our code.
| | 00:05 | I am going to make another
iOS Single View Application.
| | 00:07 | I will call this one
QuickConnections and just save it to my Desktop.
| | 00:13 | Jumping over into the .xib file, I am
going to lay out a very straightforward and
| | 00:18 | simple interface, having a
text field up at the top.
| | 00:22 | I'll just used the grab handle and resize it.
| | 00:24 | Then I'm going to have a label
underneath it. I'll both stretch that a little
| | 00:29 | wider and reset its contents to blank,
and drag on a Round Rect Button, put it in
| | 00:35 | the middle, and give it the word touch.
| | 00:37 | Now we've seen that we have to be very
specific, very explicit about how these
| | 00:42 | connect to the code files that are
associated with this user interface, but with
| | 00:46 | Xcode 4, we can be a little quicker about it.
| | 00:49 | I am going to give myself a bit more
room by turning off my Navigators and
| | 00:52 | Utilities. You don't have to.
| | 00:54 | I just don't have a lot of screen real
estate. And making sure that I'm in the
| | 00:59 | .xib file--that part is important here--
| | 01:01 | I am going to turn on the Assistant Editor.
| | 01:04 | Now the Assistant Editor shows two files:
an original file and its counterpart.
| | 01:09 | So if I've been looking at the
.h file, I would see the .m file
| | 01:13 | that's the counterpart to the interface.
| | 01:15 | But here if I am in the .xib,
it's showing me my counterpart as a
| | 01:20 | ViewController.h, the connected code file.
| | 01:23 | And this is the way we can
quickly make connections now.
| | 01:26 | What I can do is connect from this
button in the user interface by either
| | 01:30 | right-clicking or holding down the Ctrl
key, click, and holding down the mouse,
| | 01:36 | drag over into the Code view.
| | 01:38 | I can see that I have this pop-up saying
Insert Outlet, Action, or Outlet Collection.
| | 01:43 | It knows I want to make a connection.
| | 01:45 | It's not quite sure whether I
want an Outlet for an Action.
| | 01:48 | Now notice that if I'm above
or below, it won't let me do it.
| | 01:51 | I have to be inside the @interface, @end block.
| | 01:55 | So I am going to let go, and
it's going to ask, what is this?
| | 01:58 | Is this meant to be an Outlet or an
Action or even an Outlook Collection which
| | 02:02 | we are not dealing with.
| | 02:04 | Well, I could say an Action here and
give it a name, changeLabel, and this will
| | 02:08 | actually create the method signature
we have to manually write ourselves.
| | 02:14 | I can see that it's picked the
typical event, which is Touch Up Inside, which
| | 02:17 | looks correct.
Everything else is fine, Connect.
| | 02:20 | And I get the method signature in the
interface, the same one that I had to
| | 02:24 | write manually in the last
example. But that's not all.
| | 02:28 | If I actually change up here on
the jump bar and I can switch to the
| | 02:31 | ViewController.m, my implementation file,
I can see that not only do I have the
| | 02:37 | entry in my .h, but down here at the
bottom, I also have the implementation
| | 02:43 | ready to go, ready for
me to just put my code in.
| | 02:46 | So just by dragging from the
interface into the code, I get three pieces.
| | 02:51 | I get the interface part,
| | 02:52 | I get the implementation part, and over here
| | 02:55 | I've got my connection defined as well.
| | 02:57 | Well, next up I am going to create a
few spare lines her,e and I'm going to make
| | 03:02 | the connections for the
text field and the label.
| | 03:05 | Once again, I do it the same way.
| | 03:06 | I am going to hold down
Ctrl and drag over in here.
| | 03:09 | It's going to say okay, I am going to say
insert an Outlet or an Action. Which one is it?
| | 03:14 | Well, in this case it will be an Outlet.
| | 03:16 | I want to have a way of getting
from the code to the visual interface.
| | 03:22 | So it's asking for a name.
| | 03:23 | This is going to be the
name of a Text Field object.
| | 03:25 | I will just call it myTextField.
| | 03:28 | I can confirm that it's a type of UITextField.
Yes, that looks correct, and click Connect.
| | 03:34 | And in this case it's
generating a property declaration.
| | 03:38 | I will do another one from the label.
Making sure the Label is selected, hold
| | 03:42 | down Ctrl, drag over in here.
| | 03:45 | I want to insert an Outlet.
| | 03:46 | I will just call it myLabel, hit Connect.
| | 03:49 | Now you may notice that just as we had
to use IBAction to mark a method that can
| | 03:54 | be connected to our user interface,
| | 03:56 | we are using IBOutlet to mark a property
that can be connected to our user interface.
| | 04:01 | So it's automatically done that.
| | 04:02 | Now when you're defining your own
properties inside your classes, you would
| | 04:07 | usually use the word strong, but
here bear in mind, these objects the
| | 04:12 | UITextField and the UILabel, they
really belong over here in the view. The view
| | 04:17 | is what owns those objects, not this class file.
| | 04:21 | So we are using the word weak.
| | 04:23 | We are just letting Xcode do that for us.
| | 04:25 | But remember, these are generated properties,
| | 04:28 | so we need to make sure
that they are synthesized.
| | 04:30 | Well, let's go ahead and check that.
| | 04:32 | Over in the implementation file, we
will actually find that it's also added the
| | 04:37 | two lines of code to synthesize both
myTextField and myLabel and it's done
| | 04:42 | everything to hook them up
in the interface as well.
| | 04:45 | So in fact just by doing that dragging and
dropping, we are pretty much ready to go.
| | 04:49 | About the only thing that's missing is
to actually provide some behavior in
| | 04:53 | the changeLabel method.
| | 04:55 | What I am going to do is just switch
back to the Standard Editor view and then
| | 04:58 | I want to edit my implementation file.
| | 05:01 | I will use the jump bar to get there.
I could use the Project Navigator.
| | 05:05 | Come down to the very bottom.
| | 05:07 | I'll just give myself a few
spaces, so we can see this better.
| | 05:11 | And in this changeLabel
method, I want to do two things.
| | 05:14 | I want to create a new message by
combining the words "hello: with whatever is
| | 05:19 | being typed into the Text Field,
and then I am going to output that and
| | 05:24 | change the value of the Label.
| | 05:25 | So first, I will construct a string.
| | 05:27 | I am going to create this NSString
object by using not just init, but
| | 05:36 | initWithForma,t which allows me to make
a format string with a placeholder in it
| | 05:41 | and combine multiple things together.
| | 05:43 | I am just going to do
something very simple here.
| | 05:47 | So I'll have Hello, and then I am
going to put in a placeholder for an object,
| | 05:51 | which is %@. Close the quote, comma
and I have to name what's going to be
| | 05:56 | placed where the placeholder is, and what I
want to do is grab the value of the Text Field.
| | 06:01 | Now I created a property called
myTextField. I could use dot syntax to get to
| | 06:07 | myTextField.text. Or my preferred way of
course is using the Objective-C format
| | 06:13 | so it'd be myTextField text.
| | 06:17 | This being the name of the method
that retrieves the text property.
| | 06:20 | Now I'm still in a larger method call
right now, so I'd better finish that one
| | 06:25 | off. Do a semicolon and we're good there.
| | 06:28 | And then I'm going to use the property
myLabel and its setText method to pass in
| | 06:36 | that new string that I just
created on the previous line.
| | 06:39 | We are using Automatic Reference Counting,
so even though I used alloc and init,
| | 06:44 | I don't have to care about releasing anything.
| | 06:46 | I can just save this, hit Command+B to
build, and see if it's built correctly.
| | 06:51 | Yeah, Build Succeeded, and
we can go ahead and run it.
| | 06:56 | Now even using the Simulator, what I can
just do is tap into the text field here
| | 07:00 | and it will automatically
bring up the default keyboard.
| | 07:04 | I can actually use the standard
keyboard for typing into here, or I could hover
| | 07:09 | over and use my mouse, but this is fine. And
then the moment of truth, works just fine.
| | 07:15 | So not the most exciting thing, but we are
able to do full interaction. We have outlets.
| | 07:20 | We have actions. We have a lot of code being generated
to hook up our user interface to our code
| | 07:26 | files so that we can just come along
and put in the code that we want to work.
| | 07:29 | Now there is a couple of things still missing.
| | 07:32 | For example, this keyboard has
popped up, but it's not going anywhere.
| | 07:36 | So we could obviously spruce up
this user interface, but that comes a little later.
| | Collapse this transcript |
| Dismissing the keyboard| 00:00 | I have this simple application.
| | 00:02 | It's just a text field, a button, and a label.
| | 00:05 | And we've seen that if we touch
into the text field, the keyboard will
| | 00:09 | automatically appear.
| | 00:10 | I don't have to write any
code to make this happen.
| | 00:13 | It'll just happen automatically.
| | 00:15 | And the behavior that drives this is
built into this UI text field object.
| | 00:21 | It understands that the only way that it
makes sense for the user to interact with
| | 00:25 | it is if it pops up the keyboard.
| | 00:27 | But one of the problems that we have
here is even though an application is
| | 00:30 | working the typical behavior would
expect is that the keyboard goes away
| | 00:34 | after we're done with it.
| | 00:36 | It either goes away: one, if we click
the button; or two, if we tap on a blank
| | 00:40 | area of the interface; or three if we
hit the Return key on the keyboard--and
| | 00:45 | none of those three things are happening.
| | 00:46 | So we don't have to do anything to make
the keyboard appear, but we will have to
| | 00:51 | do something to make it disappear.
| | 00:52 | So I'm going to go back into my code
and quit out of this application, and do
| | 00:57 | the simplest one first.
| | 00:58 | What happens when the user touches the button?
| | 01:01 | Well, we already have a method in our
implementation file called changeLabel in
| | 01:06 | my case, where we are actually grabbing the
contents of the text field and changing
| | 01:10 | the value of the label, and it's here
that I can make that keyboard go away. And
| | 01:14 | the way that I do this is by talking
to the text field, not the keyboard.
| | 01:18 | I don't have a way of
addressing the keyboard directly.
| | 01:21 | Now when the keyboard was
touched, it became egotistical.
| | 01:25 | It realized that it was at that moment
the most important user interface element,
| | 01:31 | the one that user was actually interacting with.
| | 01:33 | In an iOS we have a name for UI
element actively in that position.
| | 01:38 | It's called being the first responder.
And what I've got to do is tell the text
| | 01:44 | field to give up the status of first responder.
| | 01:46 | And the way that I do this
is by calling the text field.
| | 01:49 | It's myTextField, and I'm just
going to call the method called
| | 01:53 | resignFirstResponder and send it that message.
| | 01:57 | I don't need any parameters.
| | 01:59 | It's just those two words inside the
square brackets with the semicolon at the end.
| | 02:03 | I save that, I run this again, we can tap
into the text field, the keyboard pops up.
| | 02:10 | It's become a first responder, and
we can do some basic interaction.
| | 02:15 | Touch the button,
resignFirstResponder, the keyboard goes away.
| | 02:19 | Tap into the text field again,
| | 02:21 | we become first responder.
Do some more text, touch it again,
| | 02:25 | resignFirstResponder, the keyboard goes away.
| | 02:28 | However, in a typical iOS
application, that's not everything.
| | 02:33 | What I'd also expect is that if I
touched somewhere in a blank area of the
| | 02:38 | interface or if I came down and touched
say the Return button on the keypad, that
| | 02:42 | it would also go away, and
that's not happening right now.
| | 02:46 | So quit out of this and return into Xcode.
| | 02:49 | Let's take care of touching a
blank area of the application.
| | 02:52 | The way that I'm going to do this
might seem like a bit of a hack.
| | 02:55 | In my XIB file I'm going to just drag
on another Round Rect button and use the
| | 03:00 | grab handles to maximize it and
make it the size of the interface.
| | 03:06 | Now that doesn't look all that
useful right now because it's now
| | 03:09 | obscuring everything.
| | 03:11 | What we need to do with the big button
selected is go to the Editor menu and I
| | 03:15 | can go down here to Arrange > Send to Back.
| | 03:20 | But it's still a large white
button, which is not what we want.
| | 03:24 | Well, with the button selected, I'm
going to go over to my Inspector section and
| | 03:29 | I need to find my Attributes
Inspector, which is the fourth button here.
| | 03:33 | And what I'm going to do is change the
Type of the button, which is the first
| | 03:37 | attribute, from Rounded Rect to Custom.
| | 03:40 | Now Custom is there to allow us to
create our own buttons, by providing our own
| | 03:45 | images for the normal state and
the highlighted state and so on.
| | 03:48 | But if I just change to a
custom button, it becomes invisible.
| | 03:52 | It's still the full width of the interface.
| | 03:54 | It's still actually there.
| | 03:55 | It might be a little difficult to grab
hold of. One other way I could do that
| | 04:00 | is by expanding the doc here, and I can see
that I still have all my selectable objects:
| | 04:04 | the button with touch on it, the text
field, the label, and behind them all,
| | 04:09 | the larger button. I can even see the small
grab handles at the side of the canvas there.
| | 04:14 | But I do need to connect this to my code,
so I'm going to do it the quick and easy way.
[00:04:20.2 6]
With the XIB selected, I'm going to switch
into the Assistant mode, close that down.
| | 04:26 | Clicking the Back to make sure I've got
the button selected, and then I'm going to
| | 04:30 | right-click it, come down, find the
Touch Up Inside event and drag it over here
| | 04:38 | to insert an action.
| | 04:42 | I'll create an action called
dismissKeyboard. And then switching back to the
| | 04:47 | standard editor, what I'm just going
to do is select my implementation file
| | 04:51 | where I should now have a
dismissKeyboard signature here, and once again all I
| | 04:57 | need to do is say myTextField
resignFirstResponder. Save that, run it again.
| | 05:06 | Now we should be able to tap into the
text field, but if I tap a blank area
| | 05:09 | the keyboard goes away.
| | 05:11 | Back into the text field again, type in
the name, the button works. Again we can
| | 05:18 | resignFirstResponder however we do this.
| | 05:21 | And there is one last thing, which is,
when we tap this Return key, we might
| | 05:26 | expect the keyboard to go away,
but it's not doing that yet.
| | 05:29 | That's the last thing we're going
to do, but the way we do this is a little different.
| | Collapse this transcript |
| Dismissing the keyboard with delegation| 00:00 | So we've seen how to make the
keyboard go away by using the
| | 00:03 | resignFirstResponder calls.
| | 00:06 | That's what I'm currently using driving
it either from the touch button or from
| | 00:09 | the invisible button on the background.
| | 00:11 | But both of these ways were driving this
behavior from outside of the text field
| | 00:16 | and outside of the keyboard.
| | 00:17 | So if we want this Return key to also
dismiss the keyboard, the question is, how
| | 00:24 | do we react to that?
| | 00:25 | Well, we use something called delegation.
| | 00:27 | What can happen here is that the
UITextField itself, which is responsible for the
| | 00:32 | keyboard, can announce towards
that hey, someone's done editing.
| | 00:36 | They've pressed that Return key. And we
can choose what to do in response to that.
| | 00:40 | Now if it's the first time you've
seen delegation, it's going to look a
| | 00:43 | little strange, but let me show
you the process, and then we'll talk
| | 00:45 | about what happened.
| | 00:47 | I'm going to jump over
into my User Interface Editor.
| | 00:51 | I'm going to highlight the text field
itself and open up my Utilities panel,
| | 00:55 | and in the last section of the
Inspectors is the Connections Inspector here.
| | 01:00 | Now I can see that I have all the same
events that I might be used to looking at
| | 01:04 | on, say, a button, like Touch
Drag Inside and Touch Up Outside.
| | 01:09 | I can even see where my outlets are hooked up
so that my code can refer to this text field.
| | 01:14 | But I have another outlet up at the
top, and you'll see this on several of the
| | 01:18 | user interface elements.
| | 01:19 | It's called delegate.
| | 01:21 | What this means is we can nominate
some other piece of code to do some
| | 01:26 | behavior on behalf of this text field.
So I'm going to grab that Plus sign for
| | 01:31 | delegate and drag it onto anywhere
else on the user interface itself, but
| | 01:36 | over here to File's Owner.
| | 01:38 | If you remember, File's Owner is
connecting us to the ViewController.h and .m
| | 01:43 | files, so I'm going to let go.
| | 01:45 | Now often I'd expect to see that pop
up something--what method do I want to
| | 01:50 | call?--but it didn't do at that
time, and there is a reason why.
| | 01:54 | I can see that we seem to have
connected it successfully, that with that text field
| | 01:59 | selected, delegate is File's
Owner. What does that mean?
| | 02:04 | Well, let me show you.
| | 02:05 | With that text field selected, I'm going
to switch to the second Inspector, which
| | 02:08 | is our Quick Help, because I want to
go to the UITextField Class Reference.
| | 02:14 | I could also get to this from the main
organizer window, using the Help menu.
| | 02:19 | So I click that. The Organizer window
opens with this documentation, and it's
| | 02:23 | all the information about the
UITextField, all the things that it can do, and
| | 02:28 | its built-in behaviors.
| | 02:29 | Now the third paragraph here for the
Overview tells me that a text field object
| | 02:34 | supports the use of a delegate to
handle editing-related notifications.
| | 02:39 | We don't have to have a delegate, but if
we have one, we can react to these things.
| | 02:43 | For more information, it has a link to
the UITextFieldDelegate protocol, whatever
| | 02:48 | that is. Talk about it in a second.
| | 02:50 | I click that link, and it
takes us to a separate document.
| | 02:54 | Now what's actually happening here,
without getting too deep into it, is there's a
| | 02:58 | whole bunch of notifications that the
text field can tell us about: whether the
| | 03:03 | text field is beginning editing or
ending editing or somebody has hit the Clear
| | 03:08 | button or someone has hit the Return button.
| | 03:10 | So by calling ourselves a delegate what
we can do is opt into these messages. We
| | 03:14 | can choose to respond to them.
| | 03:16 | And one of them is called textFieldShouldReturn.
| | 03:20 | Clicking that link, it takes me
to this part of the documentation,
| | 03:23 | textFieldShouldReturn asks the
delegate if the text field should process the
| | 03:28 | pressing of the Return button.
And that's key part of it, asks the delegate.
| | 03:33 | We can choose to respond to this.
| | 03:35 | And if this thing looks like a
method signature that's because it is.
| | 03:38 | I'm going to grab the entire thing,
including the Minus sign at the front,
| | 03:43 | and just copy that.
| | 03:45 | Jump back over, go into my implementation file.
| | 03:49 | It doesn't matter where I put this as
long as I put it before the At sign end.
| | 03:54 | I'm going to paste in that method signature.
| | 03:58 | It didn't give me any braces, so I'll
put those in myself. And what we're doing
| | 04:02 | here is by being a delegate, we can
respond to any of the methods that were
| | 04:06 | listed in that delegate reference.
| | 04:08 | This is the only one I'm interested in.
| | 04:11 | It means somebody pressed the
Return key. What do I want to do?
| | 04:14 | Well, in my case I could just
copy that same line, the myTextField
| | 04:19 | resignFirstResponder. Having said that,
another option that I could use is this
| | 04:23 | delegate method, textFieldShouldReturn, is
actually getting in a parameter called text field.
| | 04:29 | So alternatively, I could use that too.
| | 04:32 | Now it wouldn't matter for me here,
because there is only one text field, but
| | 04:36 | potentially I could be a delegate from
multiple different text fields, and I want
| | 04:41 | to make sure that I was
resigning the correct one.
| | 04:42 | However, one last thing I need
to do. I can see up here that this
| | 04:46 | textFieldShouldReturn is meant to return a
Bool saying whether this got handled or not.
| | 04:52 | So I'm going to agree to
that and say return YES.
| | 04:56 | Of courses it's an Objective-C
Bool, which means it's all in caps.
| | 05:00 | It's not true or false. It's yes or no.
| | 05:02 | Now save this, run it.
| | 05:07 | We open up. The text field becomes
first responder. The keyboard pops-up.
| | 05:11 | I can type some name, hit the button.
The resignFirstResponder the keyboard goes
| | 05:15 | away. Again tapping into the
keyboard then we hit the blank button,
| | 05:19 | resignFirstResponder the keyboard goes away.
| | 05:22 | Tap into the keyboard, come down and
hit the Return key. We'll hit the delegate
| | 05:26 | method, the textFieldShouldReturn,
resignFirstResponder, the keyboard goes away.
| | 05:31 | Now this delegation option might have
struck you as a little bit strange, but it's
| | 05:35 | a hugely powerful ability in
Objective-C and iOS development.
| | 05:40 | And in the next movie we'll talk a bit
more about exactly what happened there.
| | Collapse this transcript |
| Using delegation in iOS| 00:00 | The first time you hear this term
delegation, it might sound like some abstract
| | 00:05 | ivory tower idea and it isn't.
| | 00:07 | Like MVC, delegation is one of the core
design patterns in Apple development and in iOS.
| | 00:13 | All iOS apps use delegation, all of them.
| | 00:17 | Even the most basic Xcode project
templates are already using it in the
| | 00:21 | code they give you.
| | 00:22 | Delegation in iOS is how you accomplish
tasks that in other languages you might
| | 00:26 | do with inheritance or
event handling. It's important.
| | 00:30 | But what does it mean?
| | 00:32 | So, a delegate in iOS development is
really like the idea of a delegate in
| | 00:36 | real life, a delegate in
politics or in business.
| | 00:39 | It's someone who acts on behalf of someone else.
| | 00:43 | And to delegate is a formal way that one
person hands off responsibilities to another person.
| | 00:49 | Now for us developers, it's a formal way that
one object hands off work to another object.
| | 00:56 | An object in iOS, often a built-in
object, including several of the user
| | 01:01 | interface elements, already has
its own internal processing, sure.
| | 01:06 | But they can be connected to your objects,
your view controllers, or your custom classes.
| | 01:13 | And they can delegate certain
responsibilities to your objects.
| | 01:20 | Now later, perhaps much later,
you might be the one delegating.
| | 01:23 | You might pass work off to somebody else.
| | 01:26 | But first in iOS, you learn how to be a
delegate, how to have responsibilities
| | 01:32 | handed to your custom classes.
| | 01:35 | I like to say that being a good delegate
in iOS is like being a good delegate in
| | 01:40 | business or in politics in real life.
| | 01:42 | There are steps to this. There are rules.
| | 01:45 | Step one: know the rules. Know what you have to do.
| | 01:49 | What are the responsibilities in that role?
| | 01:52 | This is not casual.
| | 01:53 | If you wanted to be an official
delegate for a political party or government or
| | 01:57 | royalty, it means there are formal
documents that describe exactly what is
| | 02:02 | expected of that delegate
in that role. Step two:
| | 02:06 | say "I can do that."
| | 02:08 | This is where you're volunteering.
| | 02:10 | You're putting your hand up. It is a choice.
| | 02:13 | Now step three: have a plan to actually do it.
| | 02:16 | If you're going to volunteer for this
role, you better be able to follow through.
| | 02:20 | And step four: actually get the
job. Make sure you're in that role.
| | 02:26 | Volunteering is not enough;
| | 02:28 | you need to know that whoever is
handing those responsibilities out is actually
| | 02:32 | going to give them to you
and not to somebody else.
| | 02:35 | So if that's how you might approach
being a delegate in real life, what is it
| | 02:39 | in iOS development?
| | 02:41 | Well, exactly the same thing.
| | 02:43 | Step one: know the rules. Know what you have
to do, and there are formal rules here too.
| | 02:49 | The rules are called the Delegate Protocol.
| | 02:53 | You can get to them through the Xcode
documentation, and each Delegate Protocol
| | 02:58 | is a formal list of method names, and that's
all they are, just method names. Step two:
| | 03:04 | say "I can do that."
| | 03:06 | You're volunteering and you're
marking yourself as volunteering.
| | 03:09 | You're being a delegate for something
specific, and what you do in code in one of
| | 03:14 | your custom classes is that after the
usual declaration of the class, you'd use
| | 03:20 | these angle brackets and a specific
world and you'd say, I can be a delegate for
| | 03:25 | a UITextField, or I can be
a delegate for UITableView.
| | 03:29 | You can volunteer to be a delegate
for more than one thing. Step three:
| | 03:33 | have a plan.
| | 03:35 | This means, you must have to look
at the Delegate Protocol and actually
| | 03:39 | implement the necessary methods, and you
choose the methods you want to support.
| | 03:43 | And what you write in your code in your
classes must exactly match the rules in step one.
| | 03:51 | And step four: get the job.
Marking your class is not enough.
| | 03:58 | Implementing those methods is not enough.
| | 04:00 | Whatever object is handing those
responsibilities out, what we call
| | 04:04 | the delegating object,
| | 04:05 | you need to make sure they're going to
give them to your class and not someone else.
| | 04:10 | So you have to say, my class is going to be
of the delegate for that particular object.
| | 04:15 | An example might be that I can
highlight a text field, I find the delegate
| | 04:20 | outlet for that, and hook
it up to the file's owner.
| | 04:23 | That makes my file's owner class
the delegate for the text field.
| | 04:27 | You can also hook up
delegates in your code as well.
| | 04:31 | Now if it's your first time approaching
this concept of delegation, it probably
| | 04:35 | still sounds a little confusion.
| | 04:37 | But like being a delegate in business
or in government, in all likelihood you
| | 04:41 | still begin by having someone show you
around and walk you through a couple of examples.
| | 04:46 | And as we go through more of the
course, that someone is going to be me.
| | Collapse this transcript |
| Creating alert messages| 00:00 | One of the first questions I get from
developers in other languages is, how do I
| | 00:04 | make an IOS app that can pop up what
might be called a message box or an alert
| | 00:09 | box in other languages?
| | 00:10 | Now, iOS, not surprisingly, has a
specific object for doing just that.
| | 00:15 | I'm going to make a single
view application in Xcode.
| | 00:18 | This I'll call AlertMe. And I'll make
sure to have Storyboards unchecked and
| | 00:24 | Automatic Reference Counting checked.
| | 00:27 | Click next and I'll save this to the desktop.
| | 00:29 | We're going to make a very simple app
that immediately pops up an alert message.
| | 00:34 | Now of course you could use the
techniques we've seen so far to make this happen
| | 00:38 | on a touch event or anywhere else in
your code, but I'm to have it happen
| | 00:42 | immediately, and that will give us two things:
| | 00:44 | one, how to make an alert happen at all,
and two, how to execute some code as
| | 00:49 | soon as the application runs for the first time.
| | 00:51 | So if I look at my ViewController.m
file here, I see that Xcode gives me a file
| | 00:57 | with a few placeholder methods here,
and these allow us to inject our code at
| | 01:02 | several different points in
the lifecycle of an application.
| | 01:05 | There is one here called viewDidLoad,
not surprisingly for when a few loads and
| | 01:10 | when a view unloads.
| | 01:11 | There's one down at the bottom
here that answers the question, should
| | 01:15 | this application rotate to a
particular interface orientation, like
| | 01:19 | portrait or landscape?
| | 01:20 | There are several more built-in
lifecycle events, things like viewDidAppear
| | 01:26 | and viewWillAppear and depending on the
version of Xcode you're using, or if you open
| | 01:31 | older projects, you might even see
more of these placeholder methods here in
| | 01:35 | the boilerplate code.
| | 01:36 | Xcode 4.3 made the default code for a
view controller a little simpler than in
| | 01:41 | previous versions of Xcode.
| | 01:43 | But one classic place I could write
some code when an application loads for the
| | 01:48 | first time is in this method called viewDidLoad.
| | 01:52 | This will be called automatically
after the controller has loaded all the
| | 01:55 | interface elements that
are defined in our .xib file.
| | 01:59 | So I'm going to leave the line super
viewDidLoad present so it can do any
| | 02:04 | necessary code that's defined in the
superclass, and I'll put my own code
| | 02:08 | after this comment.
| | 02:09 | I'm going to create a built-in object
called a UIAlertView, and this has a
| | 02:16 | custom initializer so we can
allocate it and set it up with all the
| | 02:19 | information it needs. It's initWithTitle message, and as
we'll see, a few other things here.
| | 02:25 | I'm just going to split us apart onto
multiple lines so we can read it a little better.
| | 02:28 | You don't have to do that.
| | 02:31 | As we can see, there are
several arguments to it.
| | 02:34 | The first one that it takes is
a title, and this is an NSString.
| | 02:38 | We can just use the NSString literal
format here, so I'll call it Alert Title,
| | 02:44 | and we will see the impact that this has.
| | 02:47 | Next is another NSString for the message.
| | 02:50 | Let's say "Here's the
message -- there was a problem!"
| | 02:54 | Now we have this argument called
delegate, and what's it asking for here?
| | 02:58 | Does this thing does this UIAlertView
object need to be pointed to another
| | 03:03 | object to handle any extra processing?
| | 03:07 | If we wanted to have a complicated
UIAlertView with multiple buttons on it and
| | 03:12 | we needed some extra code to be defined
to handle when those different buttons
| | 03:15 | were pressed, we could define a
delegate here to respond to that.
| | 03:19 | So you can connect delegates in code as
well is in the visual interface builder.
| | 03:24 | But I just want a regular old UIAlertView.
| | 03:27 | I don't want anything special.
| | 03:28 | I just want it to go away when it's
done, so I don't need a delegate. And I
| | 03:32 | won't always need one.
| | 03:34 | It's quite common that you don't.
| | 03:36 | But the way here that I would say I
don't need one is just used the word nil,
| | 03:40 | N-I-L, all lowercase.
| | 03:42 | This is the equivalent of
null in some other languages.
| | 03:46 | It's basically saying a
nonexistent Objective-C object, no delegate.
| | 03:50 | Then we jump onto the next one,
which is the cancelButton Title.
| | 03:53 | What do you touch to make this thing go away?
| | 03:56 | What does the button say that
you actually put your finger on.
| | 03:58 | And I'll just give it another NSString, again
using the at sign format, and just say Okay.
| | 04:05 | And finally, we have the
otherButtonTitles argument.
| | 04:09 | This is using an unusual format
with the ellipsis, the dot, dot, dot.
| | 04:12 | What it's basically saying is we could
give it multiple arguments separated by
| | 04:16 | commas, multiple titles for other buttons.
| | 04:20 | So we could provide multiple options
here, and they do have to end with nil.
| | 04:25 | That's will actually tell the
alert view we're actually done.
| | 04:28 | The are no more other button titles.
| | 04:30 | In fact if I don't want any other
buttons, I just get rid of that and make sure
| | 04:34 | that the only thing that passes is nil.
| | 04:37 | If you want to do other buttons, take a
look at the documentation for UIAlertView.
| | 04:42 | This defines and allocates and
initializes our object, but it doesn't show it
| | 04:46 | yet. So I have this new object
called myAlert, and I'll just call show.
| | 04:52 | Save that and run it.
| | 04:58 | It pops up an alert message. Now if you
can see your debug error, you might see a
| | 05:03 | message like this: "Applications are
expected to have a root view controller at the
| | 05:07 | end of application launch."
| | 05:08 | That's because what I've done here is
kind of interfere with the process a
| | 05:12 | little bit of pumped up this modal
dialog boxes waiting for a response without
| | 05:18 | actually letting the view completely load.
| | 05:21 | It's not too much of an issue because
we're just doing an example here, but if
| | 05:25 | you do see that message, it might be
because you're kind of interfering with the
| | 05:28 | initial process. So I've got
the one cancel button here.
| | 05:32 | We can see where the alert title is
corresponding with init with title with the
| | 05:36 | message and the cancel button title.
| | 05:38 | We click okay and it takes to the
application, which doesn't really do anything.
| | 05:42 | Here, however, is one thing you might notice.
| | 05:46 | If I come out of the application by
clicking the Home button and then go back in
| | 05:50 | again to alert me, well, I
actually don't get that message.
| | 05:56 | That's because when we leave the application
using this Home button, it's not fully exiting.
| | 06:02 | It's going into a background state,
and when we reopen it, it's not calling
| | 06:07 | viewDidLoad again, so this method is
actually only being called that first time.
| | 06:11 | And this is the default
behavior of multitasking in iOS.
| | 06:15 | The viewDidLoad method will be called
the very first time someone opens this
| | 06:19 | application but not when the
application opens from a background state.
| | 06:23 | Now maybe that's what we want and
maybe it isn't, but what it does mean is we
| | 06:28 | need to start becoming a bit more
aware of the lifecycle of an application so
| | 06:32 | that we can introduce our code in
the correct places along the way.
| | Collapse this transcript |
| Understanding the iOS application lifecycle| 00:00 | After they've created a few simple
projects, most developers become curious
| | 00:04 | about what's actually happening in
the lifecycle of an iOS application.
| | 00:09 | What do those other files represent?
| | 00:12 | How do we get from someone touching an
icon on the iPhone screen to running the
| | 00:16 | code that we write in a view Controller?
| | 00:18 | Well, the most basic idea is this.
| | 00:21 | This is an Objective-C program, which means
our iOS applications begin by running main.
| | 00:28 | And in an iOS project, we do have a main.m file.
| | 00:32 | It's in our supporting files folder.
| | 00:34 | As a rule, you won't touch it.
| | 00:36 | You're going to leave it alone,
which is why Xcode puts in that folder.
| | 00:39 | Now main makes one call to a
function called UIApplicationMain.
| | 00:45 | This is a predefined function in iOS
that creates an object, UIApplication, that
| | 00:50 | represents a standard, typical iOS
application. It's the foundation, the
| | 00:55 | processing that every iOS app is going
to need. So it sets up a Run loop so the
| | 01:01 | application stays active, it
responds to events, and so on.
| | 01:04 | But our app is different from a base
generic application object, and we need to say how.
| | 01:11 | We don't use inheritance for
this in iOS. We use delegation.
| | 01:15 | And we always need a class in our
project that is the delegate for the standard
| | 01:20 | built-in iOS application object, and
this is something Xcode does for us.
| | 01:26 | Looking at the standard files
created in a single view application,
| | 01:30 | you can probably have a pretty good
guess as what the class might be that is the
| | 01:35 | delegate for our application object.
| | 01:38 | Of course, it's AppDelegate.h and
AppDelegate.m. And this is where we can put
| | 01:44 | some code to respond to application-
level events, like our application starting
| | 01:48 | and application terminating.
| | 01:50 | But right at this part of the
process, we have no user interface yet.
| | 01:54 | This is all happening in the background.
| | 01:56 | So one of the things the AppDelegate
immediately needs to do is say hey, we need
| | 02:00 | a user interface. And it does that in two steps.
| | 02:03 | First it creates an object called a UIWindow.
| | 02:06 | Now think about a window.
| | 02:08 | A window is clear.
| | 02:10 | It's transparent, although
it does have certain size.
| | 02:13 | It has boundaries.
And really that's what happens in iOS.
| | 02:17 | This UIWindow object represents the
boundaries of an iPhone or an iPad screen.
| | 02:23 | It's immediately created and it
exists for the lifetime off our app.
| | 02:27 | There is just one of them.
| | 02:28 | But it is effectively transparent.
| | 02:30 | There is nothing in it, because
what we then do is load in our view
| | 02:34 | controllers, which contain our user
interfaces and their controller code, the
| | 02:39 | .h, .m, and .xib files.
| | 02:42 | Now when we create something like a
single view application, we're loading a
| | 02:47 | single view controller into that UIWindow.
| | 02:50 | In more complex applications, we can
switch multiple different view controllers
| | 02:55 | in and out of that UIWindow.
| | 02:57 | Now if this looks a little
intimidating, fair enough.
| | 03:00 | There is a lot going on
here, but here's the thing.
| | 03:04 | Looking at this overall
process, you don't touch .ain.
| | 03:08 | You don't touch UIApplicationMain.
You don't really do anything directly
| | 03:13 | with UI application or with the window object.
| | 03:15 | Your interaction with this entire
structure is in two primary places:
| | 03:19 | your app delegate code and your view
controller code, and your user interfaces.
| | 03:24 | You just need to know
where you are in the structure,
| | 03:27 | because as your application runs and
the event loop runs, it's going to call
| | 03:32 | methods, like the application:
didFinishLaunchingWithOptions.
| | 03:37 | And it will pass that
across to your AppDelegate code.
| | 03:42 | You get to process that and respond to it.
| | 03:45 | It spawns up the UIWindow, spawns up
the View Controller, and view controller
| | 03:50 | gets things like viewDidLoad and viewWillAppear.
| | 03:54 | We can choose whether or not to
respond to these in our view controller code.
| | 03:58 | When the first view controller is made
active, the app is now fully active and
| | 04:02 | back in the AppDelegate, we get the
application:didBecomeActive notification,
| | 04:07 | and we can use that if we want.
| | 04:09 | This kicks off events like
viewDidAppear in the view controller.
| | 04:13 | And this is all happening in a split second.
| | 04:17 | If someone presses the Home button
to leave the app, we'd get things like
| | 04:21 | application will resign, application did enter
background, but we'll see more of those later.
| | 04:26 | So what is important to know is that
there's nothing really hidden behind the scenes.
| | 04:31 | All this stuff is actually in
your project, in your application.
| | 04:36 | If I jump across into a typical
application, I can find main.m. I can see the
| | 04:42 | call to UIApplicationMain.
| | 04:45 | That's going to create that object and
point it to our AppDelegate, which is, not
| | 04:50 | surprisingly, over here.
| | 04:52 | I can look at the AppDelegate
implementation and find this application
| | 04:58 | didFinishLaunchingWithOptions.
| | 05:00 | And while this code may look a little
confusing right now, what we're doing here
| | 05:04 | is creating the window that
transparent boundary of the frame.
| | 05:08 | On line 22 is the code that then
creates the first view controller.
| | 05:14 | We have this method called
initWithNibName, so we're loading both the class
| | 05:18 | files and the .xib as well.
| | 05:20 | On line 23, we're loading that view
controller into the window. Line 24 makes it visible.
| | 05:27 | All the code is provided for you.
| | 05:30 | Once you understand a little bit more
about these different options and as you
| | 05:34 | can see, they're all quite well documented here,
| | 05:37 | it's very specifically defined,
and the order is explicit.
| | 05:41 | This structure is provided for you
in all the iOS project templates.
| | 05:45 | You just have to decide
where to interact with it.
| | Collapse this transcript |
| Understanding multitasking| 00:00 | So when the user hits the icon for
your application for the first time, it's
| | 00:05 | going to start up, and in that first
launch it's going to be calling methods in
| | 00:09 | the app delegate like
applicationDidFinishLaunchingWithOptions, and in the View
| | 00:13 | Controller, like viewDidLoad
as part of that startup process.
| | 00:17 | But you can't count on these two
methods alone, because when the user hits
| | 00:22 | the Home button, your application
is going to disappear, but it doesn't
| | 00:26 | completely terminate. It doesn't exit all the way,
and that means the next time the user taps the
| | 00:31 | icon to open the app,
| | 00:33 | it would look the same to them, but
they will not be hitting those same events.
| | 00:38 | And this is because iOS devices by
default use multitasking, but what Apple
| | 00:43 | means by multitasking may not
be what you mean by multitasking.
| | 00:47 | It certainly does not mean that your
app just runs all the times after someone
| | 00:51 | has pressed the Home button.
| | 00:52 | That would be a far to uncontrolled
state of affairs for Apple to allow.
| | 00:57 | So your app would disappear from the
screen and enter a background state, a
| | 01:02 | suspended state, not an actively running one.
| | 01:05 | If the user taps your application icon
to run it again, your app moves from that
| | 01:10 | background state to the foreground state again.
| | 01:12 | They can also double-click the Home
button to get the list of applications that
| | 01:16 | are in the background and relaunch
it that way, and the cycle continues.
| | 01:20 | So we don't just have lifecycle events
for launching the app and terminating
| | 01:25 | the app, but also for moving to the
background or moving to the foreground. And
| | 01:29 | these methods include
applicationWillResignActive,
| | 01:31 | applicationDidEnterBackground. The app
disappears. We launch it again, we get
| | 01:38 | applicationWillEnterForeground,
applicationDidBecomeActive, but of course the
| | 01:43 | cycle can continue.
| | 01:45 | Hit the home button.
| | 01:46 | We'll resign again.
| | 01:47 | We'll enter the background, and
whether it's a minute later or a week later,
| | 01:52 | applicationWillEnterForeground, the
applicationWillBecomeActive, this can happen
| | 01:55 | time and time again.
| | 01:57 | These will be called automatically when
that process happens, and they're going
| | 02:00 | to be the key methods to respond to if
you need to do anything when the user
| | 02:04 | moves in and out of your app,
| | 02:06 | as they could be called
dozens of times between the first
| | 02:09 | applicationDidFinishLaunchingWithOptions
and the final
| | 02:13 | applicationWillTerminate, which rarely
gets called, but can be if your app is
| | 02:18 | indeed fully executing, because your
app can still be required to exit all the
| | 02:23 | way out, either because iOS commands it--
| | 02:26 | the operating system on the device can
decide it needs the memory--or the user
| | 02:30 | can also exit your application by
double-clicking the Home button to see the
| | 02:34 | list of apps and then holding them down
and tapping the minus button. And in that
| | 02:38 | exit processm iOS will call
applicationWillTerminate in your app delegate.
| | 02:43 | But do you notice when you're looking
at the boilerplate-provided app delegate
| | 02:48 | call, that these are very well
commented: applicationWillResignActive,
| | 02:51 | applicationDidEnterBackground,
WillEnterForeground, DidBecomeActive, and
| | 02:57 | applicationWillTerminate.
| | 02:59 | And whether you're truly terminating or
just moving to a background state, you
| | 03:03 | always have to be quick about what
you're going to do in any of these methods,
| | 03:06 | because you only have a few seconds to
exit before iOS decides you're taking too
| | 03:10 | long and just kills your process.
But if you've actually transitioned to the
| | 03:15 | background, well, what is your
application doing in the background?
| | 03:19 | Well, by default absolutely nothing.
| | 03:22 | Oh, sure, your app is taking up a little
bit of memory, but no processing cycles.
| | 03:27 | So if you had started a long-running
calculation or a long-running network
| | 03:31 | operation, those are not just
continuing in the background.
| | 03:34 | Your app is not running.
| | 03:37 | Now, but can your app do
something in the background?
| | 03:40 | Well, maybe, there is a very short and
controlled list of what an iOS app is
| | 03:45 | allowed to do once it's moved to that
background state. And you have to ask
| | 03:49 | permission of iOS by making a change to one of
your app's supporting files to do any of these.
| | 03:55 | The five very specific things an app
can do is play audio, so you can move to
| | 04:01 | the background and continue to play audio
from a network stream or from the iPod library.
| | 04:05 | You can react to location changes, perhaps
for creating a navigation app with prompts.
| | 04:11 | You can keep a voiceover IP
connection alive to make calls over your
| | 04:14 | Internet connection.
| | 04:16 | If you write a Newstand app, you can
download content while your app is in the background.
| | 04:20 | And if you're connected to an
accessory, your app can talk to that.
| | 04:25 | You can also ask permission to perform
some small generic background tasks, but
| | 04:30 | you do not get free reign on the processor.
| | 04:33 | Now, all of these are specialized
options outside the scope of this class.
| | 04:37 | We won't be working with background
operations here. But if you did have
| | 04:40 | something in mind that needed
to do these, they are available.
| | 04:44 | What we'll be working with are the
ways to react not just to application
| | 04:48 | launch and terminate events, but also
to our app moving between background
| | 04:52 | and foreground states.
| | Collapse this transcript |
|
|
5. TroubleshootingTroubleshooting a basic application| 00:00 | I'm going to illustrate a few of the most
common issues when you're new to iOS development;
| | 00:05 | I'm just using a simple program here.
| | 00:06 | It has a button and a label, and it's meant
to update the label with the current time.
| | 00:11 | I'm going to say that the NIB file
here looks correct. Then I might jump
| | 00:15 | across to an implementation file and
find that, yeah, I seem to have a method
| | 00:19 | here called updateTime.
| | 00:20 | What this is actually currently
doing is using something called an
| | 00:24 | NSDateFormatter to get the current date and
change it to just the time, hours and minutes.
| | 00:30 | We haven't gone through
date formatters, but it should be fairly obvious
| | 00:33 | here what this is doing.
| | 00:34 | And we're then changing
the label. Looks correct.
| | 00:37 | I'm going to go ahead and run this.
| | 00:39 | Build has Succeeded, so obviously
there is no problems with the code.
| | 00:43 | I go ahead and I click the
button and nothing happens.
| | 00:47 | This is a very common problem.
| | 00:49 | Your buttons don't do what you think they
should do--or your sliders, or your switches.
| | 00:53 | Some kind of user interface element does
not seem to be doing the job it's supposed to.
| | 00:57 | But what I'm not sure about is where the
problem is. Is there a problem with the button?
| | 01:02 | It's not calling the method properly, or
perhaps there's a problem with the method.
| | 01:05 | It's not updating the label property,
so we'll take them step by step.
| | 01:08 | Going into my XIB file, I'm going to
turn on the Utilities panel, and while
| | 01:12 | there's a few different ways of
seeing this information, I can see this
| | 01:16 | Connections Inspector over here.
| | 01:17 | I'm going to select the button, and I
casually see that, yeah, I seemed to be
| | 01:20 | hooked up to something.
| | 01:22 | I'm hooked up into File's Owner to
update Time, so there is an event on the
| | 01:26 | button, but if I look a little
closer, it's actually the wrong one.
| | 01:30 | What I have here is the Touch Drag
Outside is connected to File's Owner, and I
| | 01:35 | could see this information one of three ways.
| | 01:37 | Using the panel over here I could also
right-click or Ctrl+Click the button and
| | 01:41 | it shows me the Touch Drag Outside.
If I could drag this a little wider, so you
| | 01:46 | see more of it. Touch Drag Outside.
| | 01:47 | I could also see it in the
File's Owner or even code.
| | 01:50 | So how do I fix this?
| | 01:51 | Well, I'm just going to turn this off by
clicking that little X button over there.
| | 01:55 | Now the button isn't hooked up to anything.
| | 01:57 | Now, a little earlier I did show you
an option where we can connect our user
| | 02:02 | interface elements using the Assistant
Editor, and I could Ctrl+Drag across in here.
| | 02:07 | That's not what I want to do here,
because I don't want it to create a new
| | 02:12 | method for me. I just want it to hook up to an
existing one. But I can still use this format.
| | 02:17 | I'm going to right-click or Ctrl+Click
the button, grab the correct event, which
| | 02:21 | is Touch Up Inside. Making sure I have that,
| | 02:23 | move it over the updateTime
method definition and let go.
| | 02:28 | Now I know it's correct.
| | 02:29 | I'm going to go ahead and run this,
click the button, and still we have nothing.
| | 02:34 | Quit out of that and go back into the code.
| | 02:36 | And I'm looking here in my implementation file.
| | 02:41 | There is still a problem,
but I don't know what it is.
| | 02:44 | Well, let's do one low-tech way of
dealing with it. In my updateTime method what
| | 02:47 | I'm going to do is just put in an
NSLog message. Save that, run this again.
| | 02:55 | I want to be confident about
whether I'm calling this or not.
| | 02:58 | Now I click the button. Well, I don't
know for sure, depending on what parts of
| | 03:02 | Xcode I've hidden, but if in the
background here I open up the lower section--
| | 03:07 | I'm actually going to use this
button to show just the console here--
| | 03:10 | it does appear indeed
that I can call that method.
| | 03:14 | So the method is being
called correctly. That's fine.
| | 03:16 | I can go back into my code just
quitting out of that and take another look.
| | 03:21 | So I made sure that my action was
hooked up, but I didn't make sure my
| | 03:24 | outlook was hooked up.
| | 03:26 | I can see that in my header file I
have this declaration, this property, a
| | 03:30 | UILabel that is an IBOutlet, but it's
not connected. And in fact, there is a
| | 03:35 | clue right here in the
code that it's not connected.
| | 03:38 | So when you're looking at the code files,
the header files or the implementation
| | 03:41 | files, and things are marked
with IBOutlet and IBAction,
| | 03:44 | you have these circles over here in the gutter.
| | 03:47 | If the circle has a dot inside,
it's connected to something;
| | 03:51 | if the circle is empty, it's not.
| | 03:53 | So this is telling me I've written
it correctly in my code, that it can
| | 03:57 | be connected to a user interface element, but
it's not connected to a user interface element.
| | 04:02 | If I wanted to see where that
equivalent was in the interface file itself,
| | 04:06 | I'd find my label, and right-clicking it, I
see there is nothing connected to this label.
| | 04:11 | What we're interested in from this
side of things is what's called a
| | 04:14 | referencing outlet.
| | 04:15 | Again, multiple ways to connect this,
but I'm going to drag across to File's
| | 04:20 | Owner, which is representing our code
files. And then it's asking, what should I
| | 04:23 | be connected to, label time or view?
| | 04:26 | Well, it's label time, do that.
| | 04:28 | We now see that we're hooked up
to that label in the File's Owner.
| | 04:32 | And if I went back into the Code view
in my header file, I should see from this
| | 04:35 | perspective this circle now has a dot in it.
| | 04:37 | If I actually click that dot, it
will tell me what I'm connected to, the
| | 04:41 | Label in ViewController.xib, or in
the equivalent here, the Button in the
| | 04:46 | ViewController.xib.
| | 04:47 | So very useful to pay
attention to the gutter here.
| | 04:50 | I'm going to go ahead and run this,
and we seem to be working correctly.
| | 04:55 | Connecting your user interface
elements to your code is one of the chief
| | 05:01 | stumbling blocks of any new
developer in iOS, because missing connections
| | 05:06 | won't cause errors.
| | 05:07 | They will just cause nothing to occur.
| | 05:09 | Make sure that you're looking at both
your actions and your outlets and viewing
| | 05:14 | all the visual clues possible, such
as the circles that you'll find in the
| | 05:17 | gutter and the things that you can
get by right-clicking on these user
| | 05:21 | interface element. Very common
issues for anyone new to iOS development.
| | Collapse this transcript |
| Creating breakpoints and using the Xcode debugger| 00:00 | Simple troubleshooting techniques like
using NSLog messages can be very useful.
| | 00:05 | But sometimes it's not quite so clear
where the problem is. You don't want to
| | 00:08 | start writing dozens or even hundreds
of NSLog messages all through your code;
| | 00:12 | instead, you want to step through
your code line by line as it executes.
| | 00:16 | We are going to do that here
using the Xcode debugger.
| | 00:19 | So I've got a simple iOS single view
application and in my NIB file I have one
| | 00:24 | label and a button that's
interestingly titled Boom!
| | 00:28 | This button is going to call a method
in my implementation file here that's
| | 00:33 | going to take a couple of values,
divide one by the other, construct a string,
| | 00:37 | and change the value of the label.
| | 00:39 | And this code is
syntactically correct. It will compile.
| | 00:43 | I can hit Command+B. I'll get a Build Succeeded.
| | 00:46 | And it is hooked up correctly to the user
interface elements, but we still have problems.
| | 00:52 | So I am going to go ahead and run it.
| | 00:53 | We then click the button and we jump back
into Xcode, but it looks a little different.
| | 00:59 | Because we are running from Xcode, we
are jumping back with all these great
| | 01:03 | debugger options already loaded up.
| | 01:05 | Our application is actually still running.
| | 01:08 | It's still over here in the
Simulator in this kind of paused section with
| | 01:12 | the button depressed.
| | 01:13 | But it's allowing us in Xcode to view
the inner workings of what's going on.
| | 01:18 | The first thing to see is this green line here.
| | 01:21 | Xcode is telling us this is where we've
paused is on this line of code, and it's
| | 01:26 | giving me this strange term, Program
received signal: "EXC_ARITHMETIC."
| | 01:30 | Okay we'll get to that.
| | 01:32 | But what else are we looking at,
because this does look a little different?
| | 01:35 | Well, over here, on the left-hand side
we are actually in a different navigator.
| | 01:39 | We are in the debug navigator, which is
the fifth on the seven navigator options.
| | 01:44 | And what it's showing us here is what's
called a stack trace, meaning a list of
| | 01:48 | who called what called what to
get us where we are right now.
| | 01:52 | And it goes from the most recent at the top.
| | 01:55 | So I go from the bottom up, I can see
we actually began with a call to main and
| | 01:59 | then to UIApplicationMain.
| | 02:01 | That looks familiar from
my lifecycle discussion.
| | 02:04 | And then to something I don't
recognize, then to our method.
| | 02:07 | In fact, there is a bit more going on than this.
| | 02:09 | And if I look down towards the bottom of
the stack trace window, we have a slider here.
| | 02:15 | And the stack trace can be dragged
to the right to actually show more
| | 02:18 | details about the whole path between
the call to main and our doSomething
| | 02:23 | call in our ViewController.
| | 02:25 | Now quite often the stack trace can
give you a clue of how you got to the code
| | 02:29 | that's calling a problem.
| | 02:30 | But it isn't really helping us much.
| | 02:32 | We know that we touched the button,
| | 02:34 | it called our code, immediately
there was a problem. Well, what else?
| | 02:37 | Well, on this lower section over here, I
have a split between the Variables view
| | 02:43 | on the left-hand side and the
console on the right-hand side.
| | 02:46 | Now when we are in this paused mode, I
can see a list here of the Local Variables.
| | 02:51 | I've got variables like
firstVal, result, secondVal.
| | 02:55 | Those three are just integers,
whereas this one is an NSString object, so
| | 02:59 | it's a bit more complex.
| | 03:00 | When we have objects inside objects, we
can actually start to drill down inside it.
| | 03:04 | There is still nothing in it yet, because we
haven't created and allocated it probably.
| | 03:08 | This section, this Variables view,
allows us to see local variables or all
| | 03:13 | variables, giving us a few
more, or an automatic view.
| | 03:16 | I am leaving it on Local.
| | 03:17 | And while I can see the values of a
couple of local integer variables here, one
| | 03:22 | of the other things I can do is just
mouse over them in the code itself.
| | 03:26 | Sometimes you have to
step off and back on again.
| | 03:28 | Let's go for firstVal mouse over.
| | 03:30 | Its 10,000 and then back
over to secondVal, which is zero.
| | 03:34 | So there is the problem, because on
line 38 I'm trying to divide firstVal by
| | 03:39 | secondVal, 10,000 by 0.
| | 03:41 | Well, you can do a divide by zero on
a computing system. That's a problem.
| | 03:45 | But I can see, I got secondVal
from calling some other method called
| | 03:50 | calculateSecondValue, so maybe I
don't know what that one is doing.
| | 03:53 | So imagine it's a bit more challenging to
figure out where these values are coming from.
| | 03:57 | Well, what I am going to do is I know I
can't continue, so I am just going to go
| | 04:00 | ahead and click the Stop button
to come back into our regular code.
| | 04:04 | And what I am going to do is in this
method, I am going to come over to the line
| | 04:08 | that I'm about to call,
calculateFirstValue, and just click directly in the gutter
| | 04:13 | here and we get this blue arrow.
This is a breakpoint.
| | 04:15 | You are telling the debugger when
you hit this line of code, stop.
| | 04:20 | So we've got this blue icon.
| | 04:20 | If I click it again, it will become
kind of a halfway transparent, which
| | 04:24 | means it's de-active.
You can kind of flip them on and off.
| | 04:27 | If I wanted to get rid of it entirely, I
click it and drag off to the side, till
| | 04:32 | I see the little cloud and then let
go, but I actually want it there, so
| | 04:36 | first-line inside my doSomething method.
| | 04:38 | I want to be on a line where
code can actually be executed.
| | 04:42 | So with breakpoints enabled, I am
going to come back up here and click Run.
| | 04:46 | Now I'll jump across, click that button,
and we immediately jump back into the code.
| | 04:50 | It looks very similar, but instead,
we see this message here, Thread 1:
| | 04:54 | Stopped at breakpoint 1.
| | 04:55 | And before the code that cause the error.
| | 04:57 | So I have the opportunity to
figure out what's going on.
| | 05:00 | And what I'm interested in here are
these buttons down here in the debugger.
| | 05:04 | We have Step over, Step into,
Step out, Continue program execution.
| | 05:09 | This interesting-looking one on the
left just merely hides the whole Debug area
| | 05:13 | or expands it back up again.
| | 05:15 | I am going to use this one, which is
the step into and just click it once.
| | 05:20 | We're currently paused before line
35 gets executed, before the call to
| | 05:25 | calculateFirstValue.
| | 05:27 | So when I hit this, we are
going to jump in to that call.
| | 05:31 | calculateFirstValue has one line of
code, and we are right before that line,
| | 05:35 | which says return 10,000, so I click
step into again and we jumped back out,
| | 05:39 | back into the next line, which is
a call to calculateSecondValue.
| | 05:43 | I am going to continue on jumping in.
| | 05:45 | We jump into that
calculateSecondValue method. It sets up an integer a = 0 and
| | 05:50 | integer b. That's a call to
calculateFirstValue again.
| | 05:54 | Well, let's say I don't want to
actually jump into that method.
| | 05:58 | I don't need to go through it. It looks fine.
| | 06:00 | What I am going to do instead is move
and click the other one, which is Step over.
| | 06:05 | Now Step over does not
mean bypass this line of code.
| | 06:08 | It means execute it,
| | 06:09 | but if it's making a call to another
method, don't go into that method; just
| | 06:13 | execute this line and move on.
| | 06:15 | So click that once, we execute line 24.
| | 06:18 | If I mouse over b, I can see that it's
set to 10,000, which were the results from
| | 06:23 | calling calculateFirstValue. That looks correct.
| | 06:26 | And now we are into the start of the for loop.
| | 06:28 | If I was clicking this here to step
into, what's going to happen is I am just
| | 06:32 | going round and round the loop right now
because we have a loop set up to go 5000 times.
| | 06:36 | Every time around it's adding one to b.
| | 06:39 | This is going to be a little tedious
if I have to go around 5000 times. I
| | 06:42 | really don't want to.
| | 06:44 | So what I am going to do instead is say,
I just want to pause before that call
| | 06:47 | to a here, so I'm going
to set another breakpoint,
| | 06:50 | Then come down to the controls of the
debugger and just say Continue program execution.
| | 06:55 | That means continue until the next breakpoint
| | 06:58 | if there is one, so hit that.
| | 06:59 | We're going to have gone
around that loop 5000 times.
| | 07:02 | I can even check it by seeing the value
of i was 5000, b is equal to now 15,000,
| | 07:07 | 10,000 plus 5000. And we're about to return a.
| | 07:11 | There is the problem. We're returning 0.
| | 07:13 | Well, I didn't want to return 0.
| | 07:15 | I want to actually change that value.
| | 07:17 | In fact, let's double-check that this will work.
| | 07:19 | I am going to change the value of a
while we are in this paused state.
| | 07:22 | Could do it a couple of different ways
The easiest one is in my variables view,
| | 07:27 | I'll just double-click the value of 0
and say 300, hit Return. A is now 300.
| | 07:32 | I am going to hit Step into to
execute that Return statement.
| | 07:36 | We come back to line 38.
| | 07:38 | This is the line that was
giving us problems before.
| | 07:41 | But hopefully what we should be able
to do now is just try an example of
| | 07:45 | 10,000 divided by 300.
| | 07:46 | So I am going to try and
execute this line of code.
| | 07:50 | Looks good. We don't have any arithmetic
errors, so we are onto line 40, which we
| | 07:54 | hadn't got to before,
which we hadn't gone to before.
| | 07:55 | In fact, what I am going to do is
move over and just say, Continue program
| | 07:59 | execution, just keep going now.
| | 08:02 | And what this does is continue. Now the
program goes back to running as normally.
| | 08:06 | We actually get that label
being updated, the result is 33.
| | 08:08 | I am going to quit out of this and go
back into the code, because I can see here
| | 08:13 | that this was where my problem was.
| | 08:15 | I could fix this any way I see fit.
| | 08:17 | Obviously, we were just doing some
very simple and very straightforward code.
| | 08:21 | I just want to make sure
it's not returning zero.
| | 08:23 | Now what's a very common thing is as
you go through this process quite a bit,
| | 08:27 | you'll end up with a lot of breakpoints.
| | 08:30 | I've only got two, but it's quite easy to
have several, to have several dozen in fact.
| | 08:35 | So if I wanted to switch between the
modes of having all the breakpoints on and
| | 08:39 | having them all off, I don't want to
have to go through and either deactivate
| | 08:42 | them or indeed drag them off all the time.
| | 08:45 | So if I have several breakpoints set
through different parts of my code, what I
| | 08:49 | can do is use this button up here on
the toolbar to just temporarily deactivate
| | 08:55 | the breakpoints, which means if I run it
this time around, we can run it without
| | 08:59 | breakpoints and just see
the result. Looks good.
| | 09:02 | I am going to quit out of it and
then just come back up, turn all the
| | 09:06 | breakpoints on again.
| | 09:07 | Run it again. Clicking the button will
immediately take us into that paused mode.
| | 09:13 | These are the major parts of
this debugging environment.
| | 09:16 | We have the debug navigator on the
left-hand side, giving us the stack trace.
| | 09:21 | We have the Variables view and
the Console in the lower section.
| | 09:25 | We have the ability to set and turn
off breakpoints, multiple ways to step
| | 09:30 | through our code, and the option to change
variables as our code is actually running.
| | 09:35 | And just these few options should
give you the ability to debug most of the
| | 09:39 | situations you'll run into in your
first couple of years of iOS development.
| | Collapse this transcript |
|
|
6. Using UI ControlsCreating user interfaces (UI)| 00:00 | Just buttons and labels can get a
little boring, so I'm going to create another
| | 00:05 | single view application that'll let
us experiment with a few more of the
| | 00:08 | controls and other ways of
setting out a user interface.
| | 00:13 | So I'm going to open up my
ViewController.xib, my NIB file, and I want to make
| | 00:19 | sure that my Utilities panel is open on
the right-hand side, so I have access to
| | 00:23 | my inspectors and to my Object Library.
| | 00:25 | Now, we've seen the Dock over here when
we were editing the user interface file.
| | 00:30 | This can be maximized, or it can be
minimized, but it can't be hidden; we
| | 00:33 | always need it. And the icons in
the Dock are the File's Owner, First
| | 00:38 | Responder, and View.
| | 00:39 | File's Owner, as we've seen, is an icon
that represents a connection from this
| | 00:43 | user interface out to the
corresponding view controller object.
| | 00:47 | It's basically how we connect our .xib
to our .h and .m. And the First Responder.
| | 00:54 | We've heard this term
working with the text field.
| | 00:56 | For us, it's simply a placeholder object.
| | 00:58 | We won't need to touch it.
| | 00:59 | And this View icon. Well, this
represents a UI-View object and if I click it, I
| | 01:06 | can actually take a guess that it's
representing this one iPhone user interface
| | 01:10 | screen that we're currently working with.
| | 01:13 | As you probably noticed, when we're
designing these screens, we have the Status
| | 01:16 | Bar at the top with battery charging symbol.
| | 01:18 | That's because for a typical app, the
Status Bar is always shown, although it's
| | 01:22 | not really part of your app.
| | 01:24 | So actually seeing it here is a bit of a lie.
| | 01:27 | It doesn't represent
anything real in this interface.
| | 01:30 | It's here as a guideline for you to
set out your interface correctly, so that
| | 01:34 | you see your user interface elements
in context on the normal-sized layout.
| | 01:39 | So, there's the question: What is a normal layout?
How much space do we have?
| | 01:43 | Well, a regular iPhone held upright
is 320 pixels wide by 480 pixels high.
| | 01:51 | Now, if I make sure I've this view
selected by clicking it so it has the blue
| | 01:55 | outline, I'm going to switch over here
in the Inspectors to the Size Inspector.
| | 01:59 | It's the one that looks like a ruler
and will give us our measurements for
| | 02:03 | whatever's currently selected.
| | 02:05 | It's telling me this view is 320 wide
and 460, not 480, high, and that's because
| | 02:13 | the Status Bar is taking 20 pixels.
| | 02:16 | There's a question:
| | 02:17 | What about iPhones with a retina
display? Because as you may know, the iPhone
| | 02:22 | 4 and 4S, well, they have screens with
double the resolution of the original iPhone.
| | 02:27 | They are 640 pixels wide, not 320.
| | 02:30 | They're 960 pixels high, not 480.
| | 02:33 | Well here, it doesn't matter.
| | 02:36 | In the interface builder part of Xcode,
these measurements are in points not
| | 02:41 | pixels and they'll automatically be
treated as 1 pixel on a non-retina iPhone
| | 02:46 | and 2 pixels on a retina display.
| | 02:49 | Now there are a couple of places in
Xcode where you can provide different assets
| | 02:53 | for the different size screens.
| | 02:55 | For example, if I'm editing the
project settings, there are places I can
| | 02:59 | drag and drop a regular application icon and
a higher-resolution icon for a retina display.
| | 03:06 | Well when we're working on a regular user
interface, it doesn't matter. It just works.
| | 03:12 | So with that view selected, I'm going
to switch to the Attributes inspector,
| | 03:16 | the fourth one, and you'll find this is the
inspector where you'll spend most of your time.
| | 03:21 | With the View selected, I have things
like being able to turn the Status Bar
| | 03:25 | from gray to black or translucent black.
| | 03:27 | I have options for setting a Top Bar
with a Navigation Bar and the Bottom Bar
| | 03:32 | to a Tab Bar, selecting the different
options to see how large they can actually get.
| | 03:38 | But notice at the top here of this
section it says Simulated Metrics.
| | 03:42 | These are not adding functionality;
| | 03:44 | they just allow you to turn these
placeholders on for this view, so you can set
| | 03:48 | out the rest of your controls
correctly if you know that you will be using
| | 03:52 | navigation bars and tab bars.
| | 03:53 | So I'm going to switch this back just
to using a regular gray status bar and no
| | 03:59 | top bar and no bottom bar.
| | 04:01 | We also have the option to switch
from portrait to landscape and lower down
| | 04:06 | in the Attributes inspector, we can do things
like change the background color of the view.
| | 04:11 | There's not an awful lot more you
would do with a regular background view.
| | 04:15 | So let's see a few other controls.
| | 04:17 | I'm going to drag my Object Library up
a bit, just so we have more of them here.
| | 04:22 | And you've properly scrolled up and
down in this library and seen that there's
| | 04:26 | quite a lot of things, but if it's more
useful for you, you can filter down to
| | 04:31 | see the subset of just controls or
the subsets of gesture recognizers.
| | 04:36 | If I select Controls, you'll see there
actually aren't that many basic controls;
| | 04:40 | there's only ten here.
| | 04:41 | For a great single paragraph about each
one, select it and then hover, and what
| | 04:47 | you'll have is a popover that comes up
for that particular control, just giving
| | 04:51 | you a great introduction to it.
| | 04:53 | To go a little deeper on any of them, you
want to drag one onto your user interface.
| | 04:58 | In fact, I'll drag on a few.
| | 05:01 | As ever, I can use the lines
to center them on the view.
| | 05:05 | It will give me some guidelines about
when I'm getting too close to another user
| | 05:10 | interface element and if we have
multiple elements, I can also use the Editor
| | 05:16 | menu to do basic things
like aligning the left edges.
| | 05:19 | I'm going to drag the object library
down just so I can see the inspectors a bit
| | 05:25 | more now. And with any of the user
interface elements selected, I can use the
| | 05:30 | Quick Help inspector, which is the
second button, to get that information, to find
| | 05:34 | the actual reference to that element,
and the Attributes inspector to find out
| | 05:39 | what's specific about that.
| | 05:41 | With this Segmented Control,
we can change the style of it.
| | 05:45 | We a can choose how many gegments are
in it and what the title of each segment
| | 05:50 | is. With a Stepper selected, instead
here I have minimum and maximum values.
| | 05:55 | With Continuous checked, we can have
things like the ability just to hold down
| | 05:59 | on the plus sign and have it continue to rise.
| | 06:05 | I can select any of these user
interface elements obviously by clicking
| | 06:09 | directly in the screen.
| | 06:11 | I can also click on it using the
expanded view of the dock here and just
| | 06:16 | selecting them. Or I can use the Jump
Bar, which tells us where we are in the
| | 06:21 | XIB inside the view with the stepper
selected, but I can use this to change to,
| | 06:26 | for example, the switch.
| | 06:28 | While it seems obvious just to select
them on the view itself, when you have a
| | 06:32 | complex UI with several overlapping
controls, or even controls that you want to
| | 06:37 | be turning on and off in code, the Dock
and the Jump Bar can actually be a more
| | 06:42 | reliable way of getting directly to a control.
| | 06:45 | And if you're building more complex
layouts, you can actually make use not just
| | 06:49 | of the view that we already
have, but another view as well.
| | 06:53 | The view that we have, this background,
is really just a container, but you can
| | 06:57 | have containers inside containers.
| | 07:01 | You'll actually find that the
Object Library, if I view all the objects
| | 07:05 | available in it, has something just
called a View object, a rectangular region
| | 07:12 | for drawing and handling events.
This also works very well as a container.
| | 07:15 | Now, of the things you can do with it
is select a few elements, go up to the
| | 07:21 | Editor window, and then
you have an Embed In option.
| | 07:24 | I'm going to embed those in a view, and
what that actually means is they're now
| | 07:28 | contained and I can treat them as one unit.
| | 07:31 | Perhaps in code, I could even turn this
on and off, make it visible or invisible.
| | 07:35 | If you have the expanded view of the
Dock, you'll actually see that it now
| | 07:39 | considers our main view, which is the
main screen if you will, to have another
| | 07:43 | view inside it with three controls inside that.
| | 07:47 | So there're multiple ways of managing
controls and containers of controls.
| | 07:51 | Now, we saw that filtered
view here with ten on them,
| | 07:55 | if you remove that search term.
But obviously, we don't just have ten controls.
| | 08:00 | These are the basic ones.
| | 08:01 | We have a lot of more complicated
controls with greater functionality.
| | 08:05 | There's a section just of gesture
recognizers for swiping and pinching.
| | 08:10 | There's a section just for windows and
bars for navigation and for searching and
| | 08:15 | using the toolbar, and we'll see those
a little later. And a section for what
| | 08:19 | are called Data Views, giving us things
like the Image View to hold one or more
| | 08:24 | images, the Map View, the Text View and
controls like the Picker View or the Date Picker.
| | 08:31 | And the Data Views tend to be
very powerful and very useful.
| | 08:34 | So let's see some of those next.
| | Collapse this transcript |
| Using and customizing a picker control| 00:00 | Let's see one of the more
interesting controls, the Picker control.
| | 00:03 | I am going to make a new project here,
go into my XIB file, and with the Object
| | 00:12 | library open--and I will make
sure all objects are viewable here--
| | 00:15 | I am just going to filter on the word picker.
| | 00:18 | I can see that I have two of them here,
and I am going to work with the Date
| | 00:22 | Picker right now, which is
the most straightforward one.
| | 00:23 | We'll see the other one next.
| | 00:25 | We'll drag it onto this interface,
making sure to slide it into the right spot;
| | 00:30 | it's quite easy to move it off screen.
| | 00:33 | And with that selected, I can see that
in my Attributes Inspector, this Picker
| | 00:37 | control has multiple different modes:
| | 00:39 | We can be just a time, just a date,
date and time, a countdown timer.
| | 00:45 | I am going to select just Date and use that.
| | 00:48 | Now, you'll find that when this Picker
control is run, by default it will just
| | 00:52 | set itself to today's date.
| | 00:54 | You could write a little bit of
code to change that, if you wanted to.
| | 00:59 | What I want to do is allow the user to
select a date from any of the possible
| | 01:03 | options here and then find out
what day of the week that was.
| | 01:07 | So I am going to go back into my code,
quit out of this simulated application,
| | 01:12 | remove the filter from my Object
Library so I can find a Round Rect button,
| | 01:17 | drag that on, and just type in "What day is that?"
| | 01:23 | This button will need to send a message
to our code so it will be an IBAction.
| | 01:26 | I am going to hook that up, give
myself a bit more room here, and switch to
| | 01:32 | the Assistant Editor.
| | 01:34 | I'll right-click the button--Ctrl+
Click works too--and connect the Touch Up
| | 01:39 | Inside over here into my interface.
| | 01:42 | The action that I'll call, I'll
call displayDay, and hit Connect.
| | 01:47 | Similarly, what I'm going to need is to
address this Date Picker control from my
| | 01:53 | code, so I need to hook this up as an outlet.
| | 01:56 | I can right-click somewhere here.
| | 01:58 | I am not interested in the Picker
Events; what I'm interested in is the
| | 02:02 | Referencing Outlet Connection.
| | 02:04 | The benefit for me of using the right-
click menu is that when we drag across
| | 02:10 | the interface, it doesn't ask whether
we want to insert an Action, Outlet,
| | 02:14 | Outlet Connection; we have already
limited it so it knows to insert an outlet.
| | 02:19 | I let go. All I have to provide is a
name, and I will call it datePicker.
| | 02:25 | And I should be now ready to add my code.
| | 02:28 | I am going to change back to the
Standard Editor view, turn on my Project
| | 02:32 | Navigator so I can select the
View Controller implementation file.
| | 02:36 | Down towards the bottom I should
find where it has inserted the IBAction
| | 02:41 | skeleton. I'm just giving myself a few more
lines to bring it up closer to the top.
| | 02:47 | Let's take this line by line.
| | 02:48 | When the button is touched, we are going
to grab whatever date the user has just
| | 02:53 | selected on the datePicker.
| | 02:56 | So create a new NSDate variable and set
it equal to the datePicker date property.
| | 03:05 | Next, I am going to create
an NSDateFormatter object.
| | 03:09 | You have seen this briefly already.
What a DateFormatter allows us to do--not
| | 03:14 | surprisingly--is format our dates in
all sorts of different ways than the
| | 03:18 | internal representation of an NSDate
object, which is going to be date and time
| | 03:24 | and seconds and hours and minutes
and all this stuff that I don't want.
| | 03:28 | What a DateFormatter object does is use
Unicode date format. It gives us hundreds
| | 03:33 | of combinations of
different ways of writing this out.
| | 03:37 | If I open up a web browser, what I can
do is quickly search for something like
| | 03:42 | unicode date format patterns.
| | 03:46 | And I see the first entry here is
the Date Format official document on
| | 03:51 | Unicode.org, and in fact, I'm
going to click the link to jump to Date
| | 03:55 | Format Patterns here,
| | 03:57 | which tells us that a date
pattern is a string of characters.
| | 03:59 | We have a few examples here of writing
out these letters and what result that
| | 04:04 | would give us for a particular date.
| | 04:07 | If I scroll down a little further here,
we will see the Date Field Symbol Table.
| | 04:11 | We have different kinds of letters for
representing years, quarters, months,
| | 04:16 | weeks, days, periods, zones.
| | 04:20 | What I'm interested here is this,
weekday. We are using the letter E, the
| | 04:25 | uppercase E. If I use one through three Es,
that will give me the short version, like Tues.
| | 04:31 | But if I use four
uppercase Es, that will be Tuesday.
| | 04:35 | That's what I want.
| | 04:36 | I am going to jump back into my
code and show you how to do it.
| | 04:39 | I have created the formatter
object, just called formatter.
| | 04:42 | I am going to say setDateFormat, passing
in a string which will just be four Es.
| | 04:52 | Now I am going to create a new
NSString object, which is going to contain
| | 04:57 | that day of the week.
| | 04:59 | I'll get it by telling the formatter to go
ahead and create a string from the date chosen.
| | 05:07 | This is the one that we just
pulled out of the datePicker.
| | 05:10 | So the formatter is transforming
that date using its set format into just
| | 05:15 | the day of the week.
| | 05:17 | Next, I am going to create a new
NSString object and I'm going to use the init
| | 05:22 | with format initializer so I can
construct a message here with a placeholder in it.
| | 05:28 | "That's a," and whatever the day is going to be.
| | 05:31 | I need a placeholder here, which I'll
use percent sign, at sign, close the
| | 05:35 | quote, comma, and then week day, which is
the string that's going to actually
| | 05:41 | represent that day of the week.
| | 05:44 | So that will construct our message, and then
the final thing I'll do is pop up an alert.
| | 05:49 | I don't actually have a label or
any other way of getting it out to the
| | 05:53 | interface, so I'll use a UIAlertView.
| | 05:56 | Using the init with title version, just
break that apart to make it a bit more
| | 06:02 | readable. And I'm going to do
a very simple UIAlertView here.
| | 06:08 | The title of the alert will be "What day is that?"
| | 06:11 | The message will be msg, which is
what we just created on line 71, hit Tab.
| | 06:17 | We don't need any delegates so that will be
nil. The cancelButtonTitle can just be Thanks.
| | 06:24 | And otherButtonTitles, we don't need
any other buttons, so I'll just leave that
| | 06:28 | at nil, square bracket to close this,
just break that onto the separate line,
| | 06:33 | and we have a UIAlertView.
| | 06:36 | Finally, I need to show it.
| | 06:40 | Save it, hit Command+B to build,
make sure everything is looking okay.
| | 06:43 | No issues, Build Succeeded, looks good.
| | 06:46 | Go ahead and run this.
| | 06:50 | So I will spin a few of the wheels a few times.
| | 06:52 | Let's find April the 4th, 1992.
Apparently that was a Saturday.
| | 07:01 | March 4, 2028, that will be a Saturday too.
| | 07:05 | Let's double-check the third,
is a Friday. Looks good.
| | 07:10 | So yes, a simple application, but this
is how you'd start to work with the Date
| | 07:14 | Picker: hook it up to a button
in your code and manipulate it.
| | 07:17 | Now, Picker is capable of more than
just dates, so we'll see that next.
| | Collapse this transcript |
| Using data sources| 00:00 | We've seen how to read and set simple
single values in text fields and labels,
| | 00:05 | but we are now going to see how
to load more complex data sources.
| | 00:09 | We are going to use a control called
the Picker View, which is a great example
| | 00:13 | of how more complicated user interface
view objects can interact with our code.
| | 00:17 | Now, we have seen one preconfigured
version of this being used with the Date
| | 00:21 | Picker, but this time we are
going to configure it ourselves.
| | 00:24 | So in my Object Library I am just going
to filter down on the word Picker, and
| | 00:28 | instead of the Date Picker, we will
take the Picker View, and I will position
| | 00:32 | that in the bottom of my main view here.
| | 00:35 | It has some dummy data.
| | 00:38 | Now, what I am looking at is
this Picker View with one component.
| | 00:42 | Now, a component in the Picker View is
the official name for this movable piece.
| | 00:47 | You can think of the component as a
column that can have multiple rows.
| | 00:51 | So if we were looking, for example, at
that Date Picker, this one and this view
| | 00:56 | of it has four components.
| | 00:58 | If I switch that Date Picker to the
Count Down Timer, this has two components.
| | 01:04 | With just the Date, it has three components.
| | 01:07 | Each component can hold a vastly
different amount of data in it.
| | 01:11 | So I am going to delete the Date
Picker because we are not using that.
| | 01:14 | We are going to make our own.
| | 01:15 | And if we are going to define our own
picker, we need to say how many components
| | 01:19 | exist and how many rows are in each
component. What's the content of each row in
| | 01:25 | each component? And we can also say
what happens when somebody chooses between
| | 01:29 | them and selects a row.
| | 01:30 | Now, you might think that if you drag
one of these Picker Views onto your user
| | 01:34 | interface, you could then go to your
Inspector, say the Attributes Inspector,
| | 01:39 | and start loading it with data somehow.
| | 01:41 | But you are not going to be able to do that.
| | 01:43 | We're going to have to
provide the data from our code.
| | 01:47 | Unless all we want is the Apple-
provided list of cities in California, we
| | 01:51 | have to do it ourselves.
| | 01:52 | So let's talk about the simple
situation of configuring a Picker View.
| | 01:56 | I want to have a picker that has a
straightforward single list of items. For
| | 02:00 | this app it will be a mood checker.
| | 02:03 | We can spin it and say whether we are
ecstatic or happy or cheerful, and this
| | 02:07 | data has to come from somewhere.
| | 02:09 | And the way we do it is by
connecting the picker to an object that can be
| | 02:13 | its formal data source.
| | 02:15 | And the data source has to answer two questions.
| | 02:18 | How many components does this picker have,
| | 02:21 | and how many rows does each component have?
| | 02:24 | In this case we will have one
component and we will have maybe a dozen rows.
| | 02:29 | But we also need to connect
this picker to a delegate object.
| | 02:34 | And the delegate answers to more questions:
| | 02:37 | What's in each row, and what happens
when any row is actually selected?
| | 02:42 | Now, you'd be forgiven for thinking
that the data source and the delegate could
| | 02:46 | really be combined into one thing, and it
does feel like that, but we do formally
| | 02:50 | describe them as two different pieces.
| | 02:52 | However, one of the easiest ways to
deal with this is we will nominate our
| | 02:57 | current View Controller as both
the data source and the delegate.
| | 03:02 | And we will put all the necessary
code in that one View Controller.
| | 03:05 | And we support the situation just by
writing methods with particular names
| | 03:10 | inside that View Controller.
| | 03:12 | So back in to XCode. How do I hook this
Picker Control up to my View Controller code?
| | 03:17 | Well, the same way we hooked anything up there.
| | 03:20 | I'm going to jump across to
the Connections Inspector.
| | 03:23 | We could also do this by right-clicking.
And I will see that the Picker Control
| | 03:27 | has two outlets listed here: the two we
just mentioned, dataSource and delegate.
| | 03:32 | Technically, they could actually be
connected to different objects, but I'm
| | 03:37 | going to grab the plus button beside
dataSource and drag it over to File's
| | 03:42 | Owner, which represents the link to
the ViewController.h and ViewController.m
| | 03:46 | files, and I will do
exactly the same with delegate.
| | 03:50 | I can see in the Connections
Inspector they are both registered as being
| | 03:53 | hooked up to File's Owner.
| | 03:55 | Now I am going to jump over into my
header file for that, because if I want to
| | 04:00 | do this properly, what I should also
do is make that promise in my class that
| | 04:05 | we're going to be the delegate and
we are going to be the dataSource.
| | 04:08 | We have talked about using the
little angle brackets before.
| | 04:11 | So after UIViewController, I'm going to
put the opening angle bracket and type in UI, start
| | 04:19 | typing PickerViewDelegate.
| | 04:21 | We see that we have got two options here:
| | 04:23 | UIPickerViewDataSource, UI PickerViewDelegate.
| | 04:26 | We actually need both of these.
| | 04:27 | It doesn't matter which order they are in.
| | 04:29 | So UIPickerViewDataSource, comma, UIPickerViewDelegate.
| | 04:35 | And be careful with the delegates,
because there are many of them, so you don't
| | 04:38 | want to select the wrong one.
| | 04:41 | I am now marking my class.
| | 04:42 | I'm saying we are promising to support,
being both the dataSource and the delegate.
| | 04:46 | One of the benefits of marking it
this way is if I save this and then hit
| | 04:50 | Command+B to build, we are
going to get a compile error.
| | 04:54 | Over here in my Issues Navigator, it's
telling me there is a semantic issue, an
| | 04:59 | incomplete implementation.
| | 05:01 | I can actually expand these ones here
that say there is a method in the protocol.
| | 05:06 | We are promising to support a protocol,
but we are not actually supporting it.
| | 05:10 | Now, we could actually click further
into this to find a few more details, but
| | 05:13 | we actually know what's going on.
Because in my implementation file I said we
| | 05:19 | are UIPickerViewDataSource and we are a
UIPickerViewDelegate, but what does that mean?
| | 05:23 | Multiple ways to find out.
| | 05:25 | One would be holding down the Option key,
| | 05:27 | I'm going to hover over
UIPickerViewDataSource and click it.
| | 05:31 | We will get the popover window.
And I have two ways of getting to the
| | 05:35 | meaning behind this.
| | 05:36 | I could go to the reference and see the
actual documentation of it, and here it
| | 05:41 | would give me the protocol reference
for being a dataSource. What must I do?
| | 05:45 | I can see there's only actually two
tasks, and they are both required.
| | 05:50 | This is where I say how many
components do I have? Number of components in
| | 05:53 | Picker View. And how many rows does
each one have? Number of rows in component.
| | 05:59 | I could copy these and paste them into my code.
| | 06:02 | Alternatively, another way I could
have looked at this is, again, by
| | 06:06 | Option+Clicking it, and instead of going
to the documentation, I could go to the
| | 06:10 | header file for UIPickerView. I click that,
| | 06:13 | it takes me right here to the protocol
for being a UIPickerViewSource, and I
| | 06:19 | have actually got code here.
| | 06:20 | We must provide methods with the signature.
| | 06:22 | Okay, I'm going to copy both of these,
the numberOfComponentsInPickerView
| | 06:28 | and the pickerView: numberOfRowsInComponent. Copy that.
| | 06:32 | This isn't our file.
| | 06:33 | We're deep inside the iPhone OS framework.
| | 06:36 | I need to go back over into my
ViewController.m file, and I am going to paste
| | 06:42 | them inside the implementation.
| | 06:44 | You can put them anywhere.
| | 06:46 | Now, right now these aren't actually
proper signatures, so I need to replace
| | 06:48 | that closing semicolon with an opening
brace, for both of them, and now we have
| | 06:54 | that skeleton functionality.
| | 06:56 | So first, return the
numberOfComponentsInPickerView, one of them return 1.
| | 07:03 | That's it, first step is done.
| | 07:05 | Second, return the numberOfRowsInComponent.
Well, that one is different.
| | 07:10 | I don't actually know right now.
| | 07:12 | What I'm going to do is something fairly simple.
| | 07:14 | I'm going to just create an array
with a certain amount of values in it.
| | 07:18 | I want to access that array from a
few different places in this class,
| | 07:21 | so I am going to go ahead and
just create it as a property.
| | 07:23 | Jumping into my header
file, I will just say property.
| | 07:27 | It will nonatomic and strong,
NSArray, and I will call it moodlist.
| | 07:36 | Jump over into the implementation,
where I want to make sure that I
| | 07:39 | synthesize that. Done. And I want to load that
up with a few values when this application loads.
| | 07:48 | I could do that from a few places, but
one of the places that will work is for
| | 07:52 | me to write it here in viewDidLoad,
moodlist, which is already defined as an
| | 07:58 | NSArray equals--this is where we
create i-t-NSArray alloc, and I'll use the
| | 08:06 | method called initWithObjects.
| | 08:09 | We can just give it a series of strings,
for example, separated by commas, and
| | 08:14 | just finish it off with a nil.
| | 08:19 | Here of course I could have been
loading some information from a web service
| | 08:23 | or from a database like SQLite or using
core data. That's a whole another discussion.
| | 08:28 | So I just want something simple.
| | 08:30 | Seeing as this array is going to be
instantiated as soon as the view has loaded,
| | 08:35 | that's going to be before this
numberOfRowsInComponent is called.
| | 08:40 | And I need to return the
number of rows it should show.
| | 08:44 | I don't want to make a manual count,
but I don't have to. All I am going to say
| | 08:47 | is, return moodlist count.
| | 08:53 | However many options are in it will return
that number, but we are missing something.
| | 08:59 | We had said in our View Controller
that we were going to have the dataSource
| | 09:03 | connected to File's Owner, and we've done that.
| | 09:05 | We've provided the two necessary
methods, but we are also the delegate.
| | 09:10 | Now, what does that mean?
| | 09:11 | Once again, we can hop into the header.
| | 09:13 | We have seen what it means to be a
dataSource, but I could also click here and
| | 09:18 | see what it means to be a delegate.
| | 09:20 | And if I have that PickerViewDelegate
selected, and even reading in Quick Help,
| | 09:24 | the delegate of the UIPickerView must
adopt this protocol and implement at
| | 09:28 | least some of the methods to provide the
pickerView with the data it needs to construct itself.
| | 09:33 | So I am going to come down here
and click on the PickerViewDelegate
| | 09:36 | Protocol reference.
| | 09:37 | Again, the list of tasks that we have,
we don't actually need all of these, but
| | 09:41 | if I scan, we can see things like
Setting the Dimensions of the Picker View, the
| | 09:45 | row height or the width for a
particular component, because when you have
| | 09:49 | multiple components, they are not
all the same width. Take a look at the
| | 09:52 | datePicker. Months and days and
years all have different widths.
| | 09:56 | What we are interested in is the
Setting the Content of Component Rows.
| | 10:01 | Now, notice the text here. The
methods in this group are marked optional.
| | 10:05 | We would be able to compile our
application without providing them, but as it
| | 10:09 | says, to use a pickerView,
you must implement either the
| | 10:13 | pickerView:titleForRow:forComponent or the
| | 10:17 | pickerView:viewForRow:forComponent:reusingView:.
| | 10:21 | Neither of them have a wonderful-
sounding method name, but the one we want is
| | 10:25 | this, pickerView:titleForRow:forComponent.
| | 10:30 | I am going to copy the signature of
that, including the minus sign, jump
| | 10:35 | back over into my code.
| | 10:37 | I want to be in my implementation.
It doesn't matter where I put it, but I'm going
| | 10:42 | to put it after my two
dataSource methods, and paste it in there.
| | 10:47 | I need my opening and closing braces.
| | 10:49 | This is a delegate method, meaning we
don't care about how this is called.
| | 10:54 | We just know it will be called.
| | 10:56 | What's going to happen, automatically, is
that when that picker component loads,
| | 11:01 | it will ask the dataSource how many
components it's suppose to have, and it will be told 1.
| | 11:07 | It will then ask the dataSource how
many rows are in that particular component
| | 11:12 | and be given the answer: Well, how
many entries are in the array?
| | 11:15 | And then this delegate method is
going to be called for every single one of
| | 11:20 | those where we have to provide the
actual correct entry for each correct row.
| | 11:24 | This is simpler than it sounds.
| | 11:26 | We are being given several parameters here:
| | 11:30 | a pickerView, a row number,
and a component number.
| | 11:34 | The only one I'm interested in is the
row number, because I know we only have
| | 11:38 | one pickerView and I know we
only have one component in it.
| | 11:42 | So this method is going to be called
passing in 0, 1, 2, 3, 4. All I need to
| | 11:48 | do is take that parameter of row and use
it to access the correct piece of the array.
| | 11:53 | So I am going to have a return statement
that just says return, and then accesses
| | 11:58 | my moodlist array, which is
already loaded up with values.
| | 12:02 | Whatever object comes from
the particular index of row.
| | 12:06 | Save it, build that, Build
Succeeded, no complaints, and run it.
| | 12:12 | And we have our picker being loaded
up with the information from our array.
| | 12:16 | Of course, we can take this a little
further to see how to respond to these
| | 12:20 | different items actually being
selected, but we will see how to do that in
| | 12:24 | a moment.
| | Collapse this transcript |
| Selecting items in user interface controls| 00:00 | So if we have a customized Picker View
that's been loaded with some data, it's
| | 00:03 | almost certain that what you
want to do is handle a selection.
| | 00:05 | When someone changes the row here, we're
going to do something about it. Let's see how.
| | 00:11 | Going back into Xcode, this is not
something that's done with say a touch up
| | 00:16 | inside, like a button;
| | 00:17 | it's best done by
implementing another delegate method.
| | 00:21 | Now, one of the benefits we have is
we're already hooked up as a delegate to
| | 00:25 | the file's owner; we simply need to
implement another method that we haven't done yet.
| | 00:29 | If I look at my header file, I could
select the PickerViewDelegate area
| | 00:34 | and either use Quick Help, or click
with Option held down and go to the
| | 00:39 | Delegate Protocol Reference.
| | 00:41 | The brief description here--it's not
very long, but we do have this section that
| | 00:45 | says--here's how you respond to a row selection.
| | 00:49 | This Delegate Method is optional,
because perhaps you don't want to respond when
| | 00:53 | somebody changes the actual picker;
maybe you're waiting for something else to
| | 00:57 | happen, like a button touch.
But we do want to respond here,
| | 01:01 | so I'm going to copy the signature
of that, jump back into Xcode, into my
| | 01:05 | implementation, and I'm just going to
paste it in below the other Delegate Method.
| | 01:12 | Need my opening and closing
braces, and look at what we've got.
| | 01:16 | I'm going to split this across a couple of
different rows, just to make it a bit more obvious.
| | 01:20 | This method gives us
three pieces of information:
| | 01:23 | the pickerView, and the parameter
that represents which pickerView;
| | 01:28 | didSelectRow and a row;
| | 01:31 | inComponent and the component.
All I'm interested in is the row.
| | 01:36 | I know what pickerView
it is. We've only got one.
| | 01:38 | I know what component it is. We've only got one.
| | 01:41 | But of course we could have an
interface here with, say, two pickerViews on it,
| | 01:46 | with multiple components on each, and
both of those pickerViews could be hooked
| | 01:50 | up to this class file as the delegate.
| | 01:52 | So then the same method would be
called repeatedly for different pickerViews,
| | 01:56 | and using these different
parameters, I could tell which one it was.
| | 02:00 | Right now I don't have to worry too much.
| | 02:03 | So inside here, what I'm going to do is
first set up a new object called a UIColor.
| | 02:09 | We'll see why in a second.
| | 02:11 | Then I'm going to do a switch statement,
by typing switch and then hitting tab.
| | 02:16 | It will fill in basics for me.
| | 02:18 | What I'm going to switch on
is the integer called row.
| | 02:21 | So I'll just type in row. And then we
have multiple options this could be.
| | 02:26 | The value I'm going to get will be zero based.
| | 02:29 | I'm going to do something fairly
simple here, actually do multiple case
| | 02:33 | statements at the same level.
| | 02:36 | In this switch statement, I'm just
checking various ranges of values and then
| | 02:41 | storing a new color: yellow, gray, or black.
| | 02:44 | I want to make sure that I've got
the break statements in all my cases;
| | 02:48 | otherwise, we'll get some fall-through going on.
| | 02:51 | And you might wonder, what
do these ranges represent?
| | 02:54 | Well, I know that when I created the array
| | 02:57 | I loaded up several different options
here for mood, and they're kind of grouped
| | 03:00 | together into the happy end,
the middle end, and the sad one.
| | 03:05 | So I'm just doing something very simple that
gives each of these its own little category,
| | 03:10 | its own little color coding.
| | 03:11 | And the last thing I'm going to do
after the switch statement is change the
| | 03:15 | background color of the current view.
| | 03:17 | The question might be, well, how I do
this? I haven't hooked it up to anything.
| | 03:20 | I haven't made it an outlet.
| | 03:23 | Well, luckily there's an easy way to get to it.
| | 03:25 | I'm in the ViewController. If I say self--
and I'll do dot syntax here actually.
| | 03:30 | I'll do view.backgroundColor = newColor,.
Save it, run it.
| | 03:39 | Now, when this first loads, that
delegate method is not being called. What I
| | 03:44 | need to do is start
moving around and selecting it.
| | 03:48 | When I let go, I should have that
delegate method called, and it will actually
| | 03:52 | change the background color of the
view. I just changed it to the same one.
| | 03:55 | We go down to the lower end. It
becomes black; in the middle it's gray; up at
| | 04:00 | the high end, it should be yellow.
| | 04:02 | And all of this is being
done through delegation on this.
| | 04:06 | This control itself does not have any
actual touch events happening; it's all
| | 04:12 | being done through the
data source and the delegate.
| | 04:15 | It's another example of how more
complicated UI elements use delegation to
| | 04:19 | handle their behavior and
do anything interesting.
| | Collapse this transcript |
| Using the Apple Human Interface Guidelines (HIG)| 00:00 | Now that we've seen several of the
built-in controls, it's worth stepping back
| | 00:04 | and going to the Apple Developer site,
developer.apple.com. And in the iOS Dev
| | 00:09 | Center, there is a document you really
need to read at some point early on in
| | 00:13 | your iOS career, and it's the Human
Interface Guidelines, or HIG, for iOS.
| | 00:18 | Now, you will often not even need
to be logged in to get to this one.
| | 00:22 | You will often find it just on the homepage,
or you can search for it, if it's not obvious.
| | 00:27 | These are Apple's rules for what your
interface should look like, how it should behave.
| | 00:32 | And they aren't just suggestions.
| | 00:34 | If you deviate too much from these rules,
it's a common reason for your app to
| | 00:38 | be rejected from the App Store.
| | 00:39 | Now, this document is not super technical.
It's not about code.
| | 00:44 | You can get it online on the web,
or you can download a PDF version for
| | 00:48 | printing, et cetera.
| | 00:50 | It's about 180 pages or so,
but it's great, useful content.
| | 00:54 | It's split up into several sections,
including the basics of the platform and
| | 00:59 | the principles behind it.
| | 01:00 | There is a section on your app design
on actually planning the application,
| | 01:04 | creating your definition
statement, figuring your audience out.
| | 01:07 | There are some really good case studies
on things like the conversion of Mail
| | 01:12 | on the Desktop to an iPhone application,
or taking Keynote on the Desktop to a
| | 01:18 | successful iPad application.
| | 01:21 | But there are two other
sections that are particularly useful.
| | 01:24 | The User Experience Guidelines, because
while this section is non-technical, it
| | 01:29 | gets very specific, the short
principles that you should be adhering to,
| | 01:34 | things like de-emphasizing settings, so
you don't have to make your users leave
| | 01:38 | your application to go into the Settings App.
| | 01:41 | And very specific parts, like
making your targets fingertip-size.
| | 01:46 | Down to the level of what exactly that
should mean, that, say, on a calculator all
| | 01:51 | the buttons should have a target
area of the atleast 44x44 points.
| | 01:55 | Further down in the User Interface
Element Usage Guidelines, you have things
| | 02:00 | like the system-provided buttons and
icons, and these are the ones that are
| | 02:04 | actually provided for you by
Apple and available in the iOS.
| | 02:09 | So when you're using things like tab
bars and toolbars and certain terminology
| | 02:14 | for that, you're doing the right ones.
| | 02:15 | Now, this document doesn't
just describe visual items here;
| | 02:19 | there are also sections on things
like audio behavior and expectations.
| | 02:24 | And down towards the bottom of the
document is the Custom icon and Image
| | 02:28 | Creation Guidelines. It covers in depth
things like the size of your application
| | 02:32 | icons, what they should be for a regular
iPhone versus the Retina display, and so
| | 02:37 | on, the size of your app icon,
the size of launch images.
| | 02:42 | Now, we'll come back to these a little later on.
| | 02:45 | So these are very specific
guidelines that you must pay attention to.
| | 02:49 | Not only is this documentation full of
really good content, do remember that
| | 02:53 | if you deviate too much from it, it
can be a reason for your app to be
| | 02:57 | rejected from the App Store.
| | Collapse this transcript |
|
|
7. Using Table ViewsIntroduction to table views| 00:00 | You might think Table Views sound
like a new thing to learn, but you really
| | 00:04 | already know what's in this section.
| | 00:06 | You have already used table views.
| | 00:08 | If you've used the Settings
application, if you've used the iPod or Music
| | 00:13 | application, you've used Safari or Mail.
| | 00:16 | You have used Table Views.
| | 00:17 | They're everywhere.
| | 00:18 | They're very common.
| | 00:20 | Anytime you see a list like this
that you can scroll up and down.
| | 00:23 | It's pretty much in that Table View.
| | 00:25 | Now if you've thought about it you
might have thought things like this would
| | 00:28 | different, because they can look
quite different from each other.
| | 00:31 | Some have big text, some have big
text and small text, some have images,
| | 00:36 | but they're all Table Views, and probably
the most common control in an iOS application.
| | 00:43 | So let's talk about some core principles here.
| | 00:46 | All Table Views are one column wide. That's it.
| | 00:50 | It might occasionally look
like more than that, but it isn't;
| | 00:53 | Table Views are one column wide.
| | 00:55 | Now these table views don't
store your data. They just show it.
| | 01:00 | So don't get them confused with
database tables, for example. This is MVC.
| | 01:06 | These are view objects, and they
show data that is stored somewhere else,
| | 01:11 | whether that's in an array or a
property list or one of your own objects.
| | 01:16 | As you scroll these Table Views up and
down, each piece of data that you see in
| | 01:21 | a Table View is considered one row, and
each row contains one UITableViewCell.
| | 01:29 | And even when you see Table Views with
significantly different formatting, plain
| | 01:34 | text, bold text, perhaps even
images in those individual elements.
| | 01:38 | It's because that one cell has been
formatted to populate the cell with more
| | 01:43 | than just a basic piece of text.
| | 01:45 | But we want to know how to
start working with these.
| | 01:47 | So what we have to do with a Table View
is fill it with data, and the way we do
| | 01:52 | that is by hooking up the Table View
control to a data source, very similar to
| | 01:57 | working with the Picker.
| | 01:58 | We have to have a class defined as the
data source for this Table View, and in
| | 02:03 | that data source we can say at its most basic,
how many rows exist and what's in each row.
| | 02:09 | And you can also say little bit more such as,
is that Table View split up into sections?
| | 02:15 | And that's what the data source provides.
| | 02:17 | There is also a Table View delegate
which can handle things like what happens if
| | 02:22 | somebody selects one of these rows.
| | 02:24 | Do I want to do something, do I
want some operation to happen?
| | 02:27 | We need to hook up our Table View to a
class, and very commonly that's going to
| | 02:33 | be our View Controller.
| | 02:34 | It doesn't have to be the View Controller.
| | 02:36 | You can make your data source, or your
delegate any class in your application,
| | 02:40 | but we're going to use the View
Controller and put the necessary methods in
| | 02:44 | there to see an example of one of these.
| | Collapse this transcript |
| Creating a table view| 00:00 | So I have a single view application right now.
| | 00:03 | There's no change from the default project type.
| | 00:05 | I am going to go into XIB file and
from my Object Library, I am just going to
| | 00:10 | filter on the word Table.
| | 00:13 | I'll see three things here: the
Table View, the Table View Cell, and the
| | 00:16 | Table View Controller.
| | 00:17 | I want a Table View.
| | 00:20 | I already have a View Controller.
| | 00:21 | I am going to click that guy, drag it
across, and make it fill this screen.
| | 00:26 | If I look at my Attributes Inspector,
there is not an awful lot we can do.
| | 00:32 | We can change a few things about the
Table View like whether it's plain or
| | 00:36 | grouped, and we'll see that in a little while.
| | 00:38 | The important thing I need here is in
the Connections inspector, the last part
| | 00:43 | of the Inspector panel.
| | 00:44 | My two outlets for dataSource and
delegate, and both of these I am going to hook
| | 00:50 | up to File's Owner, so we can just
write the code in our View Controller class.
| | 00:54 | dataSource over to File's Owner
and delegate over to File's Owner.
| | 00:59 | What I want to do is populate this
table view with some data that's actually
| | 01:03 | stored in a file right now.
| | 01:05 | I have a file called
courses.plist which is on my Desktop.
| | 01:10 | You can get it in the exercise
files or create one yourself.
| | 01:13 | So I am going to grab courses.plist,
and I'll talk about this in a moment.
| | 01:17 | I am just going to drag it over into my project.
I'll put it in the Supporting Files folder.
| | 01:22 | It doesn't really matter where it
goes, as long as it's in the project.
| | 01:26 | Now when this window pops up, it's
very important that we choose to copy the
| | 01:31 | items in to the destination group's
folder if needed so that we have our own
| | 01:36 | copy of it, and it's not just
linking back to it on the Desktop.
| | 01:39 | We want to keep all our files together.
| | 01:41 | So I have courses.plist here.
| | 01:43 | This is a property list file, and all
I have in it is a list of a few courses
| | 01:49 | from lynda.com related to iOS and their authors.
| | 01:53 | You can of course create property
list files yourself if you go to the
| | 01:57 | Xcode New File menu.
| | 02:00 | One of the options that you will find in
the Resource section is a Property List file.
| | 02:06 | Creating this--and you don't have to,
I am just going to create a dummy one
| | 02:10 | here--would give me this plist file
with keys and values, and all I have really
| | 02:15 | done is do the equivalent of putting in a
course title and tab over and the author goes here.
| | 02:21 | Hit Return a couple of times to get a new one.
| | 02:25 | I haven't done anything more complicated
than creating multiple entries like this.
| | 02:29 | I'm going to delete that plist
file because I don't need it.
| | 02:32 | Choose to delete the whole thing.
| | 02:34 | The only thing to bear in mind here is
that I'm using these as keys and values
| | 02:39 | and keys need to be unique.
| | 02:41 | So I can't have a duplicate entry in
this left column, although it doesn't matter
| | 02:46 | if I have duplicate entries on the
right; the key is the important part.
| | 02:50 | So I want to load this file into
our application when it's running.
| | 02:55 | Now to do this, I am first going to
jump over to my ViewController.h file,
| | 02:59 | because I am going to define a couple of
objects that can hold this in our application.
| | 03:05 | First I am going to define
NSDictionary object, which will hold multiple keys
| | 03:09 | and values, the course name and the author.
| | 03:12 | Then because a dictionary doesn't have a
numeric index--it's all based on the keys--
| | 03:18 | it would actually be quite useful
in this example for me to have one.
| | 03:21 | So I am going to create a simple NSArray,
so that I can make a numeric index for this.
| | 03:26 | And what I can make in a moment is a zero-based array that will just contain all
| | 03:32 | the keys for that dictionary.
| | 03:34 | So, I jump across to the implementation
file because here I do need to synthesize
| | 03:39 | both of those properties.
| | 03:41 | I am going to go ahead and drop down
into--viewDidLoad will work here, to write
| | 03:48 | some code to load in that file.
| | 03:50 | First thing I need to do is construct
a string that has the path to the file.
| | 03:56 | And the question is, well how do
I get to that well? Here is how.
| | 04:01 | Split that out a bit.
| | 04:02 | Now what I'm doing here is using
this NSBundle mainBundle method call.
| | 04:08 | This is really a way of getting to the
installed file system on the iOS device
| | 04:13 | when I don't quite know what it is.
This line might look a little strange.
| | 04:17 | It's really a way of obtaining that
courses.plist file that's part of our
| | 04:21 | internal bundle, our
internal packaged application.
| | 04:25 | We don't have direct access to the file
system on an iOS device, so this is the
| | 04:30 | way we get hold of our own assets.
| | 04:32 | Well next, I need to create that
NSDictionary that I've already defined.
| | 04:37 | It was called courses. And I'll
set it equal to NSDictionary.
| | 04:44 | We'll do a normal alloc, but I'm
going to initialize and the useful method
| | 04:50 | I have is this one,
initWithContentsOfFile. And I am going to just use the myFile
| | 04:56 | string that I created on line 26.
| | 05:00 | So really we're just grabbing the path to
that file and loading it into the NSDictionary.
| | 05:05 | Now the next thing I am just going to
do from that dictionary, I am going to
| | 05:09 | create that array just so I have a
numeric-based way of getting to all the
| | 05:14 | keys in the dictionary.
| | 05:16 | I can do that very easily by just
calling the allKeys method of the NSDictionary.
| | 05:22 | That's all I need to load the file and
create my NSDictionary and my NSArray.
| | 05:26 | I have got all that information in my app;
| | 05:28 | I am just not doing anything with it yet.
| | 05:31 | Well, in our interface file, we had
already decided that our Table View is
| | 05:35 | hooked up to File's Owner as the
dataSource and delegate, but what does that mean?
| | 05:40 | Formally speaking, what I should do in
this class definition is volunteer and
| | 05:46 | say we are now a
UITableViewDataSource, comma, and a UITableViewDelegate.
| | 05:54 | And one of the best reasons for
doing this is just so we can Option+Click
| | 05:57 | on them and actually link to either the
protocol reference or just to the header file.
| | 06:02 | Either way would work. And it's going
to tell me that if I'm volunteering to be
| | 06:06 | a UITableViewDataSource, there are a
couple of required methods that I must
| | 06:12 | implement, which is this one, tableView:
| | 06:16 | numberOfRowsInSection and this one tableView:
| | 06:19 | cellForRowAtIndexPath.
| | 06:23 | I am going to grab this whole block here
in between the @required and @optional,
| | 06:29 | copy it, jump back over into my
implementation, and I will paste it a couple of
| | 06:35 | lines after my synthesize message.
| | 06:37 | I am going to just get rid of that
comment so we can read this a little better.
| | 06:42 | And of course I just copied the
declaration, so I need to add some curly braces
| | 06:46 | on both of these method
signatures to make sure I can add my code.
| | 06:51 | So watch this first one here: tableView:
| | 06:54 | numberOfRowsInSection. So how many rows
are there going to be in the Table View?
| | 07:00 | Well, that all depends. How many
entries are in that courses plist file?
| | 07:04 | Well, they are going to be loaded into
the NSDictionary, so all I really need to
| | 07:08 | do is return courses count.
| | 07:13 | This next method is really
the important one, tableView: cellForRowAtIndexPath.
| | 07:21 | This method will be called multiple
times and every time it's going to pass in
| | 07:26 | a new index position: zero,
then one, then two, then three.
| | 07:30 | We need to build a create the
contents of each row and pass it back.
| | 07:35 | If you notice, that's what we
have to return, a UITableViewCell.
| | 07:40 | This is our job as the data source.
| | 07:43 | So I'm going to go ahead and
first create a UITableViewCell.
| | 07:50 | I'll just call it cell, we alloc it.
And I am going to use one of the more
| | 07:56 | interesting inits, which is initWithStyle.
| | 07:59 | What does this mean?
| | 08:00 | Well, the different TableViewCells
can have different styles.
| | 08:04 | This is an enumeration, so if I start
to write--there we go--it pops up here,
| | 08:08 | UITableViewCellStyleDefault,
UITableViewCellStyleSubtitle.
| | 08:13 | I am just going to go with Default right now.
| | 08:15 | We'll see the other ones later.
| | 08:17 | And then we have another argument here,
reuseIdentifier, which accepts an NSString.
| | 08:23 | Right now, I'm just going to give
it a string of cell, all lowercase.
| | 08:29 | What we're really doing
is tagging this new object,
| | 08:32 | this new cell, with a name. And the
reason why you might use that reuseIdentifier
| | 08:36 | is you could have several different
kinds of cells in your application, some
| | 08:40 | with images, some without,
some with subtitles, some without.
| | 08:43 | And we'll see this in the next movie.
| | 08:45 | We're only going to have one kind of
basic cell, so we can call it whatever we want.
| | 08:50 | I could say cell. I could say Fred.
| | 08:52 | I could say ABC. It's just a tag.
| | 08:55 | So the cell is now created, but we
are not doing anything with it yet.
| | 09:00 | I need to give it some kind of
value, some piece of information.
| | 09:03 | I am going to create a new NSString
object that holds a course name, and I'm
| | 09:08 | going to go and grab that from the
array that we created a little earlier.
| | 09:14 | This is a zero-based array that's going
to contain all the names of the courses
| | 09:19 | that I have pulled out of the NSDictionary.
| | 09:21 | The question is, how do I
know which position to go to?
| | 09:24 | Well, it's been passed into this
method, and the cellForRowAtIndexPath gives me
| | 09:30 | an index path parameter
that I can use to get to that.
| | 09:33 | Again, if you're puzzled about how
was this method being called, don't
| | 09:37 | worry about it; the Table View is calling it
automatically because we are the dataSource.
| | 09:42 | So this method gets called multiple times,
passing in different row numbers every time.
| | 09:47 | We just have to grab the row number and use it.
| | 09:50 | So I am going to go into that array
using objectAtIndex and I'm using the
| | 09:55 | indexPath parameter that gets passed
into this method, but not just indexPath,
| | 09:59 | just a part of it that says indexPath.row.
| | 10:03 | Alternatively here again, I
am using dot syntax there.
| | 10:07 | I could also use square brackets
and just say indexPath, space, row and access
| | 10:12 | the property that way.
| | 10:14 | We should now have a string, and what
I'm going to do is set the textLabel
| | 10:20 | on that cell object that we have just created
and set its text to the currentCourseName.
| | 10:28 | Finally, this method needs
to return a UITableViewCell.
| | 10:32 | Well, we created one. We changed the text on it.
| | 10:35 | I'll say return cell.
| | 10:38 | Save it and we'll find out if I missed anything.
| | 10:42 | It looks pretty good actually.
| | 10:44 | We have got the Table View. It's scrollable.
| | 10:46 | It's loaded with data.
| | 10:48 | Now technically it's a little
inefficient right now, and I'm going to talk about
| | 10:52 | proper ways that we should be creating
those cells that are more recommended
| | 10:56 | techniques for doing it.
| | 10:58 | But this is the general process:
| | 11:00 | we add a Table View, we hook it up to
a dataSource, we provide the required
| | 11:05 | methods to say how many rows does it
have and what's in each row, and we return
| | 11:10 | a cell for each different row that we have.
| | Collapse this transcript |
| Reusing table cells| 00:00 | An important part of working with
table views is reusing your table view cells
| | 00:05 | correctly, and here's the problem this solves.
| | 00:07 | Imagine we have a table view
with a large amount of data.
| | 00:10 | It could potentially be hundreds of rows.
| | 00:12 | And as we swipe up and down, new cells
are being created for that table view so
| | 00:17 | that new rows can be seen.
| | 00:19 | But there is the question: If we're
swiping up and down all the way, do we
| | 00:23 | potentially have all of these in
memory, even the ones that we can't see?
| | 00:27 | Because of course all we're
interested in is the stuff visible at
| | 00:31 | that particular moment.
| | 00:32 | We don't need cells in memory if they
aren't being displayed and can't be touched.
| | 00:36 | Well, actually the idea for this is
already built into the table view control,
| | 00:41 | and with just a little bit of
code, we can make use of this.
| | 00:44 | So the solution is this.
| | 00:46 | We have the table view control, and
when a cell moves off the visible section,
| | 00:51 | it becomes dequeued.
| | 00:54 | The table view control itself
knows that this is not visible.
| | 00:58 | So rather than us creating a new cell
object, we can ask of the table view if it
| | 01:04 | has any dequeued cells available, and
if so, what we can do is just reuse one
| | 01:10 | instead of creating a new
table cell from scratch.
| | 01:13 | So I'm back to the code that I had
for creating the table view cell.
| | 01:19 | On line 21 through 23 we're
creating and allocating that cell.
| | 01:24 | We're setting its values and
then on line 28, we return it.
| | 01:28 | Well, I don't know for sure that there
will be a reusable cell available every
| | 01:32 | time, so I'm going to ask for one.
| | 01:36 | I'll create a new UITableViewCell, and
the way I'll do it is by asking the table
| | 01:42 | view--and the table view is being
passed in here as a parameter--to
| | 01:47 | dequeueReusableCellWithIdentifier.
| | 01:51 | I'm going to ask, are there any
reusable cells with the identifier of cell?
| | 01:58 | Again, this is just the tag
that we used to create that.
| | 02:02 | Now that line can't guarantee
me that I actually have one.
| | 02:07 | There may be a reusable cell
available, but maybe this is right after the
| | 02:11 | application's opened and there isn't any.
| | 02:14 | So what I'm going to do below it is ask.
I'm going to write an if statement.
| | 02:18 | If cell = nil, or if you prefer
to phrase it around the other way,
| | 02:23 | iust in case you do the
single equals sign, if nil = cell\,
| | 02:28 | I'll copy this code that actually
allocates and initializes a cell with
| | 02:32 | that same identifier.
| | 02:34 | I have my Pointer symbol in there.
| | 02:37 | So we already declare it up here and we
try and grab one from the table view.
| | 02:42 | If we hit the next line and I don't actually
have one, then we allocate and initialize it.
| | 02:48 | Either way, by the time we get to line
29, we have a UITableViewCell, we set the
| | 02:54 | details on it, we return it. But we're
not creating a new cell if we don't need to.
| | 03:00 | Save it, run it, and everything works just fine.
| | 03:04 | It's actually a little bit quicker.
| | 03:06 | It's more efficient. It's better practice.
| | 03:08 | This is something you should
always be doing with your table cells.
| | Collapse this transcript |
| Customizing a table view| 00:00 | So if this was what all our table views
could do, it would be pretty limited, but
| | 00:04 | luckily they are more flexible.
| | 00:06 | And we still have to work with a
limited amount of space, but let's see a couple
| | 00:09 | of the other things we can do for them.
| | 00:11 | So I'm going to deconstruct some code
here rather than do it all from scratch.
| | 00:16 | I have a very similar project to the
one I've created before, but rather than
| | 00:20 | just having this one plist file, I've
now added a second plist file with a
| | 00:24 | second set of courses. And what I'd like to
do is change the appearance of this Table View.
| | 00:31 | Now luckily a lot of this is already built-in.
| | 00:34 | I'm going to open up my Utilities panel,
and with that Table View highlighted,
| | 00:38 | I'm going to shift it from the normal
style of Plain into Grouped. And you've
| | 00:44 | probably seen this before when using
things like the Settings application, that
| | 00:48 | we now have multiple sections in the Table View.
| | 00:51 | Again, it's just showing dummy data,
but we can fill this in ourselves.
| | 00:55 | So here's how we support this.
| | 00:56 | I'm going to jump into my header file.
| | 00:59 | I've got a couple of
lines that are commented out.
| | 01:00 | I'm just going to explain what they are.
| | 01:02 | On line 13 and 14 is where I set up
the NSDictionary and NSArray to hold my
| | 01:08 | details about the first files.
| | 01:10 | I'm just going to uncomment line 17
and 18, where I'm essentially doing the same
| | 01:15 | thing but with a different NSDictionary
and different NSArray, because I need to
| | 01:19 | hold them all in memory at the same time.
| | 01:21 | Up in my implementation file, I better
have a synthesize statement for those two
| | 01:25 | new properties, and while I've got a
little bit of code that I'll come back to,
| | 01:30 | I'm just going to jump down to my viewDidLoad.
| | 01:32 | I could scroll down. Another thing I can use
is the Jump Bar here and jump to viewDidLoad.
| | 01:38 | That was where I was loading in the
files originally, and it's where I've also
| | 01:42 | got the code to load in the next file.
Pretty much duplicating exactly that.
| | 01:49 | We're making new path, we're
loading in the NSDictionary with
| | 01:52 | initWithContentsOfFile, and we're
creating an array. Nothing particularly
| | 01:58 | magical on that one.
| | 02:00 | But that by itself won't do it.
| | 02:02 | We've seen that we're implementing
this data source protocol, and previously
| | 02:08 | what we've been implementing on this
were the required methods, which were how
| | 02:13 | many rows in a section and
what's the cell for each row?
| | 02:17 | However, there's a couple of optional
methods we can also provide, like number
| | 02:23 | of sections in the Table View, and
this is the important one if we want to
| | 02:27 | group different sections.
| | 02:29 | So as you see the comment is, if we
didn't provide this, the default would be 1.
| | 02:33 | Well, I do need to provide this.
| | 02:36 | So in my implementation I have it, and
I've actually written it up at the top.
| | 02:40 | I'm going to uncomment it there.
| | 02:42 | We have the number of sections in Table View
and instead of one, we're going to return 2.
| | 02:48 | Not only that, but in my number of rows
in section, I can't just return the count
| | 02:54 | of the dictionary, because I've
got two different dictionaries now.
| | 02:57 | So instead, I have this version.
| | 03:00 | We're just asking, which section is it?
| | 03:03 | If I'm in the first section, I return
the count of the first course's file.
| | 03:07 | If I'm in the second one,
I'll return the new one.
| | 03:10 | Here's another optional
method that I just had commented--
| | 03:14 | I'm going to uncomment this--which allows us
to provide a different title for each section.
| | 03:20 | This will be called twice, the first
time I'm passing in a section parameter of
| | 03:24 | 0, second time section number of 1.
| | 03:27 | So we'll first set iOS Courses,
the second block is Web Courses.
| | 03:31 | And finally we have the work that we need to do.
| | 03:35 | We can't just access one array
or one dictionary object here.
| | 03:40 | Instead of grabbing the current
course name from the courseKeys array,
| | 03:44 | I'll comment that one out, because we have to
do something very similar to the previous code.
| | 03:50 | We have to ask what section we're in.
| | 03:52 | If we're in the first section,
I'll use the courseKeys array;
| | 03:55 | if we're in the second section, I'll
use courseKeys_web. We save that.
| | 04:01 | I'm going to build it, Build Succeeded, and
let's run it and see what the end effect is.
| | 04:06 | And we have quite a different look now.
| | 04:09 | We've got the iOS Courses header here,
showing this group, and as I scroll down,
| | 04:15 | the Web Courses, showing the second group.
| | 04:17 | We're still reusing cells and all the
other good stuff, the best practices, but
| | 04:22 | this is the ability to group your
content into sections by simply implementing a
| | 04:27 | couple more methods of
the UITableView data source.
| | 04:30 | But even this I think could be improved
a little bit, so let's take it further
| | 04:34 | next by customizing not just the Table
View, but the individual cells themselves.
| | Collapse this transcript |
| Customizing table view cells| 00:00 | You can do a lot more with table riew
cells other than just having a single line
| | 00:04 | of text, like we're looking at here.
| | 00:06 | Now, you can go all out and start
creating your own table view cells, even using
| | 00:10 | Xcode to design them.
| | 00:12 | While we're not going to do that here,
there're a few things we can do just with
| | 00:16 | a line or two of code.
| | 00:18 | So, I'm going to go back into Xcode,
into this project I have here, very similar
| | 00:22 | to what I've been building
in the last couple of movies.
| | 00:24 | We're using a grouped table view and
I'm loading in information from two
| | 00:28 | different property list files.
| | 00:30 | I've just added a little code that's currently
commented out and I'm going to go through that.
| | 00:35 | So as we've seen, the primary method
to actually create the contents of the
| | 00:40 | cell is the tableView:
| | 00:41 | cellForRowAtIndexPath. And up to this
point, we've been grabbing the name of the
| | 00:48 | course just by going against the arrays
that we created from those property list files.
| | 00:53 | However, the dictionaries we
created should also have the author name.
| | 00:57 | So what I'm going to do in this lower
section here is ask, what section are we in?
| | 01:04 | If we're in the first section, what
I'm going to do is use the same call that
| | 01:08 | I've been doing on earlier lines, go and
find the course name, and then use that
| | 01:13 | course name as the key for the
dictionary, to then retrieve the author name.
| | 01:18 | Now, in the same way, that on line 57
here we have this cell TextLabel setText
| | 01:24 | call, which we've been using all
along to set the main text of the cell,
| | 01:28 | we also have a detailTextLabel, and here
I'm setting the other part of the cell.
| | 01:34 | Now, if I save this and run it,
let's take a look at what it does.
| | 01:39 | Well the answer is, not very much.
| | 01:41 | I can't see a change at al,l and
that's because the default style that we're
| | 01:46 | looking at for TableView cells doesn't
allow that bit of detail text to show up.
| | 01:51 | We have to change something
about it to make it show up.
| | 01:55 | Quit and return back into the code.
And it's all to do with the line of code
| | 02:00 | where we actually create, allocate,
and initialize that cell object.
| | 02:05 | We're initializing it with the
style of UITableViewCellStyleDefault.
| | 02:10 | This is an enumeration.
| | 02:12 | So if we start typing
UITableViewCellStyle, we should see under that,
| | 02:17 | UITableViewCellStyleDefault,
CellStyleSubtitle, Value1, Value2.
| | 02:22 | I'm going to switch to the
SubtitleStyle. Save it, run it.
| | 02:28 | Now what we find is we have the
subtitle display, and it's actually doing a
| | 02:32 | little more than just showing the subtitle.
| | 02:34 | Whether it was noticeable or not, it's
or not it's also slightly shrinking the
| | 02:38 | size of the main black text.
| | 02:40 | The subtitle view is very commonly
seen inside things like the music
| | 02:43 | application, so we can
have song and album or artist.
| | 02:46 | So what else we can we do?
Well, going back into the code,
| | 02:50 | I'm in the same method here, but below
there, I have a few lines of code that's
| | 02:54 | going to allow us to retrieve an image.
| | 02:57 | I'll just squeeze this all onto the same line.
| | 03:00 | Now, this image I've actually
already dragged into my supporting files.
| | 03:05 | It's just a simple PNG file.
| | 03:08 | It's 44x44 pixels, which is the default
height of a UI TableView cell. And it's
| | 03:14 | kind of an Apple guideline for the
average best size for a finger touch.
| | 03:18 | So, I jump back into my implementation
and what I'm doing here is grabbing a
| | 03:24 | path to that cell image the same way
I grabbed the path to the property list
| | 03:29 | files, using the NSBundle
mainBundle call pathForResource.
| | 03:34 | On Line 73, we create a new UIImage
object just using the initWithContentsOfFile
| | 03:41 | method, and then on Line 75 find out
that cell has an imageView property. The
| | 03:46 | same way that it has a textLabel
property and it has a detailTextLabel property,
| | 03:51 | there's the imageView, and we call setImage.
| | 03:55 | Save that, run it, and because we're
not doing anything conditional, we're
| | 03:59 | using the same image for all of them,
but it doesn't seem to have a problem
| | 04:03 | loading any of them in.
| | 04:04 | Now, while the image goes on the left
by default, you can also affect what's
| | 04:09 | going on on the right.
| | 04:11 | Back into the code, we have
this thing called accessoryType.
| | 04:15 | It's a strange name if you haven't come
across it before, but it means to add an
| | 04:18 | accessory, to add a little addition to this cell.
| | 04:21 | I'm using .syntax here.
| | 04:23 | I could also have called cell
setAccessoryType. And our options are
| | 04:28 | another enumeration.
| | 04:31 | If I start typing
UITableViewCellAccessory, we see we've got AccessoryNone,
| | 04:36 | which is the default,
DisclosureIndicator, DetailDisclosureButton, Checkmark.
| | 04:41 | I'm going to use
UITableViewCellAccessoryDisclosureIndicator. Save that, run it.
| | 04:49 | What it's now adding is the little
disclosure indicator here, which is that arrow.
| | 04:54 | Now, you've probably seen this one a lot.
| | 04:56 | What you're often probably used to
is being able to click it and be taken
| | 05:00 | somewhere else, and we'll
talk about that in a second.
| | 05:03 | But obviously, we have multiple
options for this UITableViewCellAccessory.
| | 05:09 | We have things like the
DetailDisclosureButton, and if I use that, we get a
| | 05:15 | different icon there.
| | 05:16 | Now, bear in mind that you really
want to be reading the Human Interface
| | 05:20 | Guidelines when you start to use these
things, because a lot of people pick the
| | 05:24 | DisclosureButtons and the
DetailDisclosureButton as if they're identical and
| | 05:27 | it's just some aesthetic
choice and it's really not;
| | 05:30 | they are meant to mean two separate things.
| | 05:32 | So pay attention to those
interface guidelines that Apple published.
| | 05:36 | But what does this actually do?
| | 05:38 | We're often used to seeing something
like this and thinking "Well, that's
| | 05:42 | touchable. That row is selectable."
| | 05:44 | We might be expecting it to shoot off to
the left and bring in a new view on the right.
| | 05:49 | Now, when you've used the applications
where it seems you must be drilling down
| | 05:53 | from one part of a TableView to another,
| | 05:56 | if you're thinking that must be a
nested TableView or a TableView inherently
| | 06:00 | with multiple levels, it's really not.
| | 06:03 | We're typically going from one view
controller to a completely different view controller.
| | 06:08 | It just looks like it's a nested control.
| | 06:11 | The complexity of a lot of applications
is actually tying your view controllers
| | 06:16 | together so we can move from side to
side and interact with table views and
| | 06:20 | other elements like
buttons and navigation controls.
| | 06:23 | So, we're going to get into that as we
get into the idea of applications with
| | 06:28 | multiple views. But you can see with
just a few basic lines of code how we can
| | 06:33 | start to affect the image, the
disclosure buttons, the accessory, the subtitles,
| | 06:38 | and the text on a TableView cell.
| | 06:40 | And if you want to take it even further
than this, you can even create your own
| | 06:44 | TableView cells where you specify
exactly what the full layout of these are.
| | Collapse this transcript |
|
|
8. Creating Apps with Multiple View ControllersIntroduction to multiple-view applications| 00:00 | Everything we've done so far
has been on one main screen.
| | 00:03 | All the examples I've shown have used
the single view application project type,
| | 00:08 | one view controller made of
.a, .h, .m, and .xib file.
| | 00:13 | And this is not a bad thing;
| | 00:14 | there're perhaps hundreds of thousands
of single view applications for sale in
| | 00:18 | the App Store today, but it's not always enough.
| | 00:21 | Now, these can be made a
little bit more flexible.
| | 00:24 | You can group multiple controls into
sections and hide them or show them, but
| | 00:29 | it's quite common to hear phrases like
"I need more than one screen or more than
| | 00:32 | one page or more than one window,"
though you need to be really specific about
| | 00:36 | what those words mean on iOS, as we don't
have multiple windows the way you might
| | 00:41 | have on a desktop app.
| | 00:42 | We have one window.
| | 00:44 | Okay, with very few exceptions, such as
connecting an iPad to an external display,
| | 00:50 | an iOS has one window object, and it
takes up the entire device screen.
| | 00:57 | It's transparent. But what we can do is
move multiple views in and out of that
| | 01:02 | window, and a good example of this is
what's known as a Utility Application, like
| | 01:06 | the Stocks app or the Weather app on the iPhone.
| | 01:09 | They have two very separate view
controllers: a MainViewController and a
| | 01:14 | FlipsideViewController, and you go between them.
| | 01:16 | Each of these is an entirely
independent view controller with its own .xib, its
| | 01:21 | own .h and .n file and they're
handing responsibilities back and forth.
| | 01:26 | But these views don't even have to take
up the entire window, and they don't have
| | 01:31 | to completely replace each other.
| | 01:33 | We can load them in layers.
| | 01:35 | So another very common model is that
we load in one view into our window,
| | 01:39 | here represented by view controller 1, that
itself is there to help manage other views.
| | 01:45 | This would be quite common with a tab
bar, and what then happens is this helps us
| | 01:50 | move other views in and out of the
application. And these different pieces of the
| | 01:55 | app can be built as completely separate
view controllers, with their own header
| | 01:59 | and implementation files and their own .xib.
| | 02:01 | So, in your applications, you
want to be comfortable with switching
| | 02:05 | between different views.
| | 02:07 | It's a very common iOS task,
| | 02:09 | so we're going to explore a
few different ways of doing this.
| | Collapse this transcript |
| Deconstructing a utility app| 00:00 | We're going to begin working with
multiple view controllers by using the Utility
| | 00:04 | Application that Apple provides.
| | 00:07 | So selecting an iOS Utility
Application I'm just going to call
| | 00:11 | this UtilityExample.
| | 00:13 | I want to make sure that for right now
we're still not using Storyboard, but we
| | 00:16 | are using Automatic Reference Counting.
| | 00:19 | I'm going to click Next
and create it on my desktop.
| | 00:24 | Notice straightaway over here in the
Project Navigator, there's not just one
| | 00:28 | View Controller, but two sets of them:
| | 00:30 | the MainViewController.h and .m files,
the FlipsideViewController.h and .m files
| | 00:36 | and the Corresponding.xib.
| | 00:39 | So two sets of view controllers.
| | 00:41 | So what's happening when this app runs?
| | 00:43 | Well, let's take a look.
| | 00:45 | If I jump into the AppDelegate
implementation file and look at the main startup
| | 00:50 | method, which is application
didFinishLaunchingWithOptions--don't worry too much
| | 00:55 | about remembering this exact syntax;
| | 00:56 | that's not important here--
| | 00:58 | but what I can see is on line 20 I'm
instantiating a UIWindow object. That's our
| | 01:03 | transparent boundaries on our entire screen.
| | 01:05 | On line 22 I create a new
instance of the MainViewController.
| | 01:11 | I load that into the window on line 23,
and on line 24 I make the window visible.
| | 01:16 | So the AppDelegate is taking care of
loading this guy, MainViewController.
| | 01:22 | So if I go into my XIB file, I can see
that I've got a fairly dark background here.
| | 01:27 | There's nothing special about it.
| | 01:29 | If I look at my Inspector, what I
can see is we've just changed the actual
| | 01:33 | background of that to be this dark color.
| | 01:36 | Other than that, it's the same as what
we've been using all along, except we do
| | 01:40 | have at the lower-right, this button here.
| | 01:42 | Now, this is a regular Round Rect button.
| | 01:45 | There's nothing special about it; the
only difference is it had its type changed
| | 01:50 | from the regular Rounded
Rect into an Info Light button.
| | 01:54 | Well, knowing what we know about buttons,
we can see if it's hooked up to anything.
| | 01:58 | I could either right-click the
button, though it's a little small.
| | 02:01 | I'll make sure it's selected and go to
my Connections Inspector, and I can see
| | 02:05 | that I've got my Touch Up event is
hooked up to File's Owner looking for a
| | 02:09 | method called showInfo.
| | 02:11 | Well, I can presume that that showInfo
method should be in the corresponding
| | 02:15 | implementation file for MainViewController.
| | 02:18 | I can either scroll down or
use the Jump Bar to find it.
| | 02:21 | There we go, showInfo.
| | 02:23 | So what's happening here?
| | 02:25 | We have four statements.
| | 02:26 | On line 70 we're going to
allocate and initialize a instance of
| | 02:30 | FlipsideViewController, and
we'll call it controller.
| | 02:34 | Then on line 71 we'll say, hey
controller, your delegate is self, meaning the
| | 02:40 | FlipsideViewController's
delegate is the MainViewController.
| | 02:43 | We'll talk about why
that's important in a second.
| | 02:46 | Then on line 72, we say the
controller's modalTransitionStyle is
| | 02:51 | UIModalTransitionStyleFlipHorizontal.
| | 02:54 | You might make a guess, but that's
what's going to do the horizontal flip in the
| | 02:58 | Utility app for us, and that is indeed
it. And then finally on line 73 we say
| | 03:03 | presentModalViewController,
| | 03:05 | passing in that view controller we
just created and saying animated:YES.
| | 03:11 | That is going to present the new
view controller and make it the boss.
| | 03:15 | If we run this to test it, I
can expect this to just work.
| | 03:20 | The MainViewController
loads, we click the button,
| | 03:23 | it creates the new one, flips it horizontally.
| | 03:26 | I could click the Done button and go back.
| | 03:29 | I'll quit out of this and back into the code.
| | 03:32 | So that's how we're handling it from
the main view to the flipside view. What
| | 03:36 | about the other way round?
| | 03:38 | It's a little different.
| | 03:39 | So, I'm jumping to the
FlipsideViewController.xib file here, where we can see
| | 03:44 | we've got a Done button at the top.
| | 03:46 | This is using what's called a
navigation bar and a bar button item.
| | 03:50 | It's a little different from
a regular Round Rect button.
| | 03:53 | Even so, I can see using my Connection
panel that this Done button is hooked up
| | 03:58 | to the FlipsideViewController class files.
| | 04:02 | I'm going to jump across into the header
file for FlipsideViewController because
| | 04:05 | there's something slightly
different about this one.
| | 04:09 | Before the regular interface to
create this class, we have what's called a
| | 04:13 | protocol definition.
| | 04:15 | The FlipsideViewController can ask
someone to be a delegate for it, and what that
| | 04:20 | means is if you are going to be a
delegate for the flipside view, you need to
| | 04:24 | provide a method called
FlipsideViewControllerDidFinish.
| | 04:28 | It doesn't say here what that
method must do, but you need to have one.
| | 04:32 | The only other things we have here, on
line 19 there is a property that can
| | 04:36 | represent that delegate, and on
line 21, one IBAction called Done.
| | 04:42 | So, what does this mean?
| | 04:43 | Well, up to now, we've been
acting as a delegate for other objects.
| | 04:46 | We've been being given work to do, but
creating protocols like this is the way
| | 04:51 | that your own classes can describe
themselves as being delegating objects,
| | 04:56 | meaning they're in charge.
| | 04:57 | They can pass work off to someone else.
And what's happening here is that the
| | 05:02 | FlipsideView is going to pass
work off back to the main view.
| | 05:06 | What it actually means is when we
press the Done button I'm not going to take
| | 05:11 | care of dismissing this view away
inside the FlipsideView; I'm going to go and
| | 05:15 | tell the MainViewController to do it.
| | 05:17 | So in the implementation for
FlipsideView I'm going to use the Jump Bar and find
| | 05:22 | the Done action, and all it's going to
say is, hey, call whoever is the delegate
| | 05:27 | and let them know
FlipsideViewController is finished.
| | 05:30 | There's no code here to move the
ModalViewController away or to change the way
| | 05:35 | it looks or describe any kind of transition.
| | 05:37 | It's not doing it in the FlipsideView;
| | 05:40 | we're doing it back in the main view.
| | 05:42 | So, if I look here at
MainViewController, first I'm looking at the header file,
| | 05:46 | where we're volunteering to be
the delegate for the FlipsideView.
| | 05:49 | Yes, you can pass work back to us. And
then finally in the MainViewCcontroller
| | 05:54 | using the Jump Bar I should actually
expect just to implement that method, and
| | 05:59 | it's right here,
FlipsideViewControllerDidFinish, and this is the one line of
| | 06:03 | code that says, hey, we're
dismissing that ModalViewController back out.
| | 06:07 | Now, this is not the only way this
could be done, but it is a common way to do
| | 06:13 | it. And what we're really setting up
here is that the MainViewController is
| | 06:16 | in charge of both animating to the
FlipsideView and in charge of animating it
| | 06:21 | back away again, even when we can't see it.
| | 06:24 | So, the MainViewController is kind of
staying in charge, and we're staying in
| | 06:27 | control the whole time, and doing this
through delegation. And simply what we
| | 06:32 | could do is start to add our controls
and build on top of this, and this is
| | 06:36 | what's created for you with
the Utility Application in Xcode.
| | Collapse this transcript |
| Understanding navigation controllers| 00:00 | But sometimes one screen is not enough
and even two screens flipping between
| | 00:04 | each other aren't enough.
| | 00:05 | Now if you've used applications
like, say, the Settings application,
| | 00:09 | you'll have used navigation controllers.
| | 00:12 | Here, I'm not talking about the
contents of the screens themselves.
| | 00:15 | These could be table views,
like seen here, or images or video.
| | 00:19 | I'm talking about the blue bar at the
top, something that lets us keep track of
| | 00:23 | where we are and how to get back.
| | 00:27 | Settings uses it. Safari
uses it to manage Bookmarks.
| | 00:32 | Contacts uses it, the music applications
use it, and this is something called the
| | 00:38 | Navigation Controller.
| | 00:40 | It's a built-in object that can keep
track of where you are and automatically
| | 00:44 | provide you that single breadcrumb
level to get back to the previous view.
| | 00:48 | And when your app can now always fit
on one screen, you have multiple levels
| | 00:52 | going from a master level to a detail
level and even further down. This is the
| | 00:57 | classic iOS way of managing it.
| | 01:01 | To use this navigation controller, when
our application opens, we'll create the
| | 01:05 | empty window object as usual.
| | 01:07 | But instead of loading our first view
directly into the window, we will create
| | 01:12 | a navigation controller object, which has that
blue bar, and it can hold other view controllers.
| | 01:18 | We will load our First View into it, and
then we'll move the whole thing into the window.
| | 01:23 | And as you start to use the application,
say perhaps you touch a button in the
| | 01:27 | first view controller, instead of that
view controller directly creating and
| | 01:32 | transitioning to the next view
controller, as we saw in the utility app, it does
| | 01:37 | create it, but it tells the
navigation controller to handle the transition.
| | 01:41 | And the navigation controller takes
that second view controller and makes it
| | 01:45 | appear. The term we use, it's pushed
to the top of the navigation stack.
| | 01:50 | You can think of this like a deck of cards.
| | 01:52 | We are loading this in at the top of the deck.
| | 01:55 | Say we select something on
the second view controller.
| | 01:57 | We talk to the nav controller again,
we get the third one loaded on top.
| | 02:01 | Now the other view
controllers right now still exist;
| | 02:04 | they are just not visible.
| | 02:05 | And as the navigation controller has
been the one responsible for pushing these
| | 02:09 | onto the stack, it also knows
how to go back and push them off.
| | 02:13 | So as someone taps the Back button on
the navigation controller to go back, it
| | 02:17 | will take care of taking whatever's
the top of the stack and moving it away.
| | 02:21 | The term it's actually used is, that view
controller is being popped off the stack.
| | 02:26 | We click the Back button again, we get the
second one popped off and we are back at the start.
| | 02:31 | The job of the navigation controller
is to take care of the stack of view
| | 02:36 | controllers so we don't have to.
| | 02:38 | And to get started with this, Xcode
actually gives us a project type for master-
| | 02:42 | detail applications that
creates a simple example of this.
| | 02:45 | Then in the next section, we are going
to see how to go ahead and take a look at that.
| | Collapse this transcript |
| Creating a master-detail application| 00:00 | Let's see the Navigation
Controller being used in an example.
| | 00:03 | I'm going to create a
Master-Detail Application in iOS.
| | 00:08 | I will just call it MasterDetailExample.
| | 00:10 | I want to make sure at this point we're
still not using Storyboard, but we are
| | 00:13 | using Automatic Reference Counting.
| | 00:15 | Click Next and I will create it on my desktop.
| | 00:19 | I can immediately see over in the
Project Navigator that we have two sets
| | 00:24 | of View Controllers:
| | 00:25 | a MasterViewController.h, .m and .xib,
and a DetailViewController.h, .m, and .xib.
| | 00:31 | I am going to go ahead and run this, and
this is what it gives us right out of the box.
| | 00:37 | It looks like we have a table view here.
| | 00:38 | We have one row in it that says Detail.
| | 00:41 | I touch that. It jumps into a different view.
| | 00:44 | I can use the navigation bar
to navigate back up to the top.
| | 00:48 | It's simple, but all the principles
are here, and it's all based on this blue
| | 00:53 | bar at the top of the screen.
| | 00:54 | So let's go and take a
look at our interface files.
| | 00:57 | Quit out of that and go back in.
| | 00:59 | I am going to select the
MasterViewController.xib file.
| | 01:03 | I can see that I've got a table view
here, but I certainly don't see that
| | 01:07 | navigation bar at the top.
| | 01:09 | Even if I expand the dock, yeah,
I've just got a table view here.
| | 01:14 | There's nothing else on this .xib.
| | 01:16 | Jump to the
DetailViewController, maybe it's there.
| | 01:19 | Well, it doesn't look like it is. In fact,
looks like all I've got here is a label.
| | 01:24 | So there's the question, where is
that navigation controller, because it
| | 01:27 | obviously does exist in this
app, so where is it coming from?
| | 01:30 | Well, let's take a look at the
application startup code in our AppDelegate file.
| | 01:35 | Jump into AppDelegate.m, and what
we're interested of course is the classic
| | 01:40 | application
didFinishLaunchingWithOptions method.
| | 01:44 | Now, usually this code will say
create the window, create the first view
| | 01:48 | controller, and then load that
view controller into the window.
| | 01:51 | Well, what's happening is on line 20
we're creating the window, as usual. line 23
| | 01:56 | we create the MasterViewController as usual.
| | 02:00 | That's the first one we
want to show, which is fine.
| | 02:02 | But line 24 is new.
| | 02:04 | Here is where we allocate and
initialize a new instance of the
| | 02:08 | navigationController object, and we load
in masterViewController into it, in the
| | 02:14 | initWithRootViewController:
masterViewController.
| | 02:18 | So we have a combination of our
first view and that top bar of the
| | 02:22 | navigation controller.
| | 02:23 | Then we move the whole thing into the window
on line 25, and on line 26 we make it visible.
| | 02:29 | Again, it's not about the syntax here.
| | 02:31 | You shouldn't need to change this.
| | 02:33 | It's about the understanding the
process of what's happening here.
| | 02:36 | We're loading both things into the
window right at the start of the app.
| | 02:40 | So we can see that the
masterViewController is using this table view here,
| | 02:44 | although there is only one piece of data in it.
| | 02:46 | Let's take a look and see where
that data is actually coming from.
| | 02:50 | I'll quit out of that. And jumping
into the MasterViewController.m file, the
| | 02:54 | implementation, what I would expect to
see if I use the jump bar is to find some
| | 03:00 | of the table view data
source methods, so things like
| | 03:04 | numberOfSectionsInTableView,
numberOfRowsInSection, things that we talked about in
| | 03:09 | the table view part of the course.
| | 03:11 | I'll jump to
numberOfSectionsInTableView, and we have return 1, and then
| | 03:16 | numberOfRowsInSection.
| | 03:17 | Well, that apparently always returns 1 as well.
| | 03:20 | And then below it we have the
classic cellForRowAtIndexPath, creating the
| | 03:26 | individual rows for that table view.
| | 03:28 | The code here is just the standard code
you'd always expect to see in here about
| | 03:32 | creating a cell and dequeuing
it if there's one available.
| | 03:35 | In fact, the only thing we're doing
with the cell is on line 96 we're just
| | 03:40 | setting the text of the cell to say Detail.
| | 03:43 | Now, here we're actually using the
NSLocalizedString instead of an NSString.
| | 03:48 | This is just the boilerplate
code that Apple has created for us.
| | 03:52 | Localized strings are great.
| | 03:54 | They support having a separate
strings file in our app that can look up a
| | 03:58 | replacement word or phrase if we have that
provided for another language. They're great.
| | 04:03 | They're not that complex, but they're just
a little beyond the scope of this course.
| | 04:06 | You can leave this as is, but understand
that there is nothing magical going on here.
| | 04:11 | I could have just used a
regular NSString object.
| | 04:14 | That would have been fine too.
| | 04:15 | So this table view is being
loaded with very basic literal data.
| | 04:19 | You could use some of the techniques
from the table view section of this course
| | 04:22 | to load in something different.
| | 04:24 | The only thing I'm going to change here
is in numberOfRowsInSection, where I'm
| | 04:28 | going to say return 5, so that we can
at least get five rows of data, even if
| | 04:34 | they all say the same thing.
| | 04:39 | But then the question is, what actually
happens when we're tapping a row in the
| | 04:44 | table view that will take us to the detail view?
| | 04:47 | The navigation controller won't
automatically do it just because we've tapped a
| | 04:51 | row in the table view, so there
must be something else going on in this
| | 04:54 | boilerplate code, and of course there is.
| | 04:57 | Quit out of that and back into the code.
| | 04:59 | What's happening is that the provided
code here is implementing another delegate
| | 05:04 | method, and it's tableView:
didSelectRowAtIndexPath.
| | 05:09 | I'll just open up my navigator
so we can see all this properly.
| | 05:12 | There is really not very much going on here.
| | 05:15 | Line 140 asks, do I currently have a
reference to a detailViewController object?
| | 05:22 | You might think, well, where did that come from?
| | 05:25 | If I look at the MasterViewController
header file, it simply has given me one
| | 05:29 | property that can hold a
reference to a detailViewController.
| | 05:35 | So back in my implementation, all I'm asking
here is, is there an object in that property?
| | 05:40 | If there isn't, create one and
initialize it with the existing NIB, the XIB
| | 05:46 | file in our project.
| | 05:48 | Then on line 143, talk to the
navigationController and tell it to push that new
| | 05:54 | detailViewController that we
have onto the stack, animated: YES.
| | 05:59 | That makes it slide on, whereas an animated:
NO would just make it up here.
| | 06:03 | And that's all the code we need to
make it transition from the master view,
| | 06:08 | whenever we touch one of
these rows, to the detail view.
| | 06:12 | But one problem we have is that no
matter what row we're touching, it's always
| | 06:16 | doing exactly the same thing, taking
us to the same detail view that never
| | 06:20 | looks any different.
| | 06:21 | The whole point of going from a master
view to a detail view is not just to have
| | 06:25 | the screen transition, but that you're
going to pass some information between
| | 06:28 | these view controllers. So let's do that.
| | 06:30 | I am going to quit out of
this and back into the code.
| | 06:34 | Now, if I look at the header for my
DetailViewController--and this is the
| | 06:38 | Apple-provided code here--
I have two properties.
| | 06:41 | One of them is an IBOutlet that I can
see is connected, and it just represents
| | 06:45 | the label that is actually in that
.xib file, that at the moment always says
| | 06:50 | Detail view content goes here.
| | 06:53 | But we do have one more
property here on line 13.
| | 06:56 | This is a property for something called
detailItem of type id. Now, type id just
| | 07:01 | means this could be any object.
| | 07:03 | It's a placeholder.
| | 07:04 | In your app, if you knew you wanted to
pass in a product object or a song object
| | 07:09 | or a player object, you'd be specific here.
| | 07:12 | But this could accept anything.
| | 07:14 | Now, jumping to the
implementation file for DetailViewController,
| | 07:18 | I can see that I have a couple of
synthesize statements to synthesize both the
| | 07:21 | DescriptionLabel and detailItem.
| | 07:23 | Now, if you haven't seen this format
here, it just means it's synthesizing the
| | 07:28 | instance variable names with an underscore.
| | 07:31 | It's not important here.
| | 07:32 | However, the part that is a bit
more important starts on line 22.
| | 07:36 | They've provided a custom setDetailItem
method, so if someone wants to set this property.
| | 07:43 | Now, it's still pretty basic.
| | 07:44 | It accepts a generic object of type
id. You can pass in anything into this:
| | 07:48 | an array, a string, a
custom object, whatever you want.
| | 07:52 | On line 24, it's just going to ask,
did you pass me a new object or are you
| | 07:56 | trying to pass me the same object I am already?
| | 07:58 | If it's a new object, all it's
going to do is call self configureView,
| | 08:03 | the configureView method that's down
here on line 32, and all that does is ask,
| | 08:07 | is there some object in this property?
| | 08:10 | If self.detailItem, if it exists, then
I'm going to change the text on this view
| | 08:17 | to whatever the description
method for that new object returns.
| | 08:21 | You might ask, well, how do you know
the object will have a description method?
| | 08:24 | Because all of them do.
| | 08:25 | Description is a method defined on
NSObject, so everything you could possibly
| | 08:30 | pass into this will have a description
method, even if all it will say is the
| | 08:34 | name of the class and the address in memory.
| | 08:36 | And the reason they've done it this
way is just to be as generic as possible.
| | 08:41 | You don't have to have a label.
| | 08:42 | You don't have to accept something of
type id. It's just to allow you to pass
| | 08:46 | anything into this detailViewController and
have it update the label with some information.
| | 08:51 | So how do we do it?
| | 08:52 | How do we pass information between view
controllers from our master to our detail?
| | 08:58 | Well, I know that usually what I'd
want to do is pass different information.
| | 09:03 | I want to be able to pass information
that's different if we click the first row
| | 09:07 | to the second or the third.
| | 09:09 | So the place I need to be to pass
that information will be back in our
| | 09:13 | didSelectRowAtIndexPath.
| | 09:15 | So I jump into the implementation of
the MasterViewController, and I have it
| | 09:20 | selected, or I could use the
jump bar to jump right here.
| | 09:23 | And what we've seen already is
this is where we just ask, does the
| | 09:27 | detailViewController object exist?
And then push it on top of the stack.
| | 09:32 | So between asking if it exists and
pushing it to the stack, I'm going to create
| | 09:36 | a new object, and I'll just make an
NSString, which is perfectly fine.
| | 09:40 | It's a first-class object all in its
own right, but you could be creating
| | 09:45 | anything and passing it in here.
| | 09:49 | And rather than create one string
that always looks the same, I'll do an
| | 09:52 | initWithFormat so I can slightly
change it based on the different row
| | 09:56 | that's just been touched.
| | 10:00 | Give it a placeholder, You chose
row %i, because I know that I can have
| | 10:06 | an integer for that selected
row, and grab that integer from the
| | 10:10 | parameter indexPath row.
| | 10:13 | I can either use indexPath row in square
brackets or indexPath.row in dot syntax.
| | 10:20 | Close that method call.
| | 10:21 | Finish that statement.
| | 10:23 | We now have an object, but I need to
hand it to the detailViewController.
| | 10:29 | I know that I have a reference to a
detailViewController, because on line 140 I
| | 10:32 | asked if it existed, and if it didn't, make it.
| | 10:35 | So I know I have something called
self.detailViewController, and that should have
| | 10:41 | a method called setDetailItem--
| | 10:43 | there we go--which takes type
id, meaning pass me anything.
| | 10:47 | I will pass the string. Save it, run it.
| | 10:55 | We're in the master view controller.
| | 10:57 | We click, say, the first one, and what
we're doing is passing in the correct row,
| | 11:03 | which is 0; it's 0 based here.
| | 11:05 | So You chose row 0, or You chose row 1.
| | 11:10 | Selecting the fifth should say
You chose row 4, and indeed it does.
| | 11:14 | So while it's not tremendously
dramatic, we are now passing different objects
| | 11:20 | from the master view into the detail
view automatically using the navigation bar
| | 11:24 | to navigate back up.
| | 11:26 | And this is how to get started with
the master-detail app and the navigation
| | 11:29 | controller, and you can use the same
principles here to start adding more view
| | 11:34 | controllers to this project and
even transitioning further down.
| | Collapse this transcript |
| Creating a tabbed application| 00:00 | Let's take a look at the Tabbed
Application, which is another project template
| | 00:04 | that has multiple views in it,
| | 00:08 | once again making sure I'm using ARC,
but not using Storyboards right now, and
| | 00:13 | click Next and Create.
| | 00:15 | Looking in the Project Navigator, I
can immediately see that I've been given
| | 00:19 | two view controllers:
FirstViewController and SecondViewController, both the
| | 00:24 | .h, .m and .xib for those.
| | 00:27 | I am going to go ahead and run this.
| | 00:34 | And what I see is this First View option.
| | 00:37 | I have this tab bar down at the bottom.
| | 00:39 | It's divided in to two
sections that I can switch between.
| | 00:42 | The tab bar can have multiple sections.
| | 00:44 | It's not recommended on an
iPhone that you go beyond five.
| | 00:47 | And what this is doing is similar in
concept to the navigation controller, in
| | 00:52 | that it's the tab bar itself that's
controlling this switch between the
| | 00:56 | different view controllers that we have.
| | 00:59 | Well, let's take a look at that in our project.
| | 01:01 | I'm going to quit out of this and go
into FirstViewController, which should look
| | 01:06 | reasonably recognizable here.
| | 01:09 | Now, it looks like this might be
representing the tab bar down at the bottom of
| | 01:13 | it, but it's really not.
| | 01:15 | I am just selecting the view right now,
and if I take a look at my inspectors
| | 01:19 | here, my Attributes Inspector, shows me that
I have got a simulated tab bar at the bottom.
| | 01:24 | That doesn't actually do
anything programmatically.
| | 01:26 | It just lets me set up the
rest of my interface correctly.
| | 01:29 | If I click on SecondViewController,
this one is doing exactly the same thing.
| | 01:33 | Bottom bar is tab bar.
| | 01:35 | But neither of them contain anything
other than a label and a text view.
| | 01:42 | These .xib files do not contain a tab
bar controller, because what's happening,
| | 01:48 | again, is all in the AppDelegate.
| | 01:51 | Expanding this. Again, don't worry
about the syntax, just pay attention to the
| | 01:55 | concept of what's going on.
| | 01:57 | As usual, on line 22, we are
creating the window object.
| | 02:01 | Line 24, we instantiate the FirstViewController.
| | 02:04 | Line 25, we also
instantiate the SecondViewController.
| | 02:08 | On line 26, we are creating a new
instance of a tabBarController object.
| | 02:14 | That doesn't have to have an associated
class file or .xib, because we're using
| | 02:19 | the standard tabBarController
object that's built into iOS development.
| | 02:23 | And then on line 27 what we do is we
load the tabBarController up with our
| | 02:29 | custom viewControllers, number 1 and number 2.
| | 02:32 | And then on line 28, we take the
whole collection, the tabBarController and
| | 02:36 | those two viewControllers,
and load it into the window.
| | 02:39 | That's why we are not seeing
it on the interface itself. It's all done in code.
| | 02:43 | So let's see how we would add a
third section to this application.
| | 02:48 | What I need to do is create another
view controller, the whole set of .xib, .h,
| | 02:54 | and .m. Very easy to do.
| | 02:56 | I am going to go up to the File menu,
come down to the New option. Instead of
| | 03:00 | New Project, we say New File.
| | 03:02 | I'm interested in the iOS section,
and I can filter down into Cocoa Touch.
| | 03:07 | The one I'm interested in is in
the Cocoa Touch section and it's the
| | 03:11 | UIViewController subclass.
| | 03:14 | Notice the description of it.
| | 03:15 | It's an Objective-C class which is a
subclass of UIViewController, with a header
| | 03:19 | file and an optional XIB interface file.
| | 03:23 | You don't always have to do it together, but
this way is a pretty classic way of doing it.
| | 03:28 | I click Next.
It's going to ask us to give the class a name.
| | 03:31 | Well, we have
FirstViewController and SecondViewController.
| | 03:34 | Let's not break tradition.
| | 03:36 | Let's have ThirdViewController.
| | 03:38 | We do want this to be a subclass of the
built-in UIViewController, so I get all
| | 03:42 | the normal behaviors.
| | 03:44 | And then I am going to make sure that I
click the check box With XIB for user interface.
| | 03:50 | Click Next. It's asking, do I want to add it to the
current project, and yes, I do, and Create.
| | 03:58 | I have my .h, my .m, and my .xib.
| | 04:01 | So I am just going to add
something simple to the XIB here.
| | 04:07 | Drag on a label, widen it out
a bit, and call it Third View.
| | 04:13 | I will center-align this and
just increase the Font a little bit.
| | 04:19 | If I wanted to, I could also do the
same thing as the other two XIB files are
| | 04:24 | doing, which is by selecting the
background view and then simulating the bottom
| | 04:28 | bar of the tab bar, but
again, that's not necessary.
| | 04:31 | It would just stop me putting on
some controls in the wrong positions.
| | 04:35 | I am not going to touch the class
files for this view controller yet.
| | 04:38 | I am just going to go back over into my
AppDelegate and add the necessary code here.
| | 04:44 | I am just going to expand
this so I have a bit more room.
| | 04:47 | And here is the benefit of
the way they have created it.
| | 04:50 | I can really just copy some of this code.
| | 04:53 | I have a pretty good idea of what to do.
I am going to create a new UIViewController.
| | 04:56 | I will call it viewController3.
| | 04:58 | I need to make sure that I am using the
ThirdViewController class name to create it.
| | 05:04 | I can see that it's giving me a
problem here. It doesn't know what that class
| | 05:06 | is, because although I created the class files,
I haven't imported the header file up here.
| | 05:12 | So right after line 13, I am going to
do another #import, tab across, and that
| | 05:18 | needs to be in quotes and not in angle
brackets. And this will be, there we go,
| | 05:22 | ThirdViewController.h. So
now it knows that class exists.
| | 05:26 | So on this line I can instantiate it
with ThirdViewController alloc and make
| | 05:31 | sure to init with the correct Nib,
I don't want to mismatch those.
| | 05:36 | So now we have viewController3 being created.
| | 05:41 | Well, it's not going to make any
difference if I don't then load that new
| | 05:45 | viewController into the tabBarController.
| | 05:48 | Notice here is where I am
creating it with the first two, using an
| | 05:52 | arrayWithObjects called
viewController1, viewController2, nil--
| | 05:57 | nil indicating the end of the array.
| | 06:00 | So after the first comma, I am just
going to say viewController3, and add
| | 06:04 | another comma so that there is a
comma before the nil. Save it, run it.
| | 06:13 | We have a section on the tab bar for First,
section for Second. And we do have a third section.
| | 06:18 | There is nothing actually going on
here yet, but it does actually allow me to
| | 06:21 | switch to that ThirdViewController.
| | 06:24 | So it seems to be working just fine.
| | 06:27 | The missing link being, well, how can we
have a title, how can we have an icon?
| | 06:31 | Well, let's look and see what's happening there.
| | 06:33 | Quit out of this and bank into the code.
| | 06:37 | Notice that when these view
controllers are being instantiated,
| | 06:40 | viewController1, it's using
initWithNibName, a pretty classic way to do it.
| | 06:45 | Same with viewController2, initWithNibName, and
| | 06:48 | viewController3, initWithNibName.
| | 06:50 | I could go into the
implementation for the FirstViewController,
| | 06:54 | so FirstViewController.m and
here is the initWithNibName.
| | 06:58 | It's got some standard text in here,
making sure that it exists, but what it's
| | 07:02 | doing are these two lines.
| | 07:03 | Line 17, setting the title to
First and, again, it's using the
| | 07:08 | NSLocalizedString, though this could be
just a regular NSString that's said First.
| | 07:13 | And then Line 18, self.tabBarItem.image
and extracting an image from this call
| | 07:19 | to UIImage, imageNamed first.
| | 07:22 | Now, if you might have noticed, over
here we have a couple of placeholder images
| | 07:25 | here: a first.png and first@2x.png--
| | 07:31 | essentially one of them for a regular iPhone,
| | 07:33 | the other one for a Retina display.
| | 07:36 | second.png is a square and @2x
for a square for the retina display.
| | 07:42 | So we could use this model, and we
could essentially just copy and paste this
| | 07:46 | code for our third one and also set an image.
| | 07:49 | I haven't actually created an image
for that position, but I could copy this
| | 07:53 | code, jump into my implementation in
ThirdViewController, and I have got my own
| | 07:59 | initWithNibName method here with a
place for my custom initialization.
| | 08:04 | Now, I could just set this to a
localized string saying Third, Third.
| | 08:09 | Again, I am not using
localized strings in this example.
| | 08:12 | So I am loading it in there, setting
the title, and I am just going to borrow
| | 08:17 | the first named image.
| | 08:18 | Let's run that and check that it
works. And it seems to work just fine.
| | 08:25 | The dark images that are
provided are automatically going to be
| | 08:29 | correctly color coded by iOS.
| | 08:31 | You don't have to worry about that.
| | 08:33 | However, there's another option we
could use if I didn't just want to
| | 08:35 | reuse that simple circle.
| | 08:37 | Instead of creating my own title using
my own images, what I'd like to do is
| | 08:43 | reuse one of the built-in system-provided
tab bar items, and here's how you do it.
| | 08:49 | This view controller, self, is going to
have a property called tabBarItem, and I
| | 08:53 | am going to create a new instance of
tabBarItem. So I'll just do UITabBarItem
| | 09:01 | alloc. And there is an
initializer called initWithTabBarSystemItem.
| | 09:08 | That's the one that I want.
| | 09:09 | This allows me to select from an
enumeration that has a bunch of pre-provided
| | 09:14 | tab bars that are the standard ones
used in things like videos and the music
| | 09:18 | application and all sorts of other applications.
| | 09:20 | So I will start typing in
UITabBarSytemItemMore, History, Featured, Favorites,
| | 09:26 | MostRecent, MostViewed, TopRated,
and several more above that.
| | 09:31 | Let's select, for example, Contacts.
| | 09:34 | Then I will hit Tab, and it's
telling me that we also need a tag
| | 09:37 | parameter that's an integer.
| | 09:39 | Tag here doesn't actually matter.
| | 09:41 | It doesn't matter what the number
is. This is a way of associating your
| | 09:44 | different tab bar items with a number.
| | 09:47 | And that's because in more complex
situations, like the iPhone music app, you
| | 09:51 | can reconfigure the tab bar to contain
your choice of buttons and your choice of
| | 09:55 | order, and it means you can associate
each button with a particular number.
| | 09:59 | We don't really care about this here.
| | 10:01 | I could put in any number that I wanted.
| | 10:03 | I just need to provide something.
| | 10:05 | I am going to close that method, finish the
statement with a semicolon, save it, run it.
| | 10:13 | And now we are using the pre-provided
and built-in tab bar item or one of the
| | 10:18 | many, and you can see all the available
options for tab bar items in the Human
| | 10:23 | Interface Guidelines document.
| | 10:25 | This is how we get started
with a tabbed application.
| | Collapse this transcript |
|
|
9. Using StoryboardsIntroduction to storyboards| 00:00 | When iOS 5 and Xcode 4.2 released
in late 2011, we got storyboards.
| | 00:05 | These are a great way of visually laying
out an application with multiple views.
| | 00:10 | Now, we have seen techniques up to
now where we could create individual NIB
| | 00:14 | files to represent each separate
screen in an app and then create code to
| | 00:18 | transition between them.
| | 00:19 | But now we can have one storyboard
that describes all the screens in our app,
| | 00:25 | whether that's 1, 2, or 100, and the
relationships and transitions between those screens.
| | 00:30 | Unlike the idea of a storyboard in
filmmaking, a storyboard here is not a mockup.
| | 00:35 | It's not just a visual aid.
| | 00:37 | It is the real user
interface of your application.
| | 00:40 | A change to the
storyboard is a change to the app.
| | 00:44 | And it's not just a convenient way for
you to see several screens at the same
| | 00:47 | time; storyboards help manage
transitioning between screens, and they help with
| | 00:52 | passing data between them.
| | 00:54 | They help you build the flow of your app.
| | 00:57 | Unlike things like ARC,
storyboards will let you write less code.
| | 01:01 | Typically, it's one storyboard per app.
| | 01:04 | You can create storyboards for just part
of an application, but the general rule
| | 01:09 | is, you only need one.
| | 01:11 | If you make a storyboard, you
don't then need separate NIB files.
| | 01:16 | The storyboard is your UI, and
working with a storyboard is very similar to
| | 01:21 | working with individual NIB files, as we'll see.
| | 01:23 | Now, if you are creating a universal
app that can alter its appearance based
| | 01:27 | on the device, you can have one storyboard for
the iPhone part and another for the iPad version.
| | 01:33 | In fact, that's what Xcode gives you when you
make a universal project that uses storyboards.
| | 01:38 | The two main ideas in a
storyboard are scenes and segues.
| | 01:42 | You begin with one scene and you create a
new scene for each screen in your application.
| | 01:48 | And a scene, if it looks familiar, is of
course of good old view controller, but
| | 01:52 | instead of one per NIB, we are just
managing them all together in one place.
| | 01:57 | On an iPhone, a scene does typically
represent a full screen, though on an iPad
| | 02:02 | it could represent part of a screen.
| | 02:04 | So if you are working with a master
detail view, you might have multiple
| | 02:07 | scenes visible at the same time on
the iPad, because they can transition
| | 02:11 | separately from each other.
| | 02:13 | But not every scene in your app needs
to go to every other scene in your app,
| | 02:17 | so you then describe segues
between the relevant scenes.
| | 02:21 | And segues describe the visual
transitions between your view controllers.
| | 02:25 | There are built-in segues like
a Modal segue and a Push segue.
| | 02:29 | You can even define your own custom
segues, but we won't get into that here.
| | 02:33 | A segue is typically triggered by
something the user does on screen, like
| | 02:37 | touching a button or a table cell,
although you could make these segues happen
| | 02:42 | programmatically in response to
perhaps a gesture or accelerometer movement.
| | 02:46 | And the great thing about designing
everything in a storyboard is Xcode helps
| | 02:51 | you wire these all up, and it handles
loading the different pieces in and out of
| | 02:57 | the storyboard efficiently.
| | 02:59 | And of course, you often need to do
something programmatically as you're about
| | 03:03 | to segue between these scenes,
| | 03:05 | so there is an important new method in
UIViewController when using segues. It's
| | 03:10 | called prepareForSegue:sender.
| | 03:13 | You would override this method in the
view Controller you are about to leave and
| | 03:18 | it will be called automatically
when the segue is about to happen.
| | 03:21 | And here you can prepare some data
to pass into the next scene, into the
| | 03:25 | next view controller
| | 03:26 | that you're about to segue to.
| | 03:27 | So that's the basic concepts.
| | 03:29 | Let's see how to do it.
| | Collapse this transcript |
| Creating scenes and segues| 00:00 | I am going to create a new Xcode project.
| | 00:02 | This will be a Single View Application
this time, but we will use the storyboard
| | 00:07 | check box to use those.
| | 00:09 | I am going to just call this StoryboardExample.
| | 00:12 | Make sure it's for iPhone because iPad
storyboards can become enormous, and with
| | 00:18 | Storyboard and ARC checked, I am
just going to go ahead and create it.
| | 00:22 | I can see in the Project
Navigator that I have class files for a
| | 00:26 | ViewController: my .h and .m. But
instead of having a .xib, I have one
| | 00:31 | storyboard file here, MainStoryboard.
| | 00:34 | Selecting that, it jumps us to this
Canvas view, which doesn't look all that
| | 00:38 | different from the NIB
editor we've been used to so far.
| | 00:42 | And indeed, it really isn't.
| | 00:44 | At this point, we could select
objects in our Object Library.
| | 00:48 | We could drag and drop them onto here.
| | 00:50 | It'd behave very similar to what we're used to.
| | 00:52 | So we begin with this one scene.
| | 00:54 | This is the scene that will
automatically load when this app begins.
| | 00:59 | That's what this arrow
represents is the starting point.
| | 01:02 | There are a couple of differences.
| | 01:04 | When I click this to select it, I
will see that instead of having icons on
| | 01:08 | the left-hand area,
| | 01:09 | I have them down at the bottom in this doc area.
| | 01:12 | It shows us objects like the First
Responder, which we rarely need to touch, and
| | 01:17 | View Controller, which is more
useful, because like File's Owner,
| | 01:22 | we need to be able to describe how
this interface is connected to some
| | 01:26 | class files. And with that selected--and I
can see the blue bar surrounding everything--
| | 01:31 | I can go into my Identity Inspector,
which is the third button here, and see
| | 01:37 | that it is hooked up to a custom class
called ViewController. And that's how we
| | 01:41 | connect this to the actual code files.
| | 01:43 | You also do have the collapsible Doc
area, which contains that other way of
| | 01:48 | viewing the elements in your scenes.
| | 01:51 | But you can collapse it all the way
because the basic icons will always be
| | 01:54 | visible on the storyboard.
| | 01:56 | So, how to add new scenes?
| | 01:58 | Well, scenes are view controllers.
| | 02:00 | We add them by finding view controllers
in our Object Library and just dragging
| | 02:04 | them onto the canvas.
| | 02:05 | I am going to filter my Object Library
to Controllers & Objects here, and I'll
| | 02:10 | see I have a view controllers, table
view controllers, navigation controllers,
| | 02:14 | page view controllers.
| | 02:15 | I am going to just add a
couple of regular view controllers.
| | 02:19 | I have zoomed out one level, just
so I can see things a little better.
| | 02:23 | Now, I do find that interacting with
objects on a storyboard is only really
| | 02:27 | reliable when you're zoomed in at the
100% level, but zooming out can give you
| | 02:32 | a good perspective.
| | 02:34 | So I am going to zoom in there and just
rearrange these a bit more, and you will
| | 02:38 | see that even the storyboard itself has
helper guides for aligning our scenes.
| | 02:44 | You don't have to add them in a left-to-right
fashion, though that is useful and traditional.
| | 02:48 | You can put them beneath.
You can put them on the left.
| | 02:51 | You can put them on the right.
It really doesn't matter.
| | 02:53 | Now, I'd like to be able to see the
difference between these scenes without
| | 02:57 | having to add too much in
the way of user interfaces,
| | 03:00 | so I am going to select the second one
and just go into my Attributes Inspector.
| | 03:05 | In fact, I am going to zoom in one
more piece because I do want to be able to
| | 03:09 | interact with them better.
I want to get the actual view selected.
| | 03:15 | So I can then select Default.
| | 03:17 | I'll give that one a Group Table View
Background Color, just to distinguish them,
| | 03:22 | and then select the third one.
| | 03:24 | Again, you may have to be zoomed in
all the way to be able to grab this
| | 03:27 | properly, and selecting from background,
I will give it the Scroll View Textured
| | 03:32 | Background Color, just so
they're obvious which screen we're on.
| | 03:36 | So I have these two new scenes.
| | 03:39 | Now these scenes are considered view
controllers, but Xcode has not generated
| | 03:46 | custom view controller class files for
anything other than the first one, and we
| | 03:50 | will often need those files, although
we can add them later and then hook them
| | 03:55 | up to these visual view controller elements.
| | 03:58 | But first, what I want to do is just
add some basic segues, so how to do this.
| | 04:03 | A segue needs to be triggered by
something, so we might as well have, say, a
| | 04:07 | button to do this. I am going to
filter on my controls, grab a Round Rect
| | 04:12 | Button, drop it onto the first one.
| | 04:14 | I can see here it's not actually
allowing me to drop it on when I'm zoomed out,
| | 04:18 | so I am going to zoom into 100% or just
click the Equals sign, see whether that works.
| | 04:23 | Nope! Not doing it.
| | 04:25 | Let's zoom all the way in,
drag on the Round Rect Button--
| | 04:30 | that will do--and then drag
it onto the second one as well.
| | 04:33 | It doesn't really matter where you put them.
| | 04:35 | I will put them towards the lower-right.
| | 04:40 | I will just double-click
them to give them some text.
| | 04:45 | So how do I make these triggers segue?
| | 04:47 | Well, we don't even have to do an
IBAction or write any code, none of that.
| | 04:51 | I'm simply going to go to the first
button, hold the Ctrl key, click, drag onto
| | 04:57 | the second view controller, let go,
and it's going to do this pop-up, oh!
| | 05:01 | You want to do a segue, what kind?
| | 05:03 | Push or a Modal--there's actually
several kinds of modal--or Custom?
| | 05:07 | I am going to choose Push, click, and
we have the segue icon. And the icon
| | 05:12 | here is actually a clue that this
is a Push transition because a Push
| | 05:16 | transition is the classic right-to-left,
shifting one view controller from the
| | 05:21 | right over the top of the other.
| | 05:23 | I'm going to do the same with the next one.
| | 05:25 | Ctrl+Click, drag, Push segue.
| | 05:29 | I am going to just go ahead and run this,
and let's see if it made any change.
| | 05:34 | I click the Next button and nothing.
| | 05:37 | Now, here is the problem.
| | 05:39 | Not all segues make sense in all circumstances.
| | 05:43 | This Push transition, the classic
right-to-left move, is associated with a
| | 05:49 | navigation controller in iOS so that we
can keep track of which screen we're on,
| | 05:54 | and iOS still wants to do the segues
that way. And that would control the Push
| | 05:59 | and the navigation back so we would
typically expect to see one here. Can we do that?
| | 06:04 | Of course we can, and it's
very, very easy. Here's how.
| | 06:07 | We just select the first view controller.
| | 06:09 | Now, if you remember when we created
navigation controllers, the idea is we
| | 06:14 | create the navigatio controller,
and then we load in our first view
| | 06:18 | controller into it.
| | 06:19 | We can do that here.
| | 06:20 | I select it, I go up to the Editor menu,
and then I have an option that says
| | 06:25 | Embed in, and it allows me to embed this
first view into a navigation controller.
| | 06:31 | I am just going to rearrange that a
little bit. And notice what it's doing now.
| | 06:36 | It's smart enough to understand that
actually our first controller that we load
| | 06:41 | in is a navigation controller that
itself is instantly going to load in this
| | 06:46 | first view controller, the
one that we're interested in.
| | 06:50 | Now, it's shifted the UI a little bit,
| | 06:52 | so we may need to rearrange that.
| | 06:54 | But I am going to go ahead and
run it and see how that works.
| | 07:03 | I can see the navigation
controller at the top. I click Next.
| | 07:06 | We do a Push segue to the
second screen. I click Next.
| | 07:09 | We do a Push segue to the third screen.
Navigation controller takes charge of
| | 07:13 | moving them back and forth. Very easy to do!
| | 07:18 | Not a line of code.
| | 07:19 | Now, we're typically going to write a
little bit of code so we can have things
| | 07:23 | like more interesting title bars
and so on, but this is the basics.
| | 07:29 | Next, we're going to take it a bit
further and start make something a bit more
| | 07:32 | interesting, and even passing
data between our different scenes.
| | Collapse this transcript |
| Passing data between scenes| 00:00 | Let's see how to pass information
from one storyboard scene to another.
| | 00:03 | I'm going to create this
simple photo viewer application.
| | 00:08 | It allows us to select from a list
of photographs, go to a new scene that
| | 00:12 | will actually show the image itself,
go to another scene that will show
| | 00:15 | information about that image.
| | 00:17 | And while it is simple, it's
still using multiple scenes.
| | 00:20 | It's using navigation controllers,
it's using Push segues and Modal segues,
| | 00:26 | table views and image views, and it's
passing an object from one scene to the
| | 00:31 | next. I have a custom object called
photo object, which can be passed around and
| | 00:35 | show different information about
that same object from scene to scene.
| | 00:39 | I'm going to do this in five short steps.
| | 00:42 | Here is the overview.
| | 00:43 | Step one, we'll create the storyboard.
| | 00:46 | We'll layout the application, the
scenes and the segues in the different user
| | 00:50 | interface elements.
In this step we write no code.
| | 00:53 | Step two, we're going to
create the custom class.
| | 00:56 | This will be a photo class so we can create
multiple objects of this and pass them around.
| | 01:01 | This is very simple, really just
a straightforward data structure.
| | 01:05 | Step three, when we set out multiple
scenes in a storyboard they don't actually
| | 01:10 | have their own class files attached to them.
| | 01:14 | So we're going to create custom view
controller classes for each scene and then
| | 01:18 | in the storyboard, hook them up so each
scene can have its own class file with
| | 01:24 | its custom behavior.
| | 01:25 | Step four, we'll write code to load in
the data, loading in multiple rows into
| | 01:30 | the table view and then writing code
to show an image or writing code to show
| | 01:33 | information about an image.
And this will be possible by step five.
| | 01:37 | We're going to be passing the object
between the scenes so the code we write to
| | 01:41 | load the data will actually work.
| | 01:43 | We're going to hand off a photo object
from the Table View to the scene that can
| | 01:48 | show it, and then onto the scenic
that can show information about it.
| | 01:51 | That's the general approach.
| | 01:53 | Let's get started.
| | Collapse this transcript |
| Step one: creating the storyboard| 00:00 | So I'll create a new iOS Single View Application.
| | 00:04 | I'm going to call this one
PhotoViewer and make sure that it's an iPhone
| | 00:08 | application and that we're using
both storyboards and Automatic Reference
| | 00:12 | Counting. And I'll just save this to my desktop.
| | 00:14 | Now, if I want this to show some
photos, it will be useful to have some
| | 00:17 | photos in this app.
| | 00:19 | Well, I do have a folder that I
currently have on my desktop, but you can get it
| | 00:22 | from the exercise files, that
contains just a few photos in it.
| | 00:26 | I'm going to drag this into Xcode.
| | 00:28 | I'm going to put it in my
Supporting Files folder.
| | 00:31 | And when the pop-up appears, I want
to make sure that the check box to copy
| | 00:36 | these items is selected.
| | 00:38 | Now, it doesn't matter that you put
them in Supporting Files, although I find
| | 00:41 | that's the most useful place for them.
| | 00:43 | They're just simple, preformatted images,
the right size for an iPhone screen.
| | 00:48 | So I'm going to jump to my MainStoryboard.
| | 00:50 | Now, currently here what
we have is the basic setup.
| | 00:54 | We have the view controller area with
its corresponding .h and .m files in
| | 00:59 | the Project Navigator.
| | 01:01 | I actually don't want to start here, so
what I'm going to do is get rid of it.
| | 01:05 | I'm going to just highlight and delete
the whole thing, go back to a blank canvas.
| | 01:10 | Not only that, but over here in my
Project Navigator I'm going to delete the
| | 01:14 | header file, make sure to completely
delete it, and the implementation file, so
| | 01:22 | I really am starting from ground zero here.
| | 01:25 | The reason that I did this is I
actually want to start this off with a table
| | 01:29 | view controller, not a regular view controller.
| | 01:31 | And with my Object Library open, I'm
going to find a table view controller, not
| | 01:36 | a table view, but make sure you've
got the controller one, and drag it on.
| | 01:41 | Because we dragged it onto a blank
storyboard, we do have this little arrow here
| | 01:46 | that represents being the
initial view controller.
| | 01:49 | And if I look to the Attributes
Inspector, I would also see that checked,
| | 01:52 | that the Initial Scene, this
is the initial view controller.
| | 01:57 | Then I'm going to drag on
a regular view controller.
| | 02:00 | This is the one that's
going to display our photo.
| | 02:03 | And then a third, and this is going to
show the information about our photo.
| | 02:08 | Now, I know that my first table view
controller is also going to be embedded in
| | 02:13 | a navigation controller, so that we can
do a Push segue between it and the one
| | 02:18 | that displays the image.
| | 02:20 | So what I'm going to do is select the
Table View Controller, go up to my editor,
| | 02:24 | and tell it to embed in a navigation controller.
| | 02:28 | Now, I'm going to add a couple of segues.
| | 02:31 | I'm going to zoom into full size here.
| | 02:35 | I know that what I want to have
happen is when someone taps a cell in the
| | 02:40 | Table View Controller, we're going to
move to the second view controller that
| | 02:43 | will display that photo.
| | 02:45 | Here's how we do that segue in the storyboard.
| | 02:47 | I simply hold down the Ctrl key, tap
the blank cell, and drag over to that
| | 02:52 | second view controller. Let go.
| | 02:55 | It will ask what kind of segue is this.
| | 02:57 | I'll say it's a Push segue, and it knows
now, because the first one was embedded
| | 03:01 | in the Navigation Controller and
we're pushing to the second, that it's also
| | 03:05 | going to embed that in the
Navigation Controller too.
| | 03:07 | Now, I do want this second View
Controller to move to the third, but I don't
| | 03:12 | want to have it a Push segue.
| | 03:13 | I want a Modal segue here, and
something needs to trigger a Modal segue.
| | 03:17 | So I'm going to open up my Utilities
panel, filter down to Controls, and drag on
| | 03:23 | a Round Rect Button, position it there,
give it a double-click, and say details.
| | 03:31 | This View Controller is of course also
showing an image on it, so I'm going to
| | 03:35 | switch to the Data Views section of
the Object Library, find the Image View,
| | 03:40 | drag that in there, and make
sure that it's sized appropriately.
| | 03:46 | It's currently going to be over the top
of my button, so I can use the Expanded
| | 03:50 | window here to make sure that it's behind there.
| | 03:56 | Next, I'm going to make sure that
the button is selected so I can see the
| | 04:06 | This will be a Modal Segue, and we'll
see how to manipulate that in a moment.
| | 04:11 | Now this final screen is going to
show us information about that image,
| | 04:15 | so for that, I'm just
going to do a couple of things.
| | 04:18 | First, I'll just click the
blank area to select the view.
| | 04:22 | I want to change the
background to, say, a light gray color.
| | 04:28 | Then I'll drag on a label
from the Object Library.
| | 04:34 | I'll widen this out a little bit and
perhaps even use the Attributes Inspector
| | 04:43 | to manipulate the font or the text color.
| | 04:48 | Change it to System Bold, for example.
| | 04:50 | Now, at the moment a label
would only show one line of text.
| | 04:54 | That's what it's limited to.
| | 04:55 | So one more thing that I'm going to
change it to is at the top of the Attributes
| | 04:59 | grab handles around it, and I'm going
to hit my Ctrl key and Ctrl+Drag to the final View Controller.
| | 04:59 | Inspector, change this to Lines Supported are 0.
| | 05:01 | That allows it to be multi-line.
| | 05:04 | And we will need a way of
dismissing this View Controller.
| | 05:07 | We won't have a Back button, because it
won't be in the Navigation Controller.
| | 05:12 | So I'm going to add on another button.
Just position that down the bottom and
| | 05:18 | double-click it and say done.
| | 05:20 | I am going to zoom out, take a look at this.
| | 05:25 | Looks okay. The only thing I'm going to
do, and I don't have to, is on the Table
| | 05:29 | View, I'm just going to zoom in here
and double-click the first Navigation Bar
| | 05:33 | to say something like Photos.
| | 05:35 | We'll talk about how to set the title
of that bar for other scenes in a moment.
| | 05:40 | So I have my storyboard. The next
step is I need to do some prep on this.
| | 05:45 | I need to create the custom class
that we're going to use to pass between
| | 05:49 | these different scenes.
| | Collapse this transcript |
| Step two: creating the custom class| 00:00 | So step 2. Before we get much further, I
am going to create the custom class that
| | 00:04 | we will be passing between scenes.
| | 00:07 | So in Xcode, go to my File menu, create
a new file, and what I am going to look
| | 00:12 | for here under iOS is just a Cocoa
Touch Objective-C class, a plain class here.
| | 00:18 | Nothing to do with view
controllers or test cases.
| | 00:20 | Click Next, and I will call this Photo
and it will be a subclass of NSObject.
| | 00:27 | I do want to save it into my
project, so I'll just click Create here.
| | 00:31 | It has taken me to the
implementation of my Photo class.
| | 00:34 | I need to actually jump across
to the .h file into the header.
| | 00:39 | In here I am just going to
declare three properties.
| | 00:43 | They are all going to be non-atomic
and strong. And all I am having here is a
| | 00:54 | name, a file name, and a notes property.
| | 00:56 | They are all just NSStrings.
| | 00:59 | Of course if I define the properties
in my header file, I better jump across
| | 01:03 | into my implementation and make sure that I
have the synthesize statements for these.
| | 01:12 | And that's our custom class created.
| | 01:14 | I am not going to add any methods to this.
All I really want is a basic data structure.
| | 01:19 | On to the next step.
| | Collapse this transcript |
| Step three: creating the view controllers| 00:00 | So for step 3, here's the problem.
| | 00:03 | In our storyboard we've dragged on
multiple View Controller scenes, but we
| | 00:07 | don't have any corresponding View Controller
class files for these scenes in our project.
| | 00:11 | There is nowhere we could write custom
code for each of these different scenes.
| | 00:16 | So we need to provide our own View
Controller classes, the .h and .m files.
| | 00:21 | And if we don't, all these scenes on
our storyboard are just going to use the
| | 00:25 | built-in View Controller classes
in iOS, meaning no custom behavior.
| | 00:30 | So how many new class files do we need?
| | 00:32 | Well, we're going to need three.
| | 00:34 | The first one will be for our Table View
Controller so we can show the list of photos.
| | 00:39 | We'll need another class for the scene
that displays the image, and then we'll
| | 00:44 | need a third one for the View Controller
scene that shows information about each photo.
| | 00:49 | The only thing we won't need custom
code for is for the Navigation Controller,
| | 00:54 | because we don't need it to do
anything other than what it usually does.
| | 00:58 | So how do we add these files?
| | 00:59 | Well, up to the File menu, and I'll
click New > File, not New > Project, not New >
| | 01:04 | Target, but New > File.
| | 01:06 | We are going to add an Objective-C
class, so making sure that Cocoa Touch is
| | 01:11 | selected under iOS and then
Objective-C class here. Click Next.
| | 01:16 | We're not doing a standard
class that inherits from NSObject.
| | 01:20 | We want a very specific class for each of these.
| | 01:23 | They are expecting a class that can
already deal with the basic functionality
| | 01:28 | involved in being a UIViewController
or a UITableViewController, and that's
| | 01:33 | dependent on what we actually
dragged onto the storyboard.
| | 01:36 | So our first one is going to be a
subclass not of NSObject or UIView or even
| | 01:41 | UIViewController, but
UITableViewController. I am going to do this for the first
| | 01:46 | one, and I'll call it PhotosTableViewController.
| | 01:51 | I am paying attention to the
capitalization here so that it will look correct
| | 01:56 | when we view it in our storyboard.
| | 01:59 | This will be a subclass of
UITableViewController, and I want both of these
| | 02:03 | check boxes unchecked.
| | 02:04 | We do not need an extra XIB for the
user interface, and we're doing this
| | 02:08 | right now on the iPhone. So click Next.
| | 02:12 | It asks, do we want to add them to a project?
Absolutely, and Create.
| | 02:15 | And it gives me the .h and .m files.
| | 02:18 | Now, before I change anything, I am
going to just go ahead and add the others.
| | 02:23 | Up to the File menu, New > File. The
next one will again be an Objective-C class,
| | 02:28 | this time for the section
that actually displays the image.
| | 02:32 | I'll call it DisplayViewController.
| | 02:34 | That will be my name for it.
| | 02:36 | This time around, this is
not a TableViewController.
| | 02:39 | It's a UIViewController.
| | 02:41 | Once again, both check boxes unchecked.
| | 02:44 | We'll click Next and add it to the project.
| | 02:47 | And one last time, for the final
scene that will display information,
| | 02:53 | we'll create a new Objective-C class.
| | 02:55 | I'll call this one InfoViewController,
and this one also is a subclass of
| | 03:00 | UIViewController. Both check boxes
unchecked, click Next, and Create.
| | 03:05 | Now, if you're wondering, how would
I know which class to inherit from?
| | 03:09 | Well, it's actually very easy.
| | 03:10 | When we were building the storyboard, if
I open up my Utilities panel here, what
| | 03:15 | did you actually drag on for the scene?
| | 03:17 | If you dragged on a View Controller,
then you want a corresponding class that
| | 03:20 | inherits from UIViewController.
| | 03:22 | If you dragged on a Table View
Controller, you want a class that inherits from
| | 03:26 | UITableViewController, and that's so
these scenes can have the right base
| | 03:30 | functionality and we don't have to write it all.
| | 03:32 | Now, here's the very important step.
| | 03:35 | We've added these three new classes,
but there is no connection between those
| | 03:40 | and the three scenes that are
actually sitting in our storyboard.
| | 03:44 | So before I go any further, I'm going
to hook up these scenes to their correct
| | 03:48 | corresponding classes.
| | 03:49 | Now, to do this I'm going to do two things here.
| | 03:51 | First, make sure that I am zoomed into
100%. Even though it doesn't look all
| | 03:57 | that useful, this is the only way
of reliably interacting with the
| | 03:59 | storyboard right now.
| | 04:01 | I am going to open up the Utilities
panel. Now making sure that I am looking at
| | 04:06 | the right one, I can ignore
the Navigation Controller.
| | 04:08 | I am looking for my Table View Controller.
| | 04:10 | I am going to just click in there to
select it. And I want to see these two
| | 04:15 | icons on the dock, because I need to
be able to select the second one, the View Controller icon.
| | 04:20 | With that selected, I should see the
blue bar being highlighted around this.
| | 04:24 | Why am I doing this?
| | 04:26 | Because with the Utilities panel open, I
am going to go over to the third part of
| | 04:31 | the Inspector, what's
called the Identity Inspector.
| | 04:34 | And this is where it's telling me
what this scene is using as an underlying
| | 04:38 | class definition, and right
now it's UITableViewController.
| | 04:42 | They're built in one in iOS.
| | 04:44 | This is not what I want.
| | 04:45 | I want my custom one that I just made.
| | 04:47 | If I click the dropdown box, we can see
that it's smart enough to look through
| | 04:51 | the classes that are in my project and
say, hey, the only other one that counts,
| | 04:56 | because it has to inherit
from UITableViewController, is
| | 04:59 | PhotosTableViewController, and
that's how I make the connection.
| | 05:03 | Back into the storyboard,
drag along into the second one.
| | 05:06 | This is the scene that will display the image.
| | 05:09 | I am going to select somewhere in
there, make sure I can click the second
| | 05:12 | icon that represents View Controller so I see
everything highlighted with the blue outline.
| | 05:17 | Again, in the Identity Inspector it says
it's right now using just the built-in
| | 05:21 | default UIViewController class.
| | 05:24 | We need that to be our new
DisplayViewController class.
| | 05:28 | Now, there are more built-in and not
built-in classes here that are options, but
| | 05:33 | I want this one, DisplayViewController.
| | 05:36 | And finally, on to the last one,
we'll highlight this, highlight the View
| | 05:42 | Controller for the third one that will
show us the information about the photo,
| | 05:45 | and if I browse through it, we can
find InfoViewController, which was what I
| | 05:50 | defined over here in my project.
| | 05:53 | So now we have the different scenes
connected to their corresponding class files.
| | 05:58 | Well, what's the next step?
| | 06:00 | If I look at these scenes, I think, how
many of these scenes actually need to
| | 06:04 | know about that new custom class that I
created, the photo class, in the previous step?
| | 06:10 | Well, all of them.
| | 06:11 | The TableViewController
will be showing a list of them;
| | 06:14 | the DisplayViewController
will show an individual image;
| | 06:17 | and the InfoViewController will show
information that's part of the object.
| | 06:21 | So what I am going to do is before I
go much further, I am going to select my
| | 06:25 | PhotosTableViewController header file
and add an import statement for Photo.h.
| | 06:32 | And then I can just copy that and
paste it into the header files of my
| | 06:37 | DisplayViewController and
InfoViewController, because they all need to know
| | 06:41 | about that custom class.
| | 06:43 | Well, while we're talking about which
scenes and which classes need to know
| | 06:47 | about which other scenes and which classes,
| | 06:50 | we know that we're going to go from
the PhotosTableViewController to the
| | 06:54 | DisplayViewController.
| | 06:55 | We're going to segue from this one,
and then we are going to segue from the
| | 06:59 | DisplayViewController to the
InfoViewController, and we're going to be
| | 07:01 | passing information.
| | 07:02 | And what that means is our
PhotosTableViewController--and I'll jump into
| | 07:07 | the header file here--
| | 07:08 | this one also needs to have
an import statement for the
| | 07:11 | DisplayViewController header file.
| | 07:14 | That's the one we are going to segue to.
| | 07:16 | And in a very similar fashion, if I
jump to my DisplayViewController header
| | 07:20 | file, this guy needs an import
statement for the next one along, the
| | 07:24 | InfoViewController header file.
| | 07:26 | And this is because we're going to
pass information between them. Okay.
| | 07:30 | Well, what else?
| | 07:32 | Well, our TableViewController scene
will need to have a way of holding these
| | 07:37 | different photo objects.
| | 07:38 | So I am just going to have them
stored as an array of photo objects.
| | 07:42 | I will jump into the
PhotosTableViewController implementation file.
| | 07:46 | Now, I could do this as a property, but
I really don't need to, because I don't
| | 07:50 | need any other class than
this one to be able to use it.
| | 07:53 | So inside the implementation, all I am
going to add is a declaration here for an
| | 07:58 | NSMutableArray. And I'll call this photos.
| | 08:03 | We're going to write the code to
load this array in a minute when the
| | 08:07 | actual application loads.
| | 08:09 | Now, while this one will need
to hold an array of photos, the
| | 08:13 | DisplayViewController only needs one
and the InfoViewController only needs one.
| | 08:17 | It needs a place we can pass
a single photo object around.
| | 08:21 | So they actually need a
property that's accessible.
| | 08:24 | So with the DisplayViewController, I am
going to jump into the header file here
| | 08:29 | and actually just create a property.
And I'll call this one currentPhoto.
| | 08:35 | Copy that line of code, because we're
going to use it again in the next class,
| | 08:39 | but before I jump over there, I better
jump into my implementation and make sure
| | 08:43 | that inside the implementation we
have a line that actually synthesizes it.
| | 08:49 | Similar thing in the final ViewController.
| | 08:52 | I'll paste in a property declaration so
we can reach in and set this, and in its
| | 08:57 | implementation, we'll have a
synthesize statement for that. And this is all
| | 09:02 | being done so we can pass some
information between the scenes.
| | 09:05 | Now, jumping back into scan the
storyboard. Because I can tell from looking at
| | 09:10 | this, we will need to
programmatically be able to set the image on this
| | 09:14 | DisplayViewController and set the
label on the Information View Controller,
| | 09:18 | well, we better get those
set up ready to take that code.
| | 09:22 | So I am going to just zoom in to Full
Size so I can interact with this properly.
| | 09:27 | And giving myself a bit more real estate,
I am going to open up the Assistant Editor.
| | 09:33 | This is going to make it easy to add
properties that represent my image view on my label.
| | 09:39 | So I am selecting the
DisplayViewController here, and I want to make sure that
| | 09:44 | the Image View section is highlighted.
| | 09:46 | If I am not totally sure, I can use
the Jump Bar and make sure I've got Image View selected.
| | 09:51 | And with the Assistant Editor open,
I should be looking at the code for
| | 09:55 | DisplayViewController.
| | 09:56 | And what I can do is just
Ctrl+Drag from the Image View inside the
| | 10:01 | interface somewhere. I'll do it as an outlet.
| | 10:03 | I'll call this one currentImage.
| | 10:06 | Just checking, yes, it's a UIImageView.
That looks correct.
| | 10:09 | And after you've done that, just scan
the property to see if everything looks
| | 10:13 | right. It's an IBOutlet of type
UIImageView called currentImage.
| | 10:17 | Fine, We'll have the synthesized statement
will have been generated automatically.
| | 10:21 | And similarly, on the final scene I
want to highlight Label, I should notice in
| | 10:26 | Assistant View that we've changed to
InfoViewController header file, and
| | 10:30 | Ctrl+Drag from this into the file,
let go, it should be of type UILabel.
| | 10:35 | It should be an outlet, and I'll
call this one detailsLabel and Connect.
| | 10:42 | Again, just scan it, make sure
that the generated code looks correct.
| | 10:45 | It's a UILabel called detailsLabel.
| | 10:48 | So while we haven't done an awful lot
with these parts of our storyboard, we're
| | 10:52 | pretty much set up and ready to go, and
we'll start interacting with these in
| | 10:56 | the next step.
| | Collapse this transcript |
| Step four: loading the data| 00:00 | So step 4, let's get some
data loaded into the Table View.
| | 00:03 | I am just going to switch back into
the standard Editor mode and jump to the
| | 00:08 | implementation file of my
TableViewController, which is
| | 00:11 | PhotosTableViewController.
| | 00:13 | I have already defined an NSMutableArray
here, so what I need to do is just load
| | 00:17 | this with some basic data, create some
of those photo objects and load them in.
| | 00:21 | I am going to use the Jump Bar
just to jump down to say viewDidLoad.
| | 00:25 | We are just going to do
some static objects here.
| | 00:38 | First, just initialize that NSMutableArray
object, then create the first Photo object.
| | 00:49 | The only reason for this to exist is so we
can hold some data in it, hold some information.
| | 00:54 | So I'll just set its Name,
its Filename, and its Notes.
| | 01:24 | And then finally, add that to our photos array.
| | 01:30 | And rather than make you watch a lot of
this, I am going to just paste in a few
| | 01:33 | lines of code that's doing exactly
the same thing, just a few more times.
| | 01:38 | The only difference being of course if
I am reusing the pick reference, I don't
| | 01:42 | need to actually create it as a pointer there.
| | 01:45 | So we are just creating multiple
photo objects, adding them to the array.
| | 01:50 | So I have these objects, but there's
nothing that's actually going to load them
| | 01:54 | into the Table View itself.
| | 01:56 | So that's the next step.
| | 01:58 | In the photo's TableViewController,
I'm going to click on the Jump Bar.
| | 02:02 | Because this was created as a
UITableViewObject, I have automatically got the
| | 02:07 | TableView data source methods,
and they are actually going to have boilerplate code in there;
| | 02:11 | so numberOfSectionsInTableView, how many
rows in the section, what's in each cell?
| | 02:16 | If I jump to the first one,
numberOfSectionsInTableView, it's going to give me a
| | 02:20 | warning that this is a potentially
incomplete method implementation.
| | 02:24 | This needs to say how many
sections does the TableView have.
| | 02:27 | I am going to delete the
warning and just say to return 1.
| | 02:31 | We move down to how many
rows are in the section?
| | 02:34 | Again, it's giving me the
warning here. Fill this out.
| | 02:37 | Okay, I am going to.
| | 02:38 | NumberOfRowsInSection
will be based on the array.
| | 02:41 | The array is called photos.
| | 02:43 | It's just going to be photos count.
| | 02:45 | And then, we finally have the important one,
| | 02:48 | cellForRowAtIndexPath.
| | 02:50 | This method will be called repeatedly based on
however many objects are in that photos array.
| | 02:56 | Now, we need to create the
content for each table cell.
| | 03:00 | We've got the standard code in here
for dequeueing a reusable cell with
| | 03:04 | identifier, the same kind of thing we've
talked about in the other examples of TableViews.
| | 03:08 | Let me just hide the navigator to see
this a bit clearer, because all I want to
| | 03:13 | do when this method is called is pull
the corresponding photo out of the array
| | 03:17 | and grab the text, grab the title of that photo.
| | 03:22 | So I'll create a variable to just hold a photo.
| | 03:26 | I don't need to actually
instantiate it. It already exists.
| | 03:28 | It's in some position in that existing array.
| | 03:31 | So I need to access the array and
pull it out based on the current cell.
| | 03:36 | This I am just going to get
from the parameter indexPath.row.
| | 03:42 | Because this method is called repeatedly, passing
in a parameter of indexPath, so 0, 1, 2, 3, 4.
| | 03:51 | It means we could adjust our array.
| | 03:53 | We could just load it up with more
information and all this code would still work.
| | 03:57 | Then we could use just the square
brackets of Objective+C. I am using a bit of
| | 04:00 | square brackets and a bit of .syntax
here, whatever you are comfortable with.
| | 04:05 | And then we can use the cell
that was created on line 129.
| | 04:08 | We are interested in its textLabel
property, which itself has a text property,
| | 04:17 | because the label could have setText,
setFont. There is a whole bunch of
| | 04:21 | different options that it has here. But
I am just going to set it to the name of
| | 04:26 | the current photo that we
just grabbed on line 134.
| | 04:29 | Again, whatever you are happy with,
whether it's .syntax or the Objective-C
| | 04:34 | square brackets, whatever works.
| | 04:36 | There are multiple ways to write this.
| | 04:38 | Now, one more thing that's very important here.
| | 04:42 | We've talked a little bit about this idea
of having reusable cells with identifiers.
| | 04:48 | When a cell is instantiated, it's
given a little tag, just a string, a few
| | 04:52 | pieces of text, and the idea here is
that you might have multiple kinds of
| | 04:57 | different cells, and when we are
reusing them, we don't want to reuse the wrong
| | 05:01 | kind of cell object.
| | 05:03 | Now, we are only using one kind of
cell here, but this is still important to
| | 05:07 | look at, because if I jump over to the
storyboard and highlight the individual
| | 05:15 | cell on my TableView, bring up my
Utilities panel, I am currently on my Identity
| | 05:21 | Inspector, but I need to go
to my Attributes Inspector.
| | 05:24 | The TableView cell, again, making sure
that is what you have selected, has its
| | 05:29 | own reuse identifier.
| | 05:31 | You can tag it here and, in
fact, you should tag it here.
| | 05:35 | I am going to give it a name of PhotoCell.
| | 05:38 | Really, it doesn't matter what you call it,
but just some way of identifying this.
| | 05:42 | Again, the benefit being that in the
Storyboard View, you can actually just lay
| | 05:46 | out and design multiple different
kinds of cells that could all be used
| | 05:50 | together inside one TableView, and you'd want to
be able to identify each kind of cell properly.
| | 05:55 | So if I've called this PhotoCell,
then what I need to make sure back in my
| | 06:00 | TableViewController, is that's the
word that I use when I instantiate it.
| | 06:05 | I am going to save this all, build
this project, and we'll see what happens.
| | 06:09 | It's not finished yet, but we should be
able to get at least some parts of it working.
| | 06:14 | Build has Succeeded. I'll click Run.
| | 06:16 | And the application loads in the Simulator.
| | 06:20 | I can see that I am certainly
getting the individual entries.
| | 06:23 | Of course they are not loading into the
DisplayViewController, because I haven't
| | 06:27 | written anything to do that, because
now we need to start passing information
| | 06:33 | between the scenes, and that's the next step.
| | Collapse this transcript |
| Step five: passing objects between scenes| 00:00 | Okay, step 5.
| | 00:01 | Now, we need to start passing
information from first the Table View Controller
| | 00:06 | to the Display View Controller, and
then if necessary, from the Display View
| | 00:10 | Controller to the Info View Controller.
| | 00:13 | And we do this by using the new View
Controller method called prepareForSegue,
| | 00:17 | and this is automatically
called when any segue is triggered.
| | 00:21 | And what that means is that in our
PhotosTableViewController implementation
| | 00:26 | file, what we're not interested in is
the didSelectRowAtIndexPath method, which
| | 00:32 | is the usual one that you tap on for table view.
| | 00:35 | When you're working with storyboards and you
have your segue set up, you don't need that.
| | 00:39 | So we're going to create a new method
here--and I could put this anywhere.
| | 00:43 | I'm just going to put it up at
the top here, just underneath my
| | 00:46 | MutableArray definition.
| | 00:51 | It returns void, and
it's called prepareForSegue.
| | 00:54 | That is a built-in method, so even as I
start typing, it's going to bring it up here.
| | 00:59 | I need my opening and closing curly braces.
| | 01:02 | And we've got to think about what we're doing.
| | 01:03 | Well, we are currently in the
PhotosTableViewController, and we're going to
| | 01:09 | segue over to the DisplayViewController.
| | 01:13 | And we want to be able to
pass it some information.
| | 01:16 | And here's how we do it.
| | 01:17 | In the prepareForSegue method, I'm
first going to create a reference to the
| | 01:21 | DisplayViewController we're about to segue to.
| | 01:25 | I'll call it dvc, but how do I get this?
| | 01:28 | Well, here's the great thing.
| | 01:30 | When we're preparing for a segue, the
whole infrastructure here that's going on
| | 01:34 | actually knows what we're about to segue
to, and I can ask for that information.
| | 01:38 | I can ask the segue parameter here,
what is the destinationViewController?
| | 01:43 | Where are we about to go?
| | 01:44 | Because we could be segueing out of
this View Controller to multiple places.
| | 01:49 | Then what I'm going to create is an
NSIndexPath reference to the currently
| | 01:55 | selected cell in the
TableViewController, in myself. So where am I?
| | 02:02 | self.tableView indexPathForSelectedRow.
| | 02:08 | And this will allow me to grab the right photo
object so I can pass it over in just a second.
| | 02:14 | All I'm interested in about the
Index Path is the row, but that's fine.
| | 02:17 | What I'm going to do is just create
a Photo Pointer to grab the selected
| | 02:22 | photo out of the array.
| | 02:24 | It's the photos array, and I'm
interested in objectAtIndex, and we're going
| | 02:29 | to use the path variable we just created,
and we're interested in the row element of it.
| | 02:36 | Again, this could be .syntax path.row,
or I could use the square brackets and
| | 02:42 | say path, space, row.
| | 02:44 | So I have a reference to the
DisplayViewController we're about to segue to.
| | 02:49 | I have a reference to the current
photo that we've just selected, which I've
| | 02:53 | called c. So I'll use that reference
to the DisplayViewController and say
| | 02:57 | setCurrentPhoto, which is the property
we created in, in that object to c. This
| | 03:06 | is all the code I need to do to grab a
reference to where we're going and pass
| | 03:09 | it some information.
| | 03:10 | Now, for good practice I'm
going to add one extra thing to this
| | 03:14 | prepareForSegue method.
| | 03:16 | Because we could be segueing out of
this View Controller to multiple places,
| | 03:22 | this method could be being called
multiple times, and you might want to ask,
| | 03:26 | well, which segue am I about to do?
| | 03:29 | So we can actually create an if statement.
| | 03:31 | I'll fill in the condition in just a second.
| | 03:34 | And what I first want to ask is, if
it's the correct segue, we're going to do
| | 03:38 | that code that I just wrote.
| | 03:39 | Well, how do I know what the correct segue is?
| | 03:42 | If I jump back to the storyboard,
we can actually name these segues.
| | 03:47 | We can give them an identifier.
| | 03:49 | So I've clicked on the Segue itself to
select it and I open up my Utilities panel.
| | 03:54 | You see the segue only has two properties here:
| | 03:58 | an Identifier and a Style--
is it Push, Modal, or Custom?
| | 04:01 | I'm going to give it an Identifier of ShowPhoto.
| | 04:05 | Now, jump back into my implementation
file, and what I'm going to ask up here is
| | 04:10 | if we can ask the Segue
parameter, are you equal to that segue?
| | 04:25 | Are you the ShowPhoto segue?
| | 04:27 | If so, we can transition there.
| | 04:29 | This is not strictly necessary in our
example, because we only have one segue
| | 04:33 | out of this View
Controller, but you get the idea.
| | 04:36 | If we had multiple segues, this is how
we'd ask which one are we about to do, so
| | 04:40 | we can make sure we're passing
the right information to the right
| | 04:44 | destinationViewController.
| | 04:46 | So we're passing the photo object over
into the DisplayViewController, so we
| | 04:51 | better go and load it in there.
| | 04:53 | So I'm in the DisplayViewController.m file.
| | 04:57 | I'm going to come in and uncomment my
viewDidLoad method, and this is what's
| | 05:01 | going to be called when the storyboard
creates this View Controller and loads it in.
| | 05:07 | So after the call to super
viewDidLoad, I'm going to instantiate a new
| | 05:11 | UIImage object, and I'm going to call it by
using the very useful UIImage imageNamed method.
| | 05:21 | imageNamed just takes the name of an image file.
| | 05:24 | It's going to go and find it
in our applications bundle.
| | 05:27 | All I need to do is give it the file name of
the current photo object that we passed in.
| | 05:36 | I've grabbed that image.
| | 05:37 | Now I'm going to set the Image View
that's actually on our View Controller.
| | 05:42 | This was named as currentImage when we
hooked it up as an outlet, and I'll just
| | 05:47 | use the call to setImage:
| | 05:48 | image we created on the previous line.
| | 05:52 | Just going to save that and
run this. Let's check it.
| | 05:56 | So in the TableViewController we take,
say, the Beach object, we pass it over,
| | 06:00 | and we're loading in the Beach image.
| | 06:02 | Haven't done the final View Controller yet, but
we'll get to that in a second. Quit out of that.
| | 06:08 | Now, one of the things I'd like to
do is also set the title of this View
| | 06:12 | Controller so that it will appear
properly in the Navigation Bar at the top.
| | 06:16 | That's very easy to do.
| | 06:17 | What we're going to just call is a
self setTitle, which is a property of the
| | 06:23 | View Controller, and we want it to be
the name of the current photo object,
| | 06:29 | which will be currentPhoto, space, name.
| | 06:33 | Again, .syntax or square brackets,
it's up to you. Run that again.
| | 06:38 | And because we're passing the entire
object in, if I pass in Olives, we can use
| | 06:43 | Olives and grab the ping and we also
set the title on the Navigation Bar.
| | 06:49 | Flag, Overlook, it's working just fine.
| | 06:54 | But this scene in the
DisplayViewController can segue to the next scene by
| | 06:59 | clicking this button, so we
better go and fix that one.
| | 07:02 | So in our DisplayViewController we
need another prepareForSegue method.
| | 07:08 | For purposes of time,
I'll just put it right here.
| | 07:10 | It is again (void) prepareForSegue.
| | 07:14 | I want to grab a reference
to an InfoViewController.
| | 07:17 | This is what we're about to transition to.
| | 07:20 | I'll just call it ivc.
| | 07:21 | And again, I get it by asking the
segue, what's your destination, where are
| | 07:27 | you about to segue to?
| | 07:29 | We now have a reference to that
destination, so all I need to do is use its
| | 07:33 | property of setCurrentPhoto, there
we go, to my own currentPhoto object.
| | 07:40 | Again, we're passing this from one
object to the next and then on to the next.
| | 07:47 | That's all I need to do in this prepareForSegue.
| | 07:49 | For this one, I'm not going
to check the name of the segue.
| | 07:53 | You saw that example previously.
| | 07:55 | We don't actually need to do it here.
| | 07:58 | What I am going to do is jump over
into the implementation file for my
| | 08:02 | InfoViewController, so that in
viewDidLoad here--and I need to come down and
| | 08:06 | uncomment it-- we can make sure to set
the text of the label, which is simply
| | 08:16 | going to be the notes
property of our currentPhoto object.
| | 08:20 | Save that, run this, objects are
created and loaded into the Table View.
| | 08:27 | We tap one of them.
| | 08:28 | We segue passing that object to
the second scene, click the button.
| | 08:33 | We segue, passing that
object to the final scene.
| | 08:36 | Now, what we don't yet have is a
way of hooking this button back up.
| | 08:41 | Because we're not embedding this one in
the Navigation Bar, it doesn't give us a
| | 08:44 | Back button, so we need to fix that.
| | 08:47 | So quit out of this, return to the
storyboard, and I'm interested in our
| | 08:51 | final View Controller.
| | 08:53 | I'll zoom in so we can see that
properly, and open up the Assistant Editor,
| | 08:59 | so that in our InfoViewController we can
cause an action to happen from this button.
| | 09:04 | It's an IBAction.
| | 09:06 | Making sure that I have both the button
selected on this final View Controller
| | 09:10 | and the correct file selected here,
which is our InfoViewController header file,
| | 09:14 | I am going to Ctrl+Click,
drag into the interface.
| | 09:18 | I'm not adding an outlet;
| | 09:19 | I'm adding an action.
| | 09:21 | And I want this to dismiss
this current View Controller.
| | 09:24 | So I'll just call it dismiss;
| | 09:25 | you could call it whatever you want.
| | 09:28 | Jump back into the standard editor,
because I need a bit more space here, and
| | 09:32 | find the implementation of that
InfoViewController, which should have created
| | 09:37 | our skeleton method right down
at the bottom, and there it is.
| | 09:40 | And here's where we need to dismiss
this current ModalViewController that we
| | 09:45 | did a Modal segue to.
| | 09:47 | All I need to do is say,
hey, dismiss yourself, self
| | 09:51 | dismissModalViewControllerAnimated:YES.
| | 09:56 | Save, run.
| | 10:00 | Load the Table View, tap one of
these, transition to the next scene.
| | 10:05 | We've set the title properly.
| | 10:06 | We've set the image properly.
| | 10:08 | Tap the button, transition to the next scene.
| | 10:11 | We're looking at the
notes loaded into the label.
| | 10:13 | Click the Done button.
| | 10:14 | We transition away from the ModalViewController.
| | 10:17 | The only thing I don't
really like is this Modal segue.
| | 10:20 | We're taking over the entire screen, and we
really don't need that much of it. So let's fix that.
| | 10:26 | Jump back into the storyboard, and when
I select the final segue that's segueing
| | 10:31 | into the final scene, I'm going to open
my Utilities panel, and with that segue
| | 10:35 | selected, I'll see that with the
Modal style, I have multiple transitions:
| | 10:40 | Cover Vertical, Flip Horizontal,
Cross Dissolve, or Partial Curl.
| | 10:44 | And Partial Curl should do the trick.
| | 10:46 | I set that, we run it again.
| | 10:50 | Now we load the Table View, select an object,
pass it to the second scene, click the button.
| | 10:56 | We do the Modal segue
with the animated page curl.
| | 10:59 | I'm done, back, and alter the next.
| | 11:10 | So while this is not the most
complicated application in the world, we can see
| | 11:14 | that with just a few lines of code
here's how we can have multiple View
| | 11:17 | Controllers segue into each other,
interacting between Table View Controllers,
| | 11:22 | Navigation Controllers, Custom
Objects, different types of segues.
| | Collapse this transcript |
|
|
10. Using Blocks and Grand Central DispatchIntroduction to blocks| 00:00 | There is a language feature
in Objective-C called blocks.
| | 00:03 | This was made available in iOS
development with iOS 4 in 2010.
| | 00:08 | We use blocks to group code
together into reusable chunks.
| | 00:12 | You might first hear that
description and think, okay, and then a few
| | 00:15 | seconds later think, but, surely
that's what we do with classes and
| | 00:19 | functions and methods.
| | 00:21 | And yes, they all do allow us to group
code together into reusable chunks, and
| | 00:25 | there are similarities, but blocks
are used for very specific reasons.
| | 00:29 | So why do we use them in the first place?
| | 00:31 | Well, first and main reason is that
you're going to have to. While you can get
| | 00:36 | by with the Foundation Framework and
UIKit without blocks fairly well, many of
| | 00:41 | the newer and the updated and the
more interesting frameworks in iOS
| | 00:45 | development use blocks.
| | 00:47 | If you want to use the Assets Library,
Grand Central Dispatch, new audio and
| | 00:51 | video features, the Game kit, you're
going to have to get to know these.
| | 00:55 | Blocks are not some weird
esoteric feature that you get to ignore.
| | 00:59 | If you're going to work seriously with
iOS development, you'll be about as able
| | 01:02 | to avoid blocks as you
would be able to avoid integers.
| | 01:06 | And they can make your life easier.
| | 01:09 | They allow you to write less code, more
readable code, and they easily allow you
| | 01:12 | to tap into powerful techniques in iOS
development. Things like multithreading
| | 01:17 | and callbacks become a lot easier using blocks.
| | 01:20 | And in fact, this is why blocks, or
at least their equivalent concept, are
| | 01:24 | common in other languages.
| | 01:26 | In fact, Objective-C was a
little late to the party with blocks.
| | 01:30 | Other languages have had blocks
or their equivalents for years.
| | 01:34 | You might be working with a language
that has something like an anonymous
| | 01:37 | function or a closure or a lambda.
| | 01:40 | Well those are the equivalent
of blocks in other languages.
| | 01:43 | So how do we actually do this?
| | 01:45 | Let me show you a simple example of the syntax.
| | 01:48 | We are talking about blocks
being reusable chunks of code,
| | 01:51 | So let's take one that we
already know how to use.
| | 01:54 | Let's say we've got a function, and this
could be in just about any C-based language.
| | 01:58 | It's not even a method, just a very
basic function here called myFunction, and
| | 02:02 | we know how we'd call it in our own code.
| | 02:05 | So the function is made of a return type.
| | 02:08 | It's made of a name.
| | 02:09 | It's got some arguments defined
in it, and it has a body to it.
| | 02:13 | The body could be one line of code,
could be a dozen lines of code, could be a
| | 02:17 | thousand lines of code,
so a very typical function.
| | 02:20 | And when we think about a
reusable chunk of code, we might think of
| | 02:23 | something like this.
| | 02:24 | We define it and then we call it.
| | 02:26 | Now, if you want to see its direct
equivalent using blocks, you might see
| | 02:31 | something like this, and you will
quite commonly see this format shown when
| | 02:35 | you're being introduced to blocks.
| | 02:37 | I don't find this format is all
that useful, and I will explain why.
| | 02:41 | Yes, a block can be created like this
where we have the official return type.
| | 02:46 | We have the name of the block like
we'd have the name of a function, and it's
| | 02:50 | got the caret symbol before that.
| | 02:52 | We'll talk about that in a second.
| | 02:54 | And here we have something that says arguments.
| | 02:57 | But in fact, in this particular
format we will have another section that's
| | 03:00 | officially called arguments as well, and it
doesn't really look like we've won anything.
| | 03:05 | This is more code than we used before,
and it's actually bit more annoying to
| | 03:09 | look at because of the caret symbol.
| | 03:12 | The problem is this.
| | 03:13 | When you see the full declaration
of what a block could be, it's a bit
| | 03:18 | misleading because it's
giving us a lot of optional stuff,
| | 03:21 | things we would have to do for a
function, but we don't have to do for a block.
| | 03:26 | One of the things we're looking at
here is actually two blocks, which is why
| | 03:29 | we're seeing two of these carets.
| | 03:32 | Effectively, we're seeing the first
part here being a block variable and the
| | 03:36 | second part being a block literal.
| | 03:39 | Block variable means we're
actually naming it like a variable.
| | 03:42 | We're seeing it has a return type
and it says parameters, and on the
| | 03:45 | right-hand side of the equals sign,
we're actually saying what is the block,
| | 03:49 | what is the literal?
| | 03:50 | And in fact, the block literal part
is the most important part of this, and
| | 03:54 | the most useful part.
| | 03:55 | An analogy I could make is say
when we're working with strings.
| | 03:59 | We can do something like this and
it's quite common to create a string
| | 04:03 | variable and set it to the value using a
string literal, or at least a string literal format.
| | 04:10 | But a lot of the time, we just
want to use a string as a literal.
| | 04:14 | We just want to write one without
having to go through the whole problem of
| | 04:17 | defining an NSString
variable and alloc it and init it.
| | 04:21 | We just want to use it.
| | 04:22 | In the same fashion, if we go back to
our block declaration, while this is the
| | 04:27 | full formal declaration of a block,
what we can often do is just dump the first
| | 04:32 | part of it and say, no, this is all I need.
| | 04:35 | I need the caret symbol, some return types,
and then in braces, I just have some code.
| | 04:40 | That's it! But how do we use them?
| | 04:42 | Well, just like string literals, you
don't really find them by themselves.
| | 04:46 | That will be embedded and
used in some other code.
| | 04:49 | But if you're seeing that caret symbol,
the first symbol that we see here, on a
| | 04:54 | US or a UK keyboard, this is the Shift+6.
| | 04:57 | Now, if you're using a different
international keyboard, you may have to hunt for it.
| | 05:01 | But the caret symbol is
what tells us this is a block.
| | 05:04 | Once you see this symbol, you've got a block.
| | 05:07 | So your first exposure to them is
likely to be seeing them being used in some
| | 05:12 | call to one of the newer API
features, one of the newer frameworks.
| | 05:16 | I'll show you an example.
| | 05:17 | Again, don't worry too much about what
this exact syntax is. This is a method
| | 05:23 | that's defined in one of the new
classes, in the Assets Library framework, to
| | 05:28 | help us work with image
assets and video assets.
| | 05:31 | There is a method called
writeVideoAtPathToSavedPhotosAlbum, and it takes an
| | 05:36 | argument of a URL for a piece of video
that you might have taken. And then there
| | 05:42 | is another parameter called completionBlock.
| | 05:45 | What this allows us to do is make a
method call that's actually going to take a
| | 05:50 | couple of parameters.
| | 05:51 | Let's say I have got one called
myAsset that represents the URL to some video,
| | 05:55 | and I want to save it to my SavedPhotosAlbum.
| | 05:58 | completionBlock allows me to write this
block of code, pass it into this method,
| | 06:04 | and this code will be
executed when this method completes,
| | 06:07 | in this case, perhaps checking
if there was any errors with it.
| | 06:11 | Now, you might think, well, why don't I
just put that code after the method call?
| | 06:15 | Well, the benefit here is it allows
us to call methods that run on another
| | 06:19 | thread without worrying about
doing multithreading or callbacks.
| | 06:23 | This method executes. It immediately
returns to our code, but it will try and
| | 06:28 | save that video, which
could be quite a long process.
| | 06:30 | When it's done, it will call this
completionBlock, and go through this code.
| | 06:34 | So it's quite common to write a block
like this we're using the caret symbol and
| | 06:38 | just writing it straight inline
inside one of these method messaging calls.
| | 06:44 | Another alternative is you can
also create a block as an object.
| | 06:48 | The way they're defined, that same example,
I can actually save this block as a variable.
| | 06:54 | The type of this variable will be
ALAssetsLibraryWriteVideoCompletionBlock, and I
| | 06:59 | have just called this one block.
| | 07:01 | I save the value, all the code that I
want, and it could be dozens or even
| | 07:05 | hundreds of lines, and then a
little later, I use the block.
| | 07:09 | I just pass it in as a parameter.
| | 07:11 | So it's allowing me to create this chunk of
reusable code and pass it into a method call.
| | 07:17 | Now, this is all a little bit new.
| | 07:19 | Just keep in mind to recognize the
caret symbol as the immediate red light that
| | 07:23 | goes off and says, here, I have got a block.
| | 07:26 | You don't have to get obsessive about
the syntax immediately, though if you'd
| | 07:29 | like to, there is some really good
documentation on the Apple Developer sites.
| | 07:33 | But we're going to explore how to
use these blocks with one of the newer
| | 07:36 | features in iOS, something
called Grand Central Dispatch.
| | Collapse this transcript |
| Understanding Grand Central Dispatch| 00:00 | Grand Central Dispatch, or GCD, was a
new feature with iOS 4, and if you read
| | 00:05 | the official documentation from Apple
about it, you'll see lots of phrases
| | 00:09 | like "it provides systemic
comprehensive improvements in the support for
| | 00:12 | concurrent code execution."
| | 00:14 | Well, at the end of the day, we want
Grand Central Dispatch because it makes
| | 00:18 | multithreading easy.
| | 00:20 | Your question right back on this
might be, well, why do we care that
| | 00:22 | multithreading is easy?
| | 00:24 | And the end result, no matter how
you spin it, is we want to have a more
| | 00:27 | responsive user interface in our application.
| | 00:30 | We want our apps to feel more professional.
| | 00:32 | We want them to be able to
do multiple things at once.
| | 00:35 | Now, here we're talking about
multithreading, not multitasking.
| | 00:40 | Multitasking, which we have, is the
idea of multiple applications at the same
| | 00:45 | time. And as we've seen, iOS handles
switching different applications between
| | 00:50 | background and foreground states.
But we're talking about multithreading.
| | 00:54 | This is just for our app, the
ability for our application to do multiple
| | 00:58 | things at the same time.
| | 00:59 | And you still might be thinking,
well, why is this important?
| | 01:03 | And the issue is that we can have a
problem with the idea of our app having one
| | 01:08 | queue for processing.
| | 01:09 | We have this main queue, and it
performs tasks one after the other, strictly
| | 01:14 | in order, whether it's updating the UI,
performing calculations, connecting to
| | 01:18 | a database, whatever.
| | 01:19 | We can, with GCD, create a custom queue
and take some of these tasks off, make
| | 01:26 | them run on their own queue, and Grand
Central Dispatch in iOS will take care
| | 01:30 | of all of this, making sure it happens
responsively and it happens smoothly.
| | 01:34 | And the key benefit here is
particularly the ability to make sure our
| | 01:38 | user interface stays responsive even while
heavy processing goes on in the background.
| | 01:44 | So how do we use and work with Grand
Central Dispatch in our iOS applications?
| | 01:49 | There are two steps.
| | 01:50 | Step 1, you create a new queue.
| | 01:53 | We'll see this in a moment.
| | 01:54 | We give this a name, whatever name is
meaningful for us. This queue might be
| | 01:58 | just for networking or just
for long-running calculations.
| | 02:01 | Then step 2, you create blocks that we've
just talked about and you drop them in the queue.
| | 02:06 | That's step 2. Step 3 is nothing.
| | 02:10 | That's it. Okay, so there is a little bit more
when you get into advanced parts of this,
| | 02:15 | but for most people, most of the time,
the whole process of using Grand Central
| | 02:20 | Dispatch is, make a new queue in your
application, add blocks to the queue,
| | 02:24 | let iOS take care of everything else.
| | 02:27 | And if you're someone who has
programmed multithreaded code before, you'll know
| | 02:30 | that it's a fairly unpleasant thing to do.
| | 02:32 | Grand Central Dispatch doesn't just make
multithreaded code easier. It makes it easy.
| | 02:37 | Most of the time we're going to be
interested in two main commands that
| | 02:41 | we're going to execute.
| | 02:42 | One is to create a new queue, and it's
this function, dispatch_queue_create.
| | 02:48 | The way that we use it is like this,
to create a variable. In this case I've
| | 02:53 | called it myQueue, and I
give it a label, just a string.
| | 02:56 | That's pretty much it.
| | 02:57 | I've said myQueueName.
| | 02:58 | This could be a descriptive label
for what this queue is being used for.
| | 03:02 | The reason we give it a label is
if we want to see it in debugging information later on.
| | 03:07 | When I show you an example in a moment,
I'll show you that the typical label we
| | 03:10 | put in here is actually reverse DNS
notation, but you can put any text in here
| | 03:15 | that's meaningful for you.
| | 03:16 | So we've created a queue.
| | 03:17 | I've now got a queue variable called
myQueue, and then I'm going to use the
| | 03:21 | other most important command in Grand
Central Dispatch, which is dispatch_async.
| | 03:27 | And this simply takes two parameters:
| | 03:30 | the name of the queue that
we're dispatching to and a block.
| | 03:33 | I can see the caret here with the curly
braces that contain my block, everything
| | 03:38 | that we want to do asynchronously,
which in this case is just passing in one
| | 03:42 | message, one call to a
long-running operation method.
| | 03:46 | So we do have to use blocks to be
able to use Grand Central Dispatch, but
| | 03:50 | between these two calls and learning a
little bit about them, you'd be amazed
| | 03:54 | at the amount of stuff that you can do
creating your own multithreaded applications.
| | 03:58 | Well, I've talked for a while about
how easy this is, and I've shown you a
| | 04:01 | couple of the keywords, but to prove
it is easy, in the next module we're
| | 04:05 | actually going to go through and
show how to take an application from
| | 04:08 | single-threaded into
multithreaded using Grand Central Dispatch.
| | Collapse this transcript |
| Creating a multithreaded app| 00:00 | In this example, I'm going to use Grand
Central Dispatch and blocks to take an
| | 00:03 | application that's currently not
very responsive with the UI and make it
| | 00:08 | multithreaded with just a few lines of code.
| | 00:10 | So right now I have the simple application here.
| | 00:13 | It's got a date picker on it that I
can spin around and a button that says
| | 00:17 | long running operation.
| | 00:18 | I'm going to start interacting with the
date picker and then click the button.
| | 00:21 | And what initially will happen is the
entire user interface is locked up right now.
| | 00:26 | It's not responsive until we get
the result back from that operation.
| | 00:30 | Because the operation itself is blocking,
even the button itself is staying in
| | 00:34 | the depressed state.
| | 00:35 | So it's just not a responsive UI.
| | 00:38 | Your users aren't going to
like something like this. It doesn't feel professional.
| | 00:41 | It doesn't feel useful.
| | 00:43 | In fact, it feels like there
might be a problem with it. So let's deal with this.
| | 00:47 | First, I have to explain
what's actually going on.
| | 00:49 | Well, for a start, I don't
really have a complicated UI.
| | 00:52 | In fact, this date picker is
not even hooked up to anything.
| | 00:56 | It's just to show that even the
simplest, most independent user interface
| | 01:00 | element will become non-responsive if
your main thread is actually blocking.
| | 01:05 | So my button here is just
connected to a simple piece of code in the
| | 01:09 | implementation file,
| | 01:10 | this IBAction here that says
perform the longRunningOperation. And
| | 01:16 | longRunningOperation is
going to do simply two things.
| | 01:19 | First, on line 21, it's going
to go to sleep for five seconds.
| | 01:23 | And then on line 22, it will change the
text of the message label with a random
| | 01:28 | number using the
arc4random function. But that's it.
| | 01:32 | I don't have anything in here to do with
threading at all, but this is enough to
| | 01:36 | upset our user interface.
| | 01:38 | Whether this was a sleep for time
interval call, or it was a complex
| | 01:43 | calculation, it could all upset it.
| | 01:45 | So I want to turn this into using
Grand Central Dispatch and use its queues.
| | 01:51 | So first off, in here I'm actually going to
define just one queue that we can use locally.
| | 01:56 | So it's going to be
dispatch_queue_t, and I'll call it myQueue.
| | 02:06 | I'm just defining it here so it's global
in this View Controller across multiple
| | 02:10 | methods and whatever functions I might have.
| | 02:12 | And then the question is, well, where do I
create it? Where do I put something in this?
| | 02:17 | And I could do this in a whole bunch
of different places, but just for our
| | 02:20 | purposes, I'm going to do it when
the button is actually touched here.
| | 02:26 | I'll say myQueue =, and we make
a call to dispatch_queue_create.
| | 02:32 | It's brought it up here, so just hit
Return, jump into the first parameter.
| | 02:38 | I give it a label and an attributes list, and
right now the attributes list isn't being used.
| | 02:43 | Now, they're both actually optional, but
the recommendation is you give it a label.
| | 02:47 | Now, we don't have to use the at sign here.
| | 02:48 | This is just a C-style
function with C-style character array.
| | 02:54 | The official recommendation is
that you use reverse DNS notation,
| | 02:59 | so something like com.lynda and then
something that would describe my app.
| | 03:03 | Let's say it's a Grand
Central Dispatch test app.
| | 03:06 | Then I hit Tab to the other parameter,
which isn't needed, and here I just put null.
| | 03:11 | And this is more of a C-style
function call than a Objective-C object.
| | 03:16 | The reason that we give it a label,
this com.lynda.gcdtest, is so that later on
| | 03:22 | if there are issues with the queues, it
will actually show up in instruments and
| | 03:26 | allow us to diagnose it.
| | 03:27 | So what am I going to do with this queue?
| | 03:30 | Well, currently on line 19 is
here where I make a call to that longRunningOperation.
| | 03:34 | This is what I'm going to do.
| | 03:36 | I just want to do this on another queue.
| | 03:39 | So here's how I do it.
dispatch_async, first parameter is myQueue.
| | 03:51 | The second parameter is the block.
| | 03:53 | This block can be small. It can be large.
| | 03:55 | It just needs to contain the code that
we want to execute on the other thread.
| | 04:00 | So I use the caret.
| | 04:02 | I'll do my opening, space, closing braces.
| | 04:06 | That's the block format.
| | 04:07 | And then inside this I can just put the
code I want to run, which is simply this call.
| | 04:13 | Cut that out, paste it in, and just
make sure that I'm putting a semicolon at
| | 04:19 | the end of the line. That's it.
We create the queue.
| | 04:23 | I'm just going to go ahead
and compile this and run it.
| | 04:27 | And it's as simple as that, to actually
start that operation running on another thread.
| | 04:31 | If you notice when I clicked the button, I
still have this response. It didn't hang.
| | 04:38 | However, one of the problems is we don't
actually see much of a response coming back.
| | 04:42 | My label is not being changed.
| | 04:44 | That's because the way I've
created it, we have one more issue.
| | 04:47 | And to tidy that one up, I
need to go back into my code.
| | 04:51 | The issue is back here.
| | 04:52 | We're calling this longRunningOperation
on that secondary queue, and that's fine.
| | 04:57 | But I've got to look at
what this operation is doing.
| | 05:00 | Well, first it's going to sleep for
five seconds, which is not a problem, and
| | 05:04 | then it's updating the
label on my user interface.
| | 05:07 | Well, that's the issue.
| | 05:08 | You're not meant to update user interface
elements from any other thread than the main one.
| | 05:14 | And it's not that you can't,
it's not that it's going to crash.
| | 05:17 | It's just not reliable, because you
don't have a lot of control about how
| | 05:21 | quickly things are updating to that main screen.
| | 05:24 | So this myLabel setText call really
needs to be executed back on the main thread.
| | 05:30 | And the question is, well, how do we do this?
| | 05:33 | Well, here's the great thing.
| | 05:34 | I can use dispatch_async within this call to
actually put this part back on the main queue.
| | 05:41 | So I'm just going to
type another dispatch_async.
| | 05:43 | Now, you might think, well,
what's the name of the main queue?
| | 05:50 | I don't technically know, but that's okay.
| | 05:52 | I could make another function call
called dispatch_get_main_queue, which itself
| | 05:58 | just takes another block.
| | 06:00 | We use the caret symbol,
opening and closing braces.
| | 06:04 | Let's just finish that statement off,
and then I could cut this. Let's break it
| | 06:10 | upon to a couple of different
lines and paste it in. Save, run.
| | 06:15 | And what should happen now is we can
mess around with this user interface.
| | 06:20 | I can click the button.
| | 06:21 | We immediately are still responsive.
| | 06:23 | It doesn't hang the UI, but in a
few seconds we get our result back.
| | 06:27 | I can do this multiple times.
| | 06:29 | We have a multithreaded
operation working just fine.
| | 06:33 | And this is how we can use Grand
Central Dispatch and blocks to very simply,
| | 06:38 | very easily turn our application from
using a single queue into multiple queues
| | 06:42 | without even saying the word
thread anywhere in our code.
| | 06:45 | So very simple stuff, but powerful stuff to do.
| | Collapse this transcript |
|
|
11. Saving DataUnderstanding the options for saving data on iOS| 00:00 | The applications we've created so
far will always begin in the same way.
| | 00:04 | We've never saved any information for
the next time the application loads after
| | 00:08 | the iPhone has restarted.
| | 00:10 | Now, some of the times this is okay.
| | 00:12 | If your application is simple, it can
load and unload repeatedly without there
| | 00:15 | ever being a problem with this, but
it's more likely that you will want to save
| | 00:19 | some data, to persist it to storage on
the iPhone so it can last when the device
| | 00:24 | itself is restarted.
| | 00:25 | Now, your first key question here
is what kind of data are you saving?
| | 00:30 | Option one: you might be just
saving a few simple values, some strings,
| | 00:35 | Booleans and arrays.
| | 00:36 | Now, a very easy way to save these is
you can save them to a property list file,
| | 00:40 | like the one used in earlier to load
data into a Table View. And these are
| | 00:45 | useful because many of the most
common objects, things like dictionaries,
| | 00:49 | strings, and arrays just have simple
methods to save their contents directly out
| | 00:54 | to a file and read them back in.
| | 00:56 | Now, option number 2, related to this
one, is if the data you want to save is
| | 01:00 | really just application settings,
meaning preferences for your app, well,
| | 01:05 | this is an odd one.
| | 01:06 | You see, the first suggestion is, don't.
Try to write an application that does
| | 01:11 | not have much in the way of settings.
| | 01:14 | Now, if you must, Apple has a very well-
defined set of rules for working with settings.
| | 01:19 | It's something called a Settings bundle,
which essentially means that you can
| | 01:22 | tell iOS what settings you want to
store and it can take care of saving that
| | 01:27 | data for your app and even
generating the interface for you.
| | 01:31 | But using this does mean that these
settings will be accessed through the
| | 01:34 | Settings application on
iOS, not your application.
| | 01:38 | So it does require that user exit out
of your application to do it and then go
| | 01:43 | over to the Settings app where
there'll be an entry for your program.
| | 01:46 | But in the last couple of years Apple
have moved from recommending this option
| | 01:49 | to recommending you don't, simply
because of the need to exit the app.
| | 01:54 | They don't quite say "don't ever use
this," but the Human Interface Guidelines
| | 01:58 | say to deemphasize settings in general
and using the Settings app in particular.
| | 02:03 | So if you have to, they suggest using
your own screen to handle application
| | 02:08 | settings, like having the flipside view
of the Stocks app or the flipside view of
| | 02:13 | the Weather application.
| | 02:14 | But what if it's more involved, if the
data in your application can't be easily
| | 02:19 | stored in something like a property list file?
| | 02:21 | Well, we have several other
solutions available in iOS for storing and
| | 02:25 | retrieving more complex content.
| | 02:27 | First off is the SQLite and Core Data
options, which are often talked about
| | 02:32 | together but are very different from each other.
| | 02:34 | Now first, SQLite as it might sound,
is a database. It's a lightweight SQL
| | 02:39 | database that's built into iOS, and we
can create and use simple tables inside it;
| | 02:45 | whereas, Core Data, now this is the most
substantial data storage mechanism on iOS.
| | 02:51 | Rather than thinking about databases or
flat files, it lets you take a complex
| | 02:56 | object graph, meaning all your objects
and all their data, all their references
| | 03:00 | to other objects, and just save the
whole thing, just freeze dry and place when
| | 03:06 | you need to or re-create it from storage.
| | 03:09 | Now, Core Data is fantastic and
I'm a huge fan, but it is notoriously
| | 03:13 | unfriendly for new iOS developers, and I
suggest you regard it as phase 2 of your iOS learning.
| | 03:19 | First get comfortable with the general
iOS development before you dive into it.
| | 03:23 | Even Apple's own Getting Started with
Core Data guide begins with the phrase
| | 03:28 | "Core Data is not an entry-level
technology." And with iOS 5 your apps now also
| | 03:34 | have the option to use the iCloud service.
| | 03:36 | If a user's device is signed into
iCloud we can detect that and we can use it.
| | 03:41 | So, instead of just saving locally on
the device itself, your app can save into
| | 03:46 | iCloud, store data there, and have
that data automatically synchronized with
| | 03:51 | other iOS 5 devices, and even with Macs and PCs.
| | 03:54 | Now, you as a developer don't have to
pay anything to Appe to use this; the
| | 03:58 | documents saved by your app are part
of that user's allocation in iCloud.
| | 04:02 | Now a full exploration of SQLite, Core
Data, or iCloud is way beyond the scope of
| | 04:08 | this essentials course.
| | 04:09 | Bill Weinman has a course here at
lynda.com on Building Data-Driven
| | 04:13 | Applications with iOS that uses SQLite,
and in 2012 watch the space for more on
| | 04:18 | Core Data and iCloud.
| | 04:20 | So, the next question has to be, if we're
saving simple data, where are we saving it to?
| | 04:25 | Now, iOS does have a file system,
although it's not quite what you're used to.
| | 04:30 | You just don't have free access to browse
the file system like you might do on a desktop.
| | 04:35 | Your application can only
access its little sandbox part of it.
| | 04:40 | Every application gets its own documents
folder as well as a library and a temp folder.
| | 04:45 | But it's controlled by iOS, and what
that means is the path to this document
| | 04:50 | library is taken care of
by the iOS operating system.
| | 04:54 | It's not obvious, and it's not up to you.
| | 04:56 | You have to ask iOS to tell you
what it is before you start to use it.
| | 05:01 | So, you can only read and write from
your own area, and other applications can
| | 05:05 | only read and write from theirs.
| | 05:06 | They can't touch yours.
| | 05:08 | There are a few notable exceptions,
such as reading from the built-in Address
| | 05:12 | Book, from the iPod library, or from
Calendar events, but pretty much you're
| | 05:17 | limited to just your own data.
| | 05:20 | Now, the next question, when do you save?
| | 05:23 | We'd like to think that our application
is special and the users will treat it
| | 05:27 | kindly, but the truth is that any
moment the user can hit the Home screen
| | 05:30 | button and your app is going to have to exit
immediately, they are not going to hit a Save button.
| | 05:37 | They're going to leave and you're going to
need to respond to that very, very quickly.
| | 05:41 | The perfect event when they
leave the app is an event called
| | 05:44 | applicationDidEnterBackground in the
App Delegate, and this will be called by
| | 05:49 | iOS when something is triggering your
application to leave and it has to leave immediately.
| | 05:54 | So your application goes into the
background and you've saved the data.
| | 05:58 | Well, when we open up the
application again, when do you load it?
| | 06:02 | If we're restoring from the
background, the perfect place would be
| | 06:06 | applicationWillEnterForeground to
do the reverse of anything you did in
| | 06:10 | applicationDidEnterBackground.
| | 06:13 | Now, neither of these will be the time and
place to pop up UI alert views and ask questions.
| | 06:18 | It's the time to get out, get out as
quickly as possible, or get back and running
| | 06:22 | as quickly as possible.
| | 06:23 | And with these things in mind, we can
go and see an example of saving data on
| | 06:28 | an iOS device.
| | Collapse this transcript |
| Saving and loading data from property list files| 00:00 | Here's the problem that we are going to solve.
| | 00:01 | We've got a very simple application
here with a Text Field and a Date Picker.
| | 00:06 | If I type in a value here, let's try First try,
| | 00:10 | I could spin the Date Picker.
| | 00:12 | I'll select a value that's pretty easy
and memorable, January the 1st, and then
| | 00:17 | we hit the Home button to exit out of
it. Go back in again, we'll see those
| | 00:21 | values, because when moving from a
foreground to a background state just regular
| | 00:26 | user interface elements
are taken care of by iOS.
| | 00:29 | However, if we exit and either
double-click the Home button and decide to
| | 00:34 | completely exit out of that
application, or I could also restart the
| | 00:39 | Simulator, which would be like
restarting the device, and then I open it up
| | 00:43 | again, we're back to blank.
| | 00:45 | We're back to square 1, because this
information is not being persisted in any way.
| | 00:49 | So we're going to save some data from
the user interface, so it can be created
| | 00:53 | even if the iPhone is restarted.
| | 00:56 | I've got a project here that I have
created some skeleton placeholders for, just
| | 01:00 | to break down what I have.
| | 01:02 | In the user interface all
that I have here is a Text Field,
| | 01:06 | there is a Date Picker, and there's
an invisible button behind to make the
| | 01:09 | Text Field go away.
| | 01:11 | In my header file, I have outlets
for the Text Field and the Date Picker.
| | 01:15 | I have one IBAction for dismissing the keyboard.
| | 01:19 | These aren't important.
| | 01:20 | But what I have done is defined
three methods that I am going to go and
| | 01:24 | provide the code for.
One to get a file path on the system;
| | 01:28 | two, to save some data;
| | 01:30 | and three, to load some data.
I haven't done anything with these yet.
| | 01:33 | So I am going to jump over into the
implementation file where I can see my
| | 01:37 | three methods up here.
| | 01:38 | This getFilePath that returns a string,
right now it's returning just an empty
| | 01:43 | string just so this would compile.
| | 01:45 | So I need to provide some code to provide a
path to this application's documents library.
| | 01:52 | Now this should be a really simple call
to iOS saying, give me my directory, but
| | 01:57 | it's a little longer than it strictly
needs to be because we are still dealing
| | 02:00 | with older-style Desktop Cocoa
functions rather than new iOS-only ones.
| | 02:05 | So I am first going to create an array,
and the call I am going to do is to
| | 02:13 | this rather long
NSSearchPathForDirectoriesInDomains, which takes a few
| | 02:18 | different arguments here.
| | 02:20 | I'll just type them first
before I talk about them.
| | 02:32 | I pass in this function, three parameters;
| | 02:35 | NSDocumentDirectory, which
means, yes, we are looking for the
| | 02:38 | document directory;
| | 02:39 | NSUserDomainMask, which is basically
saying, yes, it's really just me, the
| | 02:44 | current user;, and then I am using a Boolean,
YES here that says I want the full path.
| | 02:50 | I don't want any kind of relative path.
| | 02:52 | Now this is a regular C-style function call,
so it doesn't need to be in square brackets.
| | 02:58 | This will return me an NSArray object,
and what I am actually interested in is
| | 03:03 | whatever is in the first position there,
because it could theoretically return
| | 03:07 | me multiple paths, although I
only care about what's at position 0.
| | 03:17 | So I am going to have a return
statement against the path at position 0, which
| | 03:21 | will be our document directory, but I
want to also append a file name to it.
| | 03:26 | So what I am going to use is
stringByAppendingPathComponent, and then I'll just
| | 03:31 | make up a name for this file.
| | 03:34 | I'll call it saved.plist.
| | 03:37 | You can call it whatever you want.
Give myself a bit more room here, and
| | 03:42 | that method will now return the
current file path to this application's
| | 03:46 | saved property list file.
| | 03:48 | So how would we use it?
| | 03:49 | Well, here in the method called
saveData, I am actually going to write some
| | 03:53 | code to grab the values of the Text Field and
the Date Picker and just store them in that file.
| | 04:24 | So I create an array and
allocate it just with two things:
| | 04:28 | the value of the Text Field and the
date currently held in the Date Picker.
| | 04:32 | That's all I need to do.
| | 04:33 | So now I have an NSArray and it knows
how to save itself to a file, and I am
| | 04:38 | just going to say value, and I want to
call the writeToFile. Where is the file?
| | 04:43 | Well, we can call the getFilePath on
the current object, on self. And
| | 04:49 | atomically we are just putting in a Boolean
variable of YES. This should be pretty instant.
| | 04:54 | Now what if that file already existed?
| | 04:56 | Well, it doesn't matter;
| | 04:57 | it's just going to overwrite it.
| | 04:59 | So that's me saving the
state of this application.
| | 05:03 | Okay, it's very simple.
| | 05:04 | It's just two user interface elements, but
you could start saving whatever you wanted here.
| | 05:10 | And next, we've got the load method.
| | 05:12 | So what actually happens if this application
is loading and trying to read in these values?
| | 05:16 | Well, first, I better go and
get the actually file path,
| | 05:19 | so I'll create a string for this.
| | 05:39 | I am first going to use a little helper
method of the NSFileManager to say, does
| | 05:44 | anything exist at that path?
| | 05:49 | If so, then I can read it in and
fill the values on my user interface.
| | 05:54 | And I am basically going to do, in
reverse, what I did in the saveData.
| | 05:58 | Creating an NSArray and initialize this
with the contents of the file, which we
| | 06:11 | just retrieved a couple of lines before.
| | 06:14 | Then simply set the values of the
Text Field and the Date Picker to the
| | 06:19 | entries in that array.
| | 06:21 | I could use dot syntax like I am using here, or I
could have used the Objective-C square brackets. It doesn't matter.
| | 06:30 | Whatever is at position 0 goes into
the Text Field. Whatever is at position 1
| | 06:44 | goes into the Date Picker. But right now, of
course, none of these methods are being called.
| | 06:49 | Nobody is calling saveData.
Nobody is calling loadData.
| | 06:52 | There is nothing magical
about those method names.
| | 06:55 | So the first easy thing I want to say is,
if this application is loading from a
| | 06:59 | device restart or Simulator restart,
| | 07:02 | we're going to call loadData to ask if
that file exists, and if so, load the
| | 07:07 | contents of it into our user interface.
| | 07:09 | Now there is one easy place to put this,
but it's not going to fix all our problems.
| | 07:13 | I am going to put it here in viewDidLoad. It's just
going to be self and a call to load data. That will do it.
| | 07:20 | The thing is, viewDidLoad is only
called when the app is launched from scratch.
| | 07:26 | This is not called when the app moves
in the background to the foreground, and
| | 07:29 | if we were worried about that, we have
to be careful here, because we can't rely
| | 07:34 | on any of these view-based methods:
| | 07:37 | viewDidUnload, viewWillAppear,
viewDidAppear, viewWillDisappear,
| | 07:40 | viewDidDisappear. None of these will be
called when the background. Foreground
| | 07:44 | operations are happening.
| | 07:46 | You see, we are interested in
the application-level events.
| | 07:51 | We are interested particularly in
applicationDidEnterBackground and
| | 07:53 | applicationWillEnterForeground, but
these get called in the AppDelegate.m file,
| | 08:02 | not in your ViewController file.
| | 08:04 | Now there are ways that we can volunteer.
| | 08:07 | We can opt in our ViewController to
also respond to these events. But because
| | 08:13 | the saveData and loadData methods are
declared in our ViewController and the
| | 08:17 | AppDelegate created the ViewController
object in the first place, meaning that
| | 08:21 | it did it up here, as self.viewController,
| | 08:26 | I can actually call them directly here.
| | 08:28 | So in applicationDidEnterBackground,
I am going to say self.viewController
| | 08:33 | to access that one ViewController, and we
should have the accessible method, saveData.
| | 08:38 | applicationWillEnterForeground,
self.viewController loadData, save.
| | 08:47 | I am going to build this application,
Build Succeeded. I'll go ahead and run it.
| | 08:51 | Now before I actually test this, I
am just going to quit back into Xcode.
| | 08:57 | I've installed this application correctly.
| | 08:59 | The reason I just quit right back out
of it is when you are running directly
| | 09:02 | from Xcode and you decide to both leave
the app, go back in, terminate it, and
| | 09:07 | check a few things, Xcode
can get very confused indeed.
| | 09:11 | So I ran it once to install it on the
Simulator, and now I am just going to use
| | 09:15 | Spotlight to actually
access the Simulator directly.
| | 09:18 | So we're not currently in Debugging mode.
| | 09:20 | I am going to open up that application.
| | 09:23 | We're on Today. I'm going to go to
our Text Field here.
| | 09:27 | I am going to type something in: "Does this save?"
| | 09:32 | Change the wheel to an
earlier date, like January the 14th.
| | 09:35 | Now if I just exit out of it, go from
the foreground to the background, well,
| | 09:40 | this would working anyway.
| | 09:42 | The real key issue is can I exit the
application by double-clicking the Home,
| | 09:47 | clicking the Minus button?
| | 09:48 | And when this opens again,
it still has the data.
| | 09:52 | We're actually loading it in from that file.
| | 09:55 | I could even quit out of the
Simulator, then open it back up again.
| | 09:59 | It's like a restart the device. Click
the app and it's loading that information.
| | 10:07 | Technically speaking, this was
indeed even a little bit of overkill.
| | 10:11 | If all we were doing is trying
to recreate a user interface,
| | 10:14 | it pretty much does a good job of that anyway.
| | 10:17 | But this would be one basic approach
for a simple ability to persist data to a
| | 10:23 | file on the iOS device.
| | 10:25 | Testing foreground and background events
in the Simulator and using Xcode can be
| | 10:30 | a little tedious, and it's definitely
one place where some patience and some
| | 10:33 | NSLog statements can come in very useful indeed.
| | Collapse this transcript |
|
|
12. iPad DevelopmentUnderstanding iPad development| 00:00 | So what's different when
developing for the iPad?
| | 00:02 | Well, first off, not a lot.
| | 00:04 | We still use all the same
techniques we have been using so far:
| | 00:08 | view Controllers, delegate,
storyboards, actions, outlets.
| | 00:11 | We still work with the idea of one
application at a time that takes up the full screen.
| | 00:15 | Everything we've done so far
will work on the iPad just fine.
| | 00:19 | The little alteration we would need to do
is mainly just awareness of screen size.
| | 00:23 | So this screen size, this resolution,
which is 1024 x 768, or 768 x 1024 depending
| | 00:30 | on which way you are holding it.
| | 00:31 | Now if you can call any screen
resolution a classic, then this is one.
| | 00:35 | Now as you have seen, all the Xcode
project templates allow you to choose iPad
| | 00:40 | and they then create an iPad-
size View Controller for you to use,
| | 00:43 | though some of these projects
types that you are familiar with them on
| | 00:47 | the iPhone, like master detail app and
utility app, are implemented slightly differently.
| | 00:51 | The utility app on an iPhone, for
example, does the horizontal flip back and
| | 00:55 | forth, and this just
wouldn't work on the iPad screen.
| | 00:58 | So on iPad, it uses a new interface
element called a popover to show the flip
| | 01:03 | view, but everything else is the same.
| | 01:05 | We will see that in a moment.
| | 01:07 | So the technique changes in a few
places because we have these new user
| | 01:11 | interface elements like popovers and
Split View Controllers, which aren't
| | 01:15 | available on the iPhone.
| | 01:17 | But what if you don't
want to develop for the iPad?
| | 01:20 | Well, of course you don't have to.
| | 01:22 | If you have a simple iPhone application
that's not been specifically changed to
| | 01:26 | deal with the iPad, it will still run
on the iPad but in compatibility mode.
| | 01:31 | I'm going to shift to my hardware menu in
the Simulator here and change this to the iPad.
| | 01:36 | And I will open up the iPad at 50%
view here, just because I don't have a lot of real estate room.
| | 01:41 | I am going to go back to the
application and open it up.
| | 01:44 | This is an iPhone application, and
you have probably seen this before when
| | 01:48 | you can actually run the iPhone app
either in the same native resolution as
| | 01:52 | the iPhone, or by tapping the 2x button to
double the size of it on the larger screen.
| | 01:58 | But there are a few issues here.
| | 01:59 | First, it doesn't actually take up all
of the iPad screen because the aspect
| | 02:03 | ratio is different
between the iPhone and the iPad.
| | 02:06 | Secondly, it's technically usable, but if
you're just doubling the pixels of your
| | 02:11 | application, you could get a
blocky look that's undesirable. But more
| | 02:15 | importantly, classic iPhone application
models like navigation-based apps and
| | 02:20 | utility apps are usable but kind of clunky.
| | 02:24 | They just aren't taking advantage of
the space that we have available in
| | 02:27 | the way that we would if we had an
application specifically designed for
| | 02:30 | this larger screen size.
| | 02:32 | An another issue is that when someone
with an iPad is browsing in the App Store,
| | 02:36 | they will see iPhone only apps in a
different de-prioritized section than iPad
| | 02:42 | apps or apps that we work
on both iPhone and iPad.
| | 02:45 | So compatibility mode is not iPad support.
| | 02:48 | It's the lack of iPad support.
| | 02:50 | That's what happens when you do nothing.
| | 02:52 | So your choices are, you can create
two totally different applications--
| | 02:56 | one for the iPhone, another project for
the iPad--and there will be two different
| | 03:01 | entries in the App Store, or you
can create a universal application.
| | 03:05 | This is one choice in your project
creation, and it will mean one entry in
| | 03:09 | the App Store, but it will count as a
fully fledged iPad application because it
| | 03:13 | will adjust itself according to the
device it's running on, using different NIB
| | 03:18 | files for each different screen.
| | 03:19 | Now one very important piece you
should know is that unlike with the iPhone,
| | 03:23 | Apple do recommend on the iPad
that all orientations are supported,
| | 03:28 | and that your user should be able to use
your application holding it any way they want.
| | 03:32 | Now sure, some applications might only
realistically work in just portrait or
| | 03:36 | just landscape mode, but if
possible, you should support both modes.
| | 03:41 | The difference is that while you're able
to do that on an iPhone, it's not required.
| | 03:45 | It's just a nice-to-have.
| | 03:46 | On the iPad it is
recommended that that's how you do it.
| | 03:50 | So as the user interface for the iPad
is what contains the most significant
| | 03:54 | changes that things we will naturally
encounter the first few times we try to
| | 03:58 | do iPad development, we're going
to cover a couple of those next.
| | Collapse this transcript |
| Using iPad-specific UI elements| 00:00 | In the first hour of using an iPad
you'll have come across most, if not all, of
| | 00:05 | the different user
interface elements from the iPhone.
| | 00:07 | And because it's an Apple device, you
probably didn't think about them that much;
| | 00:11 | they just seemed natural.
| | 00:12 | But while you or users in that role
don't have to care, as developers we need to
| | 00:17 | make sure we know what these different
elements are in each circumstance so we
| | 00:20 | can use the right one.
| | 00:22 | Now the most significant new user
interface idea is the split view, typically
| | 00:27 | used when you have nested data or
some kind of master-detail relationship.
| | 00:31 | So if you were in the Settings app on
the iPhone, you get used to go in left to
| | 00:36 | right through multiple screens.
Same thing with the Mail application.
| | 00:38 | But here it's all on the same screen.
| | 00:41 | You select from the list on the left
and the area on the right, the Detail page,
| | 00:45 | changes to handle your
selection, and it's very common.
| | 00:49 | You'll see this in a lot
of applications on the iPad.
| | 00:51 | You'll see it in Mail.
| | 00:53 | You'll even see things like the Notes
application uses this. Though it's been
| | 00:58 | given a customized view;
it's still the same idea.
| | 01:00 | That's very common for the split
view to change when you switch between
| | 01:04 | Landscape and Portrait mode, switching
from the dual-pane view to a single pane
| | 01:10 | showing only the detail.
| | 01:11 | Same thing happens with the Notes application.
| | 01:14 | Now the difference is in this case we
actually technically lose some data,
| | 01:18 | some part of the screen.
| | 01:19 | The area that allows us to select a new
note has disappeared, but we can get it
| | 01:23 | back with the popover, and that's the term
for this new floating element that you will
| | 01:28 | find very common in a lot of
different iPad-based applications.
| | 01:31 | Now it sometimes feels like a menu,
as it's often initiated from tapping a
| | 01:35 | button on a toolbar.
| | 01:37 | But this popover can appear
from a few different places.
| | 01:40 | It doesn't have to come from the top.
| | 01:42 | It can come from somewhere in the middle or
lower on the bottom like when using a map.
| | 01:46 | Now the classic model here is that you
won't find a button to dismiss a popover.
| | 01:52 | The idea is you're either going to
select something on this popover or you'll
| | 01:56 | just tap somewhere else on
the screen to dismiss it.
| | 01:59 | And now as we have more screen space,
we can also design view controllers and
| | 02:04 | make them appear modally, so that
when we're choosing options, say, from the
| | 02:08 | toolbar, we can have screens within
our app that will dim the background and
| | 02:12 | require us to focus and perform
an action before they go away.
| | 02:16 | In many applications
you'll have a variety of these.
| | 02:20 | Modal views have a few different presentation
styles to take part of, or all of, the screen.
| | 02:25 | But even going through the Settings
application to configure an email account
| | 02:29 | will have using split views, and modal
views, pop-up keyboards for text entry, and
| | 02:34 | all of these can be configured
in your own iPad applications.
| | 02:37 | They're not very different from
creating iPhone apps, but there are a few
| | 02:41 | gotchas to be aware of as we
begin to write code to use these.
| | 02:45 | So we're going to cover a couple
of the classic new UI elements.
| | Collapse this transcript |
| Creating iPad apps with popovers| 00:00 | Let's go ahead and create
an application for the iPad.
| | 00:03 | I'm not going to make a single view
application here because that really
| | 00:07 | would be kind of boring.
| | 00:08 | It just is a big iPhone app.
| | 00:10 | There's nothing remarkable, nothing
different about it except for a bigger view.
| | 00:14 | I am going to go ahead and make a
utility application, which is a little
| | 00:18 | different on the iPad than on the iPhone.
| | 00:21 | I am going to make sure to select
the iPad Device Family and keep on
| | 00:28 | Automatic Reference Counting.
| | 00:30 | Now, the reason I'm doing this is
not to make a utility app as such;
| | 00:34 | it's to demonstrate popovers.
| | 00:36 | Though because it's a useful comparison,
I will be contrasting some of the things
| | 00:41 | we see here to the iPhone utility app
we deconstructed earlier in the course.
| | 00:45 | I am going to click over here and
take a look at my MainViewController.xib.
| | 00:49 | Now, one of the downsides here is
because I'm recording on a small screen size,
| | 00:55 | it's difficult for me to
see the entire iPhone screen.
| | 00:58 | If I was using storyboards, I could
zoom out, although that isn't always
| | 01:02 | reliable for actually interacting with the view.
| | 01:04 | But we have a MainViewController.xib.
| | 01:08 | We have a FlipsideViewController.xib,
and this one just looks like an iPhone
| | 01:12 | screen, and we'll see why.
| | 01:14 | They do call it a
FlipsideViewController, which is the same as the iPhone
| | 01:18 | version of this project, even
though we won't actually animate a flip.
| | 01:22 | Let me show you what happens when we
just go ahead and run this application.
| | 01:26 | So it opens up in my iPad Simulator,
which I am at 50% here, and whereas on
| | 01:32 | the iPhone version we'd expect to see a
little tiny little button at the lower-right,
| | 01:36 | that could get lost in a big iPad
application, so instead we're using the bar up
| | 01:41 | at the top that has an Info button.
| | 01:43 | I hit that, and instead of flipping,
which would be a bit intrusive, we just
| | 01:47 | have a popover, this thing with the
drop shadow and the surround on it and a
| | 01:53 | little arrow that points to the button.
| | 01:54 | So let's see how they're doing this.
| | 01:55 | I am going to quit out of
this and go back into Xcode.
| | 01:58 | Looking at the MainViewController.xib,
right up at the top here, we can see I've
| | 02:03 | got a bar on the top, and this is
not a simulated user interface element;
| | 02:07 | it really is a real one,
with a Bar Button item on that.
| | 02:12 | And if I open that up, I'll make sure
to select the Bar Button item itself, and
| | 02:17 | sometimes it's beneficial
to use the expanded dock here.
| | 02:22 | I can see that in my Connections Inspector
| | 02:25 | it's hooked up to File's Owner and the
showInfo method, which is exactly the
| | 02:29 | same as it was on the
iPhone version of this project.
| | 02:32 | So let's take a look at some of this.
| | 02:34 | I am going to jump into the
header file for my MainViewController.
| | 02:39 | This is the first time I actually
see a little bit of a difference.
| | 02:42 | So this MainViewController class is
going to be responsible for creating and
| | 02:47 | showing the
FlipsideViewController and even making it go away.
| | 02:51 | So on line 13 here, I have a property
that's going to hold a reference to it,
| | 02:55 | but instead of holding it directly,
it's actually going to create a container,
| | 03:00 | something called a
UIPopoverController, and that's what's going to be
| | 03:04 | responsible for adding the surround
and generating the drop shadow and so on.
| | 03:08 | So in the implementation file for
MainViewController, I am going to find
| | 03:13 | the showInfo method.
| | 03:15 | We have a little bit more code
here, but it's not all that complex.
| | 03:19 | We're first asking, does this object even exist?
| | 03:23 | If it doesn't, we're going to allocate
and instantiate a new instance of the
| | 03:28 | FlipsideViewController from our
FlipsideViewController NIB file,
| | 03:32 | set its delegates to self, meaning
MainViewController. This is the same as
| | 03:37 | in the iPhone version.
| | 03:39 | However, what is a little different is
we're going to instantiate then a new
| | 03:43 | UIPopoverController and load in that
FlipsideViewController we just created.
| | 03:49 | So rather than show the
FlipsideViewController directly, we create a
| | 03:53 | PopoverController and load the
FlipsideViewController into it.
| | 03:56 | On line 77, we ask is the popover visible?
| | 04:00 | If it is, we dismiss it;
| | 04:02 | if it isn't, we're going to show it. And we call
| | 04:04 | presentPopoverFromBarButtonItem:
permittedArrowDirections: animated.
| | 04:11 | Animated you can guess;
present Popover you can guess;
| | 04:15 | permittedArrowDirections helps iOS
generate an arrow from the popover to
| | 04:21 | the button that caused it to appear, without
us worrying about exactly what that looks like.
| | 04:25 | Let me show you what that means.
| | 04:29 | I open the Simulator.
| | 04:30 | I am quickly just going to zoom in from my
window scale to 100%, just so we can see this.
| | 04:36 | I tap the Bar Button item and
it makes the popover appear.
| | 04:40 | I can see I've got this drop shadow that
surrounds the popover, and I've also got
| | 04:44 | an arrow on the right-hand side of the
popover pointing to this info button.
| | 04:49 | Now, that does not mean that
popovers always do an arrow on the right.
| | 04:52 | They don't have to.
| | 04:53 | If I quit out of this, then I can just
very quickly--and this is just to show
| | 04:58 | you as an example--jump into my xib
file for the MainViewController, drag this
| | 05:04 | Bar Button item to the left-
hand side, and run it again.
| | 05:08 | We'll see that in this case it's
actually smart enough to generate the arrow
| | 05:12 | on the left-hand side.
| | 05:13 | That's the benefit of
using this PopoverController.
| | 05:17 | It can do all this for you.
| | 05:19 | I am going to quit out of
that and go back to the code.
| | 05:22 | That's all we need there to show the popover.
| | 05:25 | Above this showInfo method is the
flipsideViewControllerDidFinish method that
| | 05:29 | just has one line of code to
dismiss the PopoverController.
| | 05:33 | This is using exactly the same delegation
technique as the iPhone version of this project.
| | 05:39 | The FlipsideViewController will ask
us, the main screen, to dismiss it; it
| | 05:43 | doesn't dismiss itself.
| | 05:44 | Now, the only other thing worth
mentioning is actually in the initializer for
| | 05:49 | the FlipsideViewController.
| | 05:51 | Because this is a popover, it
could potentially be a different size;
| | 05:55 | it doesn't have to be the
same size as the iPhone screen.
| | 05:58 | That is a pretty classic size, the
320x480, but if I decided in this code to say
| | 06:03 | this was going to be 680, for
example, save that and run it,
| | 06:08 | that's all we'd need to do to
make the popover a different size.
| | 06:14 | Notice also that if I touch on a blank
area of the application, a non-popover
| | 06:19 | area, it's still going to
take care of dismissing itself.
| | 06:22 | We didn't have to write
any code to make that happen.
| | 06:25 | So as you can see, the same process, the
same approach, yes, an awareness of the
| | 06:31 | size of the views and an awareness of a
couple of small techniques, and this is
| | 06:35 | one way to build an iPad version.
| | Collapse this transcript |
| Creating iPad apps with split views| 00:00 | The Split View Controller is unique to the iPad.
| | 00:03 | It's what allows us the use things like
the Settings application and have this
| | 00:06 | split view with the two panes, like
you'd see in the Settings app or in the Mail
| | 00:11 | application on an iPad.
| | 00:13 | On the left-hand side you have the
master area. You select an entry and you see
| | 00:18 | more about your selection on the
right-hand side. It's the detail.
| | 00:24 | And it's something that
changes based on the orientation.
| | 00:28 | In Landscape mode you see the split
view, but if you switch to Portrait mode,
| | 00:33 | the default technique is that the master
becomes hidden and all you see is the detail.
| | 00:38 | The master becomes available as a pop-over.
| | 00:42 | If you see this kind of arrangement on
a desktop application, you might expect
| | 00:46 | to be able to shift the divider to the
left or right and adjust the width of the
| | 00:49 | panes, but no, not here.
| | 00:52 | The left pane of a Split View
Controller is fixed at 320 pixels wide and the
| | 00:57 | detail pane on the right takes whatever is left.
| | 01:00 | Now although a split view generally
changes when rotated to portrait, there are
| | 01:04 | a couple of applications that don't do
that. The Settings application is exactly a
| | 01:08 | good example of this one.
| | 01:10 | When this one shifts to portrait,
it stays with the split view.
| | 01:13 | But we're going to create an application and
go with the shifting behavior, for two reasons.
| | 01:18 | One, it is a good model, and it works
really well, and two, a lot of the work is done first if we do.
| | 01:24 | I'm going to go ahead into Xcode and
make a master-detail application, making
| | 01:29 | sure that I choose to do this as an
iPad app. So iPad from the Device Family.
| | 01:35 | I'll just call it MasterDetail
and as ever, save it to my desktop.
| | 01:42 | First off, this project
does not look that remarkable.
| | 01:46 | I can see that over on the left-hand
side I have a MasterViewController and a
| | 01:50 | DetailViewController.
| | 01:52 | I can view the NIB files for that.
| | 01:57 | MasterViewController appears to have a
table view that doesn't look all that
| | 02:01 | remarkable and the
DetailViewController, that's pretty simple too.
| | 02:05 | What I don't see over here is any
signs of a Split View Controller.
| | 02:10 | I don't see it in either of the interface files.
| | 02:13 | I don't see it referred to as a code file.
| | 02:15 | And that's because I
really don't need to see it.
| | 02:17 | The Split View Controller is kind of dumb.
| | 02:20 | It doesn't look like anything.
| | 02:22 | This is a controller that
has no visual appearance.
| | 02:25 | It's just a container that can hold two
real view controllers that provide the
| | 02:30 | actual visible content.
| | 02:32 | So the great thing is, our focus is
still what it's always been, on our own view
| | 02:37 | controllers, on our own application content.
| | 02:40 | We create a Master View
Controller that represents the left pane,
| | 02:44 | we create a Detail View Controller that
represents the right, and we just load
| | 02:48 | them into the slots on
that Split View Controller.
| | 02:50 | It takes care of
transitions and managing the rest.
| | 02:54 | But it can go further than this, because
as you've probably noticed, panes in a
| | 02:58 | split view can actually switch
between multiple view controllers.
| | 03:03 | If you're using the Settings
application, for example, the Detail pane often
| | 03:07 | shifts from left to right.
| | 03:09 | It looks like it's got a
navigation controller at the top.
| | 03:13 | If you're using the Mail application,
you'll find it's the left-hand side that
| | 03:16 | shifts between different
inboxes and different folders.
| | 03:19 | And just from looking at these, they
kind of look like navigation controllers at
| | 03:24 | the top keeping track of a navigation stack.
| | 03:26 | And that's exactly what they are; each
pane can have its own navigation stack.
| | 03:31 | So a classic layout would be create
the Split View Controller, our container.
| | 03:36 | Then create a Navigation Controller.
| | 03:39 | Load our first Master View Controller
into it, then make a second Navigation
| | 03:44 | Controller, load our Detail pane into it.
| | 03:48 | Then slide the first Nav Controller
into the left-hand side and the second Nav
| | 03:53 | Controller into the right-hand side.
| | 03:55 | And that's exactly what's
happening in this example project.
| | 04:00 | If I run this application from Xcode
without making any changes to it, we start
| | 04:04 | up in Portrait mode just showing the
detail view, but it looks like we have a
| | 04:08 | navigation bar at the top.
| | 04:09 | I can hit this button to bring up the pop-over.
| | 04:12 | But this master actually does contain a
navigation controller, and it can shift
| | 04:16 | itself back and forth.
| | 04:18 | That may or may not be what you want.
| | 04:21 | Shifting into Landscape mode, we go
to Detail View, and they both have the
| | 04:26 | navigation bars at the top.
| | 04:27 | They're not being used in any substantial
way in this project, but they're supported.
| | 04:32 | The ability is there.
| | 04:33 | Let's see exactly how.
| | 04:35 | Well, in our application, we have the
MasterViewController class files, the
| | 04:41 | MasterViewController.nib, the
DetailViewController class files, the
| | 04:45 | DetailViewController.nib.
| | 04:46 | And it's all going to come
down to the AppDelegate code.
| | 04:50 | So when our application
launches, here's what we do.
| | 04:54 | Line 25, which obviously is split
across two lines here, create an instance of
| | 04:59 | the MasterViewController.
| | 05:01 | No big surprises there.
| | 05:03 | Line 26, we'll create a
navigation controller and load the Master
| | 05:07 | View Controller into it.
| | 05:09 | Line 28, we create the DetailViewController.
| | 05:12 | Line 29, we create its
navigation controller and load the
| | 05:16 | DetailViewController into it.
| | 05:18 | On line 31, that's where we
instantiate the SplitViewController, and on line
| | 05:23 | 33 is where we load it with the
masterNavigationController on the left and
| | 05:28 | the detailNavigationController on the right,
obviously bringing along our view controllers.
| | 05:33 | Then we load that into the
window and make it visible.
| | 05:37 | And while the MasterViewController code
still drives a lot of the things, bear
| | 05:41 | in mind it's the Detail View
that's actually always being shown.
| | 05:45 | But because it's the
DetailViewController, that's always shown regardless of
| | 05:49 | what position it's in.
| | 05:51 | Here is where you'll find some code,
at the bottom of DetailViewController.m,
| | 05:55 | for both hiding and showing
the masterViewController when the
| | 05:59 | splitViewController shifts position.
| | 06:02 | We have a method here that's
going to automatically be called,
| | 06:05 | splitViewController
willHideViewController, withBarButtonItem,
| | 06:10 | forPopoverController.
| | 06:12 | That's where in Portrait mode we'll
actually create the barButtonItem at the top-
| | 06:16 | left that in this case just says
Master and control loading that master view
| | 06:21 | into a pop-over controller.
| | 06:23 | The flipside of that, below here,
when it's going to show the Master View
| | 06:27 | Controller, we'll take the
barButtonItem off, and we'll detach the
| | 06:31 | masterViewController from being a
popover because it's going back into Landscape
| | 06:35 | mode where it actually shows up in Split View.
| | 06:37 | But once this is all up and running,
once it's loaded, using the Master and
| | 06:43 | Detail View Controllers is the
same as with their non-iPad versions.
| | 06:48 | We can pass information between them.
| | 06:51 | They can talk to their own navigation
controller to control transitions, push
| | 06:55 | and pop other view controllers off the stack.
| | 06:58 | Even the DetailViewController class
file is created exactly the same as in the
| | 07:02 | iPhone version, just creating a generic
detailItem property that will allow us
| | 07:07 | to load custom objects in here just to
prove that it works and that they all
| | 07:10 | connect to each other.
| | 07:11 | So while creating these applications is
a little more involved than basic iPhone
| | 07:15 | apps, the principles and techniques
for using them is exactly the same.
| | Collapse this transcript |
|
|
13. Finishing touchesCreating an application launch image| 00:00 | You know that cool zooming effect you
get when you launch an iOS application,
| | 00:04 | where there is that split second
where we seem to be zooming in on the
| | 00:09 | application's first screen?
| | 00:10 | Well, this zoom is a lie.
| | 00:13 | We are not looking at our app's first
view controller or any view controller
| | 00:18 | of the application.
| | 00:19 | It might look like that, but all it is
is there is an image being provided by
| | 00:24 | our application, so that while iOS is
actually loading the real app, they can do
| | 00:30 | a nice animated zoom of what
your app is supposed to look like.
| | 00:34 | Now, you may have noticed this when you
have been working with these projects in Xcode.
| | 00:38 | If I create, say, a Master-Detail
Application--I will just call this one,
| | 00:43 | ImageTest, make sure that it's for
iPhone, just because that's going to be
| | 00:47 | easier to look at while I'm recording this--
| | 00:51 | we can run it and install it in the
Simulator, and all the functionality is
| | 00:55 | fine, but we won't get that animated zoom.
| | 00:58 | Now I will have to hit the Home button
and go out and try it again to see that,
| | 01:02 | but all we will get is black.
| | 01:04 | We can see a little bit of a zoomed
status bar, but that's it, as opposed to, say,
| | 01:12 | the Settings application where we get
the blank page; or Contacts, where we get
| | 01:16 | the blank page; or Game Center,
where we get the green background.
| | 01:21 | So what do we need to do to
get that cool zoom effect?
| | 01:24 | Well, we need to provide a launch
image the size of the iPhone screen.
| | 01:28 | These are required before you can
submit your app to the App Store, and you need
| | 01:33 | to provide two if you're making an iPhone app.
| | 01:36 | One is for a regular iPhone and one is
for a retina display, and two images for
| | 01:41 | an iPad app, but there it's one for
the landscape and one for portrait.
| | 01:44 | Now some applications use this
opportunity to show a splash image in that short
| | 01:50 | time between the application being
requested and it actually opening up.
| | 01:55 | This is actually discouraged by Apple;
| | 01:57 | you are not supposed to do it that way.
| | 01:59 | Your application's launch image is
supposed to look like your first screen
| | 02:03 | without any data or text, and that's
what you'll see on most of the Apple ones.
| | 02:08 | Now one of the reasons for this is
so you could localize your app into
| | 02:13 | multiple languages and you wouldn't
have a mismatch by having a launch image
| | 02:17 | with only, say, English on it.
| | 02:19 | So what would be the best
way to make one of these?
| | 02:22 | What we want really is this first page
of the application without any data on
| | 02:28 | it, without any text, without
any entries in the TableView.
| | 02:31 | I could recreate this in Photoshop or
Fireworks, but that would be a little
| | 02:35 | tedious, because I can get a head start.
| | 02:38 | While I am looking at the app in the
Simulator, I am going to go to the File
| | 02:40 | menu and I have got an
option for saving a screen shot.
| | 02:44 | That's going to give me an image of the
right size and the right type, a PNG file.
[00:0249.33]
I am going to quit out of the
Simulator and just minimize Xcode, and on the
| | 02:53 | Desktop here, I have the
iOS Simulator Screen Shot.
| | 02:57 | So I would like to make a little change to this.
| | 02:59 | You could use Photoshop, Fireworks,
whatever image editor you have. I am just
| | 03:03 | going to open up in Pixelmator, and I
am just going to do something very basic
| | 03:08 | in a few seconds here.
| | 03:09 | I want to blank out the text that we have,
| | 03:12 | so I am going to go low-tech and just drag in.
| | 03:16 | Yes, I will continue.
| | 03:17 | I don't mind editing the original image here.
Just drag in a white rectangle to overlay that.
| | 03:24 | I could go ahead and clear off the
Status bar and also the Nav bar here, but
| | 03:29 | this will do the trick, just to prove our point.
| | 03:32 | So I am going to save that, quit
out of Pixelmator, back into Xcode.
| | 03:37 | What I need to do is make sure
that in my Project Navigator
| | 03:40 | I have the project itself selected, the
very top icon, not any of the individual
| | 03:46 | files, but this needs to be highlighted.
| | 03:48 | And then making sure that in the
middle section, I have got my ImageTest, my
| | 03:52 | project target highlighted,
| | 03:54 | if I expand this a little bit,
| | 03:57 | in the Project Settings that we have, we have
an area where we can drag on the launch image.
| | 04:03 | For an iPhone app, you will see
one for regular iPhone, giving you the
| | 04:07 | dimensions, one for the Retina Display,
and it won't let you drag on something
| | 04:11 | of substantially wrong dimensions here.
| | 04:14 | If you are working with an iPad, you
would see a portrait and landscape version.
| | 04:18 | I am just going to open up a Finder
window and jump back to the desktop, and I
| | 04:23 | can grab that PNG and drag it over here
into the regular iPhone section. And we
| | 04:29 | can see a little preview of that.
| | 04:31 | It also moves it into my
project, under the name Default.png.
| | 04:36 | So let's go back and run this. Build succeeded.
| | 04:39 | We open up the Simulator. We load it in.
| | 04:41 | Of course, we don't see it the first
time around, but if I reopen it, we can see
| | 04:46 | that we have the zoom. In fact, the
good indicator here is it almost looks
| | 04:50 | like the words are just flicking on
after the app loads, and that is the
| | 04:58 | approach for doing it.
| | 04:59 | Now the iPhone and iPhone Retina
Display are supposed to be full size,
| | 05:04 | either 480x320 or 960x640.
| | 05:09 | I had used a regular iPhone example.
| | 05:12 | What I could also do is switch in
the Simulator in my hardware to the
| | 05:17 | iPhone(Retina) Display--and important
here to make sure I am at 100% Scale, even
| | 05:22 | though for me that's a little difficult to manage.
| | 05:27 | Then I could open this up and take
another screen shot for the Retina Display
| | 05:32 | and repeat the process there.
| | 05:34 | I am not going to actually do that
right now, but you see how that would work.
| | 05:38 | For the iPhone in Retina Display,
they're supposed to be the full size.
| | 05:41 | They should include the status bar.
Whereas with the iPad launch images, you are
| | 05:46 | not supposed to include the status bar.
| | 05:48 | We actually shave 20 pixels off
for both portrait and landscape.
| | 05:53 | And simply if I went ahead and
actually changed that second image that I had
| | 05:58 | captured, I can see this one
by highlighting at 640x960.
| | 06:03 | I could just drag that one
on to the Retina Display size.
| | 06:06 | Of course, I haven't edited it yet, but
you get the idea. And this is you having
| | 06:11 | the required launch images for your application.
| | Collapse this transcript |
| Creating an application icon| 00:00 | As you all have noticed, when
you're testing your applications they add
| | 00:04 | themselves to the iPhone home screen
with this generic white icon, with a bit of
| | 00:09 | a rounded corner, a bit of a shine to it.
| | 00:11 | But you'll need to provide your own
icons in order to publish you app to the
| | 00:15 | App Store or even just to have
something different from the white ones.
| | 00:18 | So let's see how to do this.
| | 00:20 | Now an iPhone app needs two
application icons, very similar to working
| | 00:24 | with launch images.
| | 00:25 | You need one for regular
display and one for retina display.
| | 00:29 | Simply put, we need to create two
square PNG files one, that's 57 pixels wide by
| | 00:35 | 57 pixels high and another
that's double that, 114 x 114.
| | 00:39 | And you can use any image editor to do this.
| | 00:44 | Now if you are developing an iPad app,
that needs one icon that's kind of in
| | 00:48 | the middle, 72 x 72.
| | 00:49 | At the moment of recording this, we
don't have retina displays on the iPad.
| | 00:54 | I'm sure that's coming, at which
point it will be double that size.
| | 00:58 | Now you might be wondering about the
fact that most of the icons you see on the
| | 01:03 | iPhone home screen have a shine to them,
and they have rounded corners to them.
| | 01:07 | And if you're questioning your
Photoshop skills about doing this, it's not a
| | 01:11 | problem, because we don't do that.
| | 01:14 | iOS does this for us.
| | 01:16 | We create our icon perfectly square,
without the rounded corners, without the shine.
| | 01:21 | For the purposes of saving time, I have
two very simple icons on my desktop here.
| | 01:26 | You can get them from the exercise files,
or you can just make ones yourself.
| | 01:30 | I have called one regular icon. It's 57 x 57.
| | 01:33 | It's about as simple as it gets. And then I
have got a retina icon that's 114 x 114.
| | 01:39 | There's no shine to them.
| | 01:41 | There is no rounded corners.
| | 01:43 | They are perfectly flat.
| | 01:45 | If I was going to open this up in an
image editor, you would see something
| | 01:48 | very, very basic indeed.
| | 01:50 | And all I need to do is find the
application that I want this to work for. Of
| | 01:54 | course in my case this needs to
be an iPhone application here.
| | 01:57 | We need to be on our Project Settings,
and with the target selected in the
| | 02:01 | Summary section, I will find the two
places to drop the app icons, for the
| | 02:06 | regular one and for retina display.
| | 02:08 | So switching back to my icons, I'll
grab Regular, drop it in there. It will
| | 02:14 | tell you if they are the wrong size or the
wrong type, and drag that one and drop it there.
| | 02:19 | As I can see, they were
added to my project as well.
| | 02:23 | Let's run this example.
| | 02:24 | This is just a regular single view application.
| | 02:27 | It's actually opened up on the retina
display iPhone just because I had that
| | 02:32 | selected in my device.
| | 02:34 | Of course, I don't see it in the
application itself, but if I exit out of that,
| | 02:39 | I certainly do. And I can
scale in to 100% and see that
| | 02:45 | it's done quite a nice job of adding
the rounded corners and the shine on the
| | 02:49 | slight gradient to this.
| | 02:51 | If I switch my hardware to the Regular
iPhone, the non-Retina one, we get that
| | 03:00 | example. So very, very simple to do.
| | 03:03 | Now application launch images and
application icons are not just nice additions.
| | 03:08 | These are required for you to
put your app on the App Store.
| | 03:12 | Not only that, but there are
several other images you can provide.
| | 03:16 | If you look at the iOS Human Interface
Guidelines, there is a section for Custom
| | 03:21 | icon and Image Creation Guidelines
| | 03:24 | that not only will give you a good
reference on the exact size that these things
| | 03:28 | have to be, but you'll also get other
ones you can create, like small icons for
| | 03:32 | when documents in your application
show up in a Spotlight search or document
| | 03:36 | icons, what size they should be,
the specifications exactly for them.
| | 03:41 | So take a look at the Human
Interface Guidelines for more on the optional
| | 03:44 | icons as well.
| | Collapse this transcript |
|
|
ConclusionGoodbye| 00:00 | In the past few hours you've seen a lot
of different subjects in iOS development.
| | 00:04 | We've worked with Objective-C.
| | 00:05 | We've explored the tools.
| | 00:07 | You've seen patterns like MVC, Delegation.
| | 00:10 | We've used table views and navigation
controllers, pop-overs and split views.
| | 00:14 | We've organized our apps with
storyboards, and we've worked with saving data,
| | 00:18 | multithreading, block,s
and Grand Central Dispatch.
| | 00:21 | And the question is, well, what now?
| | 00:24 | This was just the basics, so
where do you go from here?
| | 00:27 | And I think it's a great time to re-
inspect and revisit the iOS Developer Center
| | 00:32 | and the enormous amount of content
that is available here, if you can find it.
| | 00:37 | Because it's easy to think of this site
as this is reference, this is where you
| | 00:40 | get your class reference documents,
but it's a lot more than that.
| | 00:44 | Now, the first two documents, I think
it's essential for every iOS developer to
| | 00:47 | know very well, the iOS Application
Programming Guide and the iOS Human
| | 00:53 | Interface Guidelines, or HIG, and these
are usually found on the front page.
| | 00:58 | The Application Programming
Guide really is the core information.
| | 01:02 | If you're unsure about aspects of
things like app states and multitasking or
| | 01:07 | the main run loop, these are all contained here.
| | 01:10 | We've already seen the
Human Interface Guidelines.
| | 01:13 | The Development Guide is different
from the Application Programming Guide.
| | 01:16 | This is a great document too, and it's
the one that you need for getting more
| | 01:20 | into things like setting up
development devices or publishing an app for user
| | 01:24 | testing, and eventually
publishing to the App Store.
| | 01:26 | Now, if you go to this Developer
site and just head straight to the iOS
| | 01:30 | Developer Library--all of the
documentation--you're going to find an immense
| | 01:35 | amount of content here.
| | 01:36 | There are hundreds of documents,
thousands of pages you can potentially read.
| | 01:40 | But the most valuable one for recent iOS
developers is this section called Guides.
| | 01:46 | If you click Guides on the left,
you'll find there's about 150 of them here.
| | 01:50 | I'm filtering on Guides.
| | 01:51 | I'm going to sort by topic, because
you'll find that there is a bunch of guides
| | 01:56 | split into the General section, and
then you have guides specifically on, say,
| | 02:00 | audio and video, Multimedia Programming Guide.
| | 02:03 | If we move down, we have things
on data management, working with
| | 02:06 | strings, working with text.
| | 02:08 | Moving further down, we'll get into
things like graphics and animation, the Core
| | 02:12 | Animation Cookbooks, mathematical computation.
| | 02:17 | And as I continue into Security,
then Tools & Languages, more documents
| | 02:22 | about Xcode itself, Keyboard
Shortcuts and Gestures, Xcode Glossary, tools
| | 02:27 | that we have in there.
| | 02:29 | If you want to geek out on the
internals of things like the LLVM Compiler,
| | 02:33 | you'll find that stuff here. And also,
User Experience areas, working with
| | 02:39 | View Controllers, working with Table Views,
and of course the Human Interface Guidelines.
| | 02:45 | And these guides are provided as both
web-based and you'll typically find a PDF
| | 02:49 | link as well, although do be aware
that they are updated on a regular basis.
| | 02:54 | Going back into the Developer Library,
you'll also find that under this there
| | 02:58 | will be a Sample Code section.
| | 03:00 | Right now it looks like there's
another 150 or so sample projects.
| | 03:04 | Some of them, if I order by Date, can
be a few years old, so they won't be
| | 03:09 | necessarily using the up-to-date
best practices and APIs, but they are
| | 03:13 | updated fairly regularly.
| | 03:15 | You can scan through them.
| | 03:16 | You can find a bit of information about what
each one is, how to create an Image Picker UI.
| | 03:23 | Or TopSongs here demonstrates importing
data from an RSS feed into a core data store.
| | 03:28 | Let's find this one here,
SimpleDrillDown using a Table View and a Storyboard,
| | 03:34 | and that was updated a couple of
months ago to use ARC and storyboards.
| | 03:38 | Grabbing this as an example, you can
actually browse all the code straight on
| | 03:42 | the web, or you can click the button
above it to download sample code, which
| | 03:46 | will give you a ZIP file.
| | 03:47 | I'll just open that up, double-click
the Xcode project file, and we can open up
| | 03:55 | and start to take a look at it.
| | 03:59 | It's opened up a project I already had
previously, so let's switch to it and
| | 04:03 | make sure we're looking at SimpleDrillDown.
| | 04:08 | Sometimes it's good to just go ahead
and run these and you can get a good idea
| | 04:13 | of what this application is doing and
decide for yourself whether you want to
| | 04:17 | look further into the code or not.
| | 04:19 | So I'm going to go back into the web site.
| | 04:22 | And of course, if you know for sure
that there is something particular that
| | 04:26 | you're interested in, you want to
explore, say, working with the MapKit or working
| | 04:30 | with Locations, or Push Notifications,
or Core Data, then you'll find there's a
| | 04:34 | great deal of content here to get started with.
| | 04:37 | And that's it for this first course.
| | 04:39 | Thanks for joining me for
iOS SDK Essential Training!
| | 04:42 | Make sure to take a look at some of
the other courses here at lynda.com that
| | 04:46 | we'll have on different
aspects of iOS development.
| | 04:49 | See you next time!
| | Collapse this transcript |
|
|