IntroductionWelcome| 00:04 | Hi, this is Simon Allardice, and
welcome to Cocoa Essential Training.
| | 00:07 | In this course, we're going to build
applications that run on Mac OS X.
| | 00:12 | That's what Cocoa development is all about.
And to do this, we're going to use Xcode, the
| | 00:16 | development environment for creating,
testing, debugging, and managing Mac apps.
| | 00:21 | You'll see a lot of Objective-C, the main
programming language used to create these apps.
| | 00:25 | And Cocoa development has a long history,
so we're going to explore the common
| | 00:30 | conventions and guidelines of programming Mac
applications that have grown over the years,
| | 00:34 | concepts like Delegation and Model view
Controller and how they're used in Cocoa.
| | 00:39 | We'll also talk about what's new and
up to the minute in Cocoa development now,
| | 00:43 | Sandboxing, Gatekeeper, and more.
| | 00:46 | And if those terms mean nothing to you now,
that's fine, they will by the time we're done.
| | 00:50 | And we'll go over the process of
developing a Macintosh application, see what
| | 00:54 | can and should be done with a user
interface, talk about testing, debugging, and
| | 00:58 | even publishing your app to the Mac App Store.
So let's get started.
| | Collapse this transcript |
| What you need to know| 00:00 | For this course, I don't expect you to
have done any Mac programming at all, but
| | 00:04 | I do expect that you're comfortable
programming in an object-oriented language
| | 00:09 | and that you know at least
the basics of Objective-C.
| | 00:12 | You don't need to be an expert in it,
but you certainly need to know how to
| | 00:15 | instantiate objects, call methods, write
classes, and so on. And if you're coming
| | 00:20 | from a language like Java or C# or
Ruby and you haven't done anything with
| | 00:24 | Objective-C yet, I would caution you
not to underestimate the differences.
| | 00:28 | It's common to find Objective-C
quite a strange language at first.
| | 00:32 | So I do suggest you go through at least
the first few chapters of the Objective-C
| | 00:36 | Essential Training course here at lynda.com,
then come back to this course so we
| | 00:41 | can focus here on the Cocoa side of things,
| | 00:43 | what's unique about developing
applications for OS X instead of spending
| | 00:48 | our time talking about what the square brackets
mean and why BOOL is written in uppercase.
| | 00:53 | Another reason I expect basic Objective-C
knowledge here is that I imagine some
| | 00:57 | of you that are watching this course are
coming to Cocoa development after doing iOS
| | 01:01 | development with Objective-C,
| | 01:03 | as that's becoming a very common entry
point for developing in the Apple world.
| | 01:07 | Now iOS development is, of course, based on
Cocoa, and they share many ideas and techniques.
| | 01:14 | But if you aren't coming from iOS, as
you'll see, there're some key differences in
| | 01:17 | how we approach things here,
| | 01:19 | though you will encounter a few ideas in
this course that'll make you realize why
| | 01:24 | certain things are done the way they are in iOS.
| | 01:27 | So if you know iOS development,
that's great. But if not, no problem.
| | 01:31 | And if you're coming from another
developer platform, the experience you have in Java
| | 01:36 | or Dot Net or Ruby on Rails is very
valuable, but try to leave some of that
| | 01:42 | behind for a few hours.
Things are different here.
| | 01:45 | Cocoa development has a very long
history, and we have customs and ways of doing
| | 01:50 | things that are unlike other platforms,
and not just in syntax, but really in core
| | 01:55 | concepts--even things like when we
might use inheritance. And if you try and
| | 02:00 | force everything in Cocoa into an exact
equivalent of something you're used to
| | 02:04 | in Java or C# or PHP, it's just not going
to work, and you're likely to find this
| | 02:10 | very painful and frustrating.
| | 02:12 | So forget about your favorite
platform for a while, just bring your core
| | 02:16 | programming skills and some
Objective-C, and let's get going.
| | 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
| | 00:04 | a DVD, you will have
access to some exercise files.
| | 00:07 | I have expanded them here on my
Desktop just in this Exercise Files folder.
| | 00:11 | And inside that each of the relevant
chapters has its own folder, and there're
| | 00:14 | some files I'll be working with
during this course, and we'll point out any
| | 00:18 | files at the relevant time just by
showing you the path to the file location.
| | 00:22 | You'll also find some finished examples
if you want to compare and contrast what
| | 00:27 | you have done with what I have done.
| | 00:29 | But these are all just for convenience.
If you don't have access to the exercise
| | 00:33 | files, you can follow along from
scratch or with your own assets.
| | Collapse this transcript |
|
|
1. Getting StartedInstalling the tools| 00:00 | If you already know you have Xcode 4.4 or
later installed, you can skip this step.
| | 00:05 | But if not, let's make sure
we have got the right tools.
| | 00:08 | So first things first.
| | 00:10 | What do you actually need to
make Mac OS X applications?
| | 00:13 | Well, not surprisingly, you need a Mac,
the development tools aren't cross-platform.
| | 00:18 | So you have to have a Mac and needs to
be Intel-based, and it should contain at
| | 00:22 | least a Core 2 Duo chip.
| | 00:24 | This is nothing to do with Xcode and
our tools. That's actually required to run
| | 00:29 | Lion OS 10.7 or Mountain Lion 10.8.
| | 00:32 | And your Mac should be running
one of these Operating Systems.
| | 00:36 | Well, you can download Xcode for
earlier versions like Snow Leopard it doesn't
| | 00:41 | include some of features we'd
like to use in this course like ARC.
| | 00:44 | I'll be using both 10.7 and 10.8 as my
Operating System in this course and talk
| | 00:50 | about the differences between the two a
little later. But having the latest OS
| | 00:54 | is highly recommended if you're going
to be developing Mac apps because I can
| | 00:59 | create apps using 10.8 that will run
just fine on 10.6, but I can't create apps
| | 01:05 | using 10.6 that would use the features in 10.8.
| | 01:07 | Now let's say you have just borrowed a
Macintosh to start developing, and you
| | 01:12 | don't know for sure what it's running.
| | 01:14 | Well if you check the Apple menu on
the top left and click About This Mac,
| | 01:18 | this will give you the version of the
Operating System that we're using, in
| | 01:22 | this case 10.7.4, which is fine, it's
Lion. And it's also telling me that this
| | 01:27 | processor is an Intel Core 2 Duo which is
expected as I wouldn't able to install Lion if it wasn't.
| | 01:33 | So as far as our requirements go we're
ready, but we need to have the tools, the
| | 01:38 | development environment Xcode. Which
comes bundled with a bunch of other useful
| | 01:42 | programs for development.
You get this from Apple, and it's free.
| | 01:45 | If you have Lion or later as your
Operating System, you just go to the App
| | 01:50 | Store and get it there.
| | 01:52 | The Category in the App Store you're
interested in is the Developer Tools
| | 01:56 | category, and Xcode should be extremely obvious.
| | 01:59 | This one download is the best part all
two gigabytes, and that's so big because
| | 02:03 | it's not just Xcode, it's Xcode plus a
whole bunch of other programs, tools, and
| | 02:09 | supporting files, like
iPhone and iPad simulators.
| | 02:12 | The SDK is the Software
Development Kits for both OS X and iOS.
| | 02:17 | So it's everything you need for
creating iPhone and iPad apps and Mac Desktop
| | 02:22 | apps, it's all there.
| | 02:23 | Some of the stuff in this download,
you won't need, and you will never care
| | 02:27 | about, but it's all bundled together.
| | 02:28 | And if you don't want to get it from
the App Store, alternatively you can also
| | 02:33 | download a .dmg image from
the developer.apple.com site.
| | 02:38 | So this is our foundation for building
both iOS and Mac Desktop applications.
| | 02:44 | And once you have installed it, it is also pretty
useful to have a shortcut to that on your Dock.
| | 02:52 | The final test, of course is, can you
actually open it? And either from the Welcome
| | 02:57 | screen or from the about Xcode pane,
you want to see at least Version 4.4.
| | 03:02 | Almost everything we do in this course
would work with Version 4.3, and even 4.2,
| | 03:07 | but you don't want to go any earlier than that.
| | 03:10 | Apple do release updates to their
Developer tools frequently--usually every few
| | 03:15 | months. So you could well have a later
version than I have, and that's fine, I'm
| | 03:19 | a big believer in always having the
latest version. Though you may see some
| | 03:23 | small differences if you do
have a later version than mine.
| | 03:26 | Part of being an Apple developer is
really rolling with these frequent
| | 03:30 | incremental changes to the Developer tools.
| | Collapse this transcript |
| About the Apple Developer Programs| 00:00 | If you haven't already signed up with
Apple as a registered Apple developer, you
| | 00:04 | should really do that before you go
much further. And this will give you access
| | 00:08 | to documentation, sample code, videos,
and other useful stuff, and it's free.
| | 00:13 | And to do this, point a web
browser at developer.apple.com.
| | 00:18 | This page will really give you three
links that take you to the main developer
| | 00:22 | centers for Apple, which is the iOS Dev Center,
the Mac Dev Center, and the Safari Dev Center.
| | 00:28 | We're interested, in this
course, in the Mac Dev Center.
| | 00:32 | If you have registered, you can just go
ahead and Log In, but if you haven't yet
| | 00:36 | there is a Register link at the top
right. And this will tell you a little
| | 00:40 | bit of information about what you
need to do to Register as an Apple
| | 00:44 | Developer and what you can get.
| | 00:45 | Once you have gone to this link and
filled out all the information, you can come
| | 00:49 | back and login to the Mac Dev Center itself.
| | 00:51 | And for now, this is the place that
you need that has the most current
| | 00:55 | documentation, it has sample code,
and it will be very useful to make sure
| | 00:58 | we have the most up-to-date help information.
| | 01:01 | So signing up as a Registered Apple
Developer is free, but there are a couple of
| | 01:05 | restrictions to know about.
| | 01:07 | If you're just a Registered Apple
Developer you can't yet publish your apps
| | 01:11 | to the Mac App Store. And if you want
to do that, you'll need to join the Mac
| | 01:15 | Developer Program--and that's one step
up from being just a Registered Apple
| | 01:19 | Developer--and it does cost money.
| | 01:21 | Back on that Registration page, towards
the bottom, there's a link that tells you
| | 01:26 | more about the Developer Programs. Now
you don't need to be in the Mac Developer
| | 01:30 | Program for this course,
but you should know about it.
| | 01:33 | The two Paint Developer Programs that
Apple has are, the iOS Developer Program for
| | 01:38 | iPhone and iPad, and the Mac Developer
Program, and you need to join this to
| | 01:43 | release apps in the Mac Desktop App Store.
| | 01:45 | There's a couple of ways to join, but
at the moment--in the US--it's $99 for a
| | 01:50 | year, 60 pounds in the UK, and so on.
| | 01:52 | Now you don't get new software after
joining, it's the same Xcode. Although
| | 01:57 | joining the Developer Program will
often give you access to some beta releases
| | 02:01 | of new versions of Xcode.
| | 02:03 | But after joining you will be able to
take your finished applications and sell
| | 02:07 | them on the Mac App Store.
| | 02:08 | Now, also with the release of Mountain
Lion, which contains the security feature
| | 02:12 | called Gatekeeper. Apple are pushing the
idea that all applications, whether sold
| | 02:18 | on the Mac App Store or elsewhere,
should be digitally signed with the developer ID
| | 02:22 | And you can get that if you're in
the Mac Developer Program. We will talk
| | 02:27 | about that part later.
| | 02:28 | Do be aware that if you haven't
joined the Developer Program, and you are
| | 02:32 | holding off until the last possible
minute to spend the $99, know that the
| | 02:36 | process is not immediate, you can't just pay
your $99 and then instantly submit to the app store.
| | 02:42 | Some information needs to be verified,
and you may have to wait a couple of days
| | 02:47 | after you begin this process
before everything gets turned on.
| | Collapse this transcript |
| Creating your first Cocoa app| 00:00 | We're going to jump right into Xcode
to create a simple Mac application, after
| | 00:05 | which we'll jump right back out again
to explain several of the pieces we're
| | 00:08 | going to see in the next couple minutes.
| | 00:10 | So I'll open up Xcode, and either from
this Welcome screen or from the menu I
| | 00:14 | want to Create a new Xcode project.
| | 00:17 | Right now, just think, Project equals
Application. Whenever you want to make an
| | 00:21 | App, you're going to make a Project in
Xcode, it's just a way of keeping all the
| | 00:26 | relevant files together.
| | 00:27 | Next I'm presented with a list of
templates for this Project, and it seems
| | 00:31 | like we have a lot of choices here.
Because Xcode can, of course, be used for
| | 00:35 | developing iPhone and iPad
Applications, System Level plug-ins, Background
| | 00:39 | Task Programs, Reusable Collections
of Classes--known as Frameworks--and of
| | 00:44 | course, for developing applications
for Mac OS X Desktop, which is what we're
| | 00:48 | interested in here.
| | 00:49 | We have two main sections on the
left of this window, one for creating iOS
| | 00:54 | apps, and one for the Mac OS X apps.
| | 00:57 | If you have done any iOS development
you'll know that when creating a Project in
| | 01:01 | Xcode you need to make a choice
between several different kinds of Xcode
| | 01:05 | Project, like a Master-Detail Application, or a
Tabbed Application, or Page-Based Application.
| | 01:10 | Well that might be the case
for iOS but that's not the case for Cocoa.
| | 01:15 | We really have one choice,
one option for our Project type.
| | 01:19 | So if I select the Applications section
under OS X, this is what I am interested
| | 01:25 | in, Cocoa Application.
| | 01:26 | This is the Project Template we
will use for everything in this course.
| | 01:30 | There're other options but
they're not really relevant here.
| | 01:34 | We can of course create Command-Line
Applications without a User Interface.
| | 01:38 | Underneath here, we have options for
different kinds of Frameworks and
| | 01:42 | Applications and System plug-ins.
| | 01:44 | But everything we'll do in this course uses
the Cocoa Application in the OS X Applications section.
| | 01:51 | So with that selected I click Next,
there're a lot of options on this next
| | 01:55 | window but only a couple are important now.
| | 01:58 | We have to provide a Product Name for
our Application. What's this App called?
| | 02:03 | What's this Project?
| | 02:04 | You can write whatever you want, but
by convention don't use spaces and
| | 02:07 | capitalize each word.
| | 02:09 | I could do something simple like say,
Demo or Example, but it is our first Cocoa
| | 02:15 | App of the course, so let's use HelloWorld.
| | 02:20 | Organization Name here doesn't have to
be your name or your organization name
| | 02:25 | this is just going to be inserted into
comments in your code, it's not all that important.
| | 02:30 | And right now the Company
Identifier isn't hugely important either.
| | 02:36 | This is because when creating a real
App you intend to sell, the product name
| | 02:40 | won't necessarily be enough to
guarantee it's unique in the App Store.
| | 02:44 | So this Company Identifier is a name
that can be unique for your organization
| | 02:49 | even if that's just you.
| | 02:51 | By convention it's usually your Domain
Name in reverse, so I might say com.lynda.
| | 02:58 | And as I type this it's combining the
Product Name and the Company Identifier
| | 03:03 | into what's called a,
unique Bundle Identifier, here.
| | 03:07 | That really should be completely unique if I
ever wanted to move this into the App Store.
| | 03:11 | But don't worry too much about
Company Identifier right now, we're just
| | 03:15 | making simple examples.
| | 03:18 | I'm going to leave Class Prefix alone
here. What ever letters you would type
| | 03:22 | here Xcode would automatically put at
the start of any class and class files
| | 03:26 | you make in this Project.
| | 03:27 | Now App Store Category is exactly
what it sounds like, giving you a list of
| | 03:32 | options for the App Store. I'm
going to leave that at None, we could
| | 03:36 | always change that later.
| | 03:37 | Below this we have a few
check boxes for extra features.
| | 03:41 | Now these are all great options to have,
but most of them would add complexity to
| | 03:47 | our simple HelloWorld Project and
one of them removes complexity from it.
| | 03:51 | So I want to make sure that Create
Document-Based Application is unchecked--
| | 03:56 | we'll see that later--and also
that Use Core Data is unchecked.
| | 04:01 | Core Data is Apple's own persistence
Framework, which means it deals with saving
| | 04:06 | then later retrieving the internal
state of our Application, but we certainly
| | 04:11 | don't need it in this App, and we
won't be using Core Data in this course.
| | 04:15 | Core Data is fantastic, but it
deserves a course all by itself.
| | 04:20 | And unchecked Unit Tests, all
these things are terrific later.
| | 04:24 | Right now, they're getting in the way.
| | 04:26 | The one that I'm going to have checked
is ARC, Use Automatic Reference Counting.
| | 04:33 | Now depending on when you learned your
Objective-C, you might not have used ARC.
| | 04:37 | As it is a new feature provided in late
2011, we'll talk a little bit more about
| | 04:42 | it later, but it makes Memory
Management easier, and we will have ARC checked
| | 04:47 | for every single Project in this course.
| | 04:50 | I'll click Next, next it's going to ask me
where I want to save the Project files.
| | 04:55 | You can put this stuff anywhere you
want, there is no magic location for storing
| | 05:00 | your Projects from Xcode.
I'm just going to save them onto my Desktop.
| | 05:04 | Now Xcode understands both git and
subversion for Source Control and well I'm a
| | 05:09 | huge fan of Source Control, it would get
in the way here so I'll be leaving this
| | 05:13 | unchecked and just click Create.
| | 05:16 | We now have A Mac Project and
Xcode is going to create files for us.
| | 05:21 | Over here on the left-hand side, we have
what's called the Project Navigator, a
| | 05:25 | view of the different files in our Project.
| | 05:28 | I can single click around the files
here and they will open in the middle
| | 05:31 | section in the Editor.
| | 05:33 | If I click a file that represents code,
I'll get a Code Editor, and I have a couple
| | 05:37 | here, AppDelegate.h and AppDelegate.M.
Of course, this being Objective-C,
| | 05:42 | we're used to seeing our class files in pairs.
| | 05:45 | If I click a file that represents a
User Interface, I'll get a User Interface
| | 05:50 | Editor instead of the Code Editor, what's
called the Interface Builder Part of Xcode.
| | 05:54 | What I'm actually seeing first here
is representation of the menu system
| | 05:59 | for this Application, this will appear in
the real menu bar when we run this program.
| | 06:05 | However, when I think other User
Interface I want more than a Menu.
| | 06:08 | So if I look in the left-hand section
of the Interface Builder--what's called
| | 06:13 | the Dock--I see a few things. Now
this Dock can actually be expanded and
| | 06:17 | contracted doesn't really matter
which view you're looking at.
| | 06:21 | But I can see that by hovering over--
right now I have got the Main Menu highlighted.
| | 06:25 | Below, I have something called Window,
and if I click that we see
| | 06:29 | what we might imagine as the Window,
the main Window of this Application which
| | 06:33 | will appear when we run.
| | 06:34 | Now like many other programming IDEs,
Xcode lets me write code, test code,
| | 06:39 | design interfaces, all in the same
application. Unlike many IDEs, it lets me
| | 06:44 | drag and drop User Interface Elements.
| | 06:47 | In Xcode the place to find them is in
the Object Library, which I currently have
| | 06:52 | visible over here on the right, if I
can't see this right-hand panel, I'd need
| | 06:56 | to click this button on the
top menu here to make it visible.
| | 07:00 | I'm going to just to drag this up a
little bit so I can see more of it, and then
| | 07:04 | moving through this I want to find
Label. I'm just going to drag the Label
| | 07:08 | over here and let go.
| | 07:10 | With the Label here on my window, I'm going
to double-click it, and just say Hello World.
| | 07:16 | Clicking off to deselect it, I could
grab it, start to rearrange it, put it just
| | 07:21 | somewhere in the middle of this window.
| | 07:23 | I'm then going to go up to the top
menu bar and click the Run button.
| | 07:28 | And Xcode is going to compile--or
build--and then run our Application.
| | 07:35 | I'm just going to minimize Xcode behind
it so we can see this a little clearer.
| | 07:39 | What we'll get is our Application,
which I can drag around the screen here, we
| | 07:42 | get the Menu at the top here with HelloWorld.
| | 07:46 | I can actually select from several
all of the Menus and see that they have
| | 07:50 | pretty classic Macintosh style options
like Print, which actually seems to have
| | 07:56 | some functionality here.
We have got the classic File menu,
| | 08:00 | if go over to Help, I can see that
even have Help menu with the Search Box
| | 08:04 | and HelloWorld Help.
| | 08:06 | Clicking that will tell me well, right
now, Help isn't available for HelloWorld.
| | 08:10 | well that makes sense, I click OK.
| | 08:12 | I can even go back to the HelloWorld
menu itself and click the About option, and
| | 08:18 | I can see this is being built by some
people and designed by some other people
| | 08:22 | and Testing Hopefully not
nobody, special thanks to Mom.
| | 08:26 | Okay, well that aside, it does seem
that right out of the box, we're not
| | 08:30 | starting with a blank slate.
| | 08:32 | We have some functionality here, we have
this window, we have the menu system, we have
| | 08:36 | some kind of print functionality, and
it's great that we have these, but it's
| | 08:40 | important to realize.
| | 08:41 | When we create a Cocoa Application
it's not, here's a blank code file start
| | 08:46 | typing Objective-C. We actually have a
basic App that we're going to build on top of.
| | 08:52 | So we need to understand what we have
already got before we start adding anything else.
| | 08:56 | So I'm going to quit this Application,
just the normal way, and return to Xcode.
| | 09:01 | So looking at this first Cocoa
application in Xcode you're probably starting to
| | 09:06 | think of a whole bunch of questions.
What are these code files and what do they represent?
| | 09:10 | What does this MainMenu.xib represent?
What is xib? what are the
| | 09:17 | different parts of this User
Interface view? If you have moused over things,
| | 09:20 | you'll see First Responder, Application,
File's Owner, all sorts of cryptic names.
| | 09:26 | How would we hook a button up?
| | 09:28 | Which menu options are going to
already work, and which ones don't?
| | 09:31 | Well we're going to get all of this, but
the first piece of understanding Cocoa
| | 09:36 | development is. What exactly is Cocoa anyway?
| | Collapse this transcript |
| What is Cocoa?| 00:00 | Cocoa is a term that could be used
informally or formally, and it has a few
| | 00:04 | different meanings worth exploring here.
| | 00:07 | Informally, I can just say Cocoa
Development as a generic phrase that means
| | 00:11 | developing applications for Mac
OS X, and everything that entails.
| | 00:16 | The world of creating apps that run on
the Mac, the tools, the language, the
| | 00:20 | available libraries and frameworks,
the runtime, the ideas we use when doing
| | 00:25 | this, just everything.
| | 00:27 | Now, what we call Cocoa began in the
late 1980s with NeXTSTEP, the operating
| | 00:33 | system created at NeXT
Computing when Steve Jobs left Apple.
| | 00:37 | And when he rejoined Apple in the mid-90s,
NeXTSTEP was used as the basis for
| | 00:42 | Mac OS X, and a lot of the classes, the
libraries, the ideas we use in Cocoa now,
| | 00:48 | come from those original NeXTSTEP
days, which is why the letters NS still
| | 00:54 | permeate so much of what we do
in Cocoa 25 years after NeXTSTEP.
| | 00:59 | Now, Apple's own official
documentation sometimes use the word Cocoa for both
| | 01:05 | Mac OS 10 development, and iPhone and
iPad development. Although they often use
| | 01:10 | the term Cocoa Touch to refer to the
specific area of developing apps for iOS.
| | 01:16 | But if I am talking to someone at a
conference and they tell me they're a Cocoa
| | 01:20 | developer, I assume they build apps for the Mac.
| | 01:23 | I have never actually had anyone
introduced themselves as a Cocoa Touch developer.
| | 01:27 | They're much more likely to just
say they're an iOS developer instead.
| | 01:30 | So that's the kind of
informal use of the word Cocoa.
| | 01:34 | Now, Cocoa is technically not the only
option for developing Mac apps, but it is
| | 01:39 | the recommended way.
| | 01:41 | You might also occasionally hear the term
Carbon used when talking about Mac development.
| | 01:46 | Carbon was a set of APIs provided by
Apple to allow Mac OS 8 and OS 9 apps
| | 01:52 | to run on OS X. It's only 32-bit, has
been fading for years, most of Carbon
| | 01:58 | is officially deprecated in Mountain
Lion. And it's not something you should
| | 02:02 | be looking at, unless you have to
officially support or migrate much older
| | 02:06 | legacy Mac applications.
| | 02:08 | Now, Objective-C is the language
we use for creating Cocoa apps.
| | 02:13 | There are projects like MacRuby,
RubyCocoa, and pi Object-C that make it
| | 02:19 | technically possible to use Ruby or
Python to write these Cocoa applications,
| | 02:24 | but we're not going to use those here.
| | 02:26 | And even though I am very fond of both
Ruby and Python, I don't really recommend
| | 02:30 | using them for Cocoa.
| | 02:31 | Cocoa is built on Objective-C, this
is not an arbitrary choice, and picking
| | 02:36 | another language does not remove
Objective-C from the picture, it simply puts
| | 02:40 | another layer between you and Objective-C,
which you'd have to learn anyway.
| | 02:44 | If you are a Cocoa developer,
you know Objective-C, end of story.
| | 02:49 | Now, as soon as you start using
Objective-C as a language--even for simple
| | 02:55 | command line apps without a user
interface--you're going to be using the
| | 02:59 | Foundation Framework, a collection
of basic useful classes, things like
| | 03:04 | NSString, NSDate, NSArray.
| | 03:07 | Over a 100 classes are written and
compiled together into the Foundation
| | 03:12 | Framework, and you can't practically
right an Objective-C program without
| | 03:17 | linking to this Foundation Framework.
| | 03:20 | In the simplest of Xcode projects,
like this command line tool, if I look at
| | 03:26 | Frameworks, we're already linking to
it, and we can have all the different
| | 03:30 | headers of those classes that
exist in that Foundation Framework.
| | 03:34 | But great as the Foundation
Framework is, it isn't enough for us now.
| | 03:38 | We need classes that represent user
interface elements, like windows and buttons
| | 03:43 | and menus and fonts and cursors.
| | 03:45 | We also need functionality that can
control what's different about a visual
| | 03:49 | application over a command line application.
| | 03:52 | When we write a command line app,
it should just run through as fast as
| | 03:56 | possible and finish.
| | 03:57 | But with a visual application, we need
it to stay running, and to continually
| | 04:01 | respond to being moved or minimized or
clicked on, to continually respond to
| | 04:06 | events, until we explicitly quit the app.
What's referred to as the event loop.
| | 04:11 | Well, I don't want to have to write all
that code myself, and of course, I don't
| | 04:16 | have to. Apple has already written
that functionality--classes dealing with
| | 04:20 | alerts and buttons and fonts and menus
and the application idea itself--and it
| | 04:25 | has compiled these
together into another framework.
| | 04:28 | And that framework is
called Application Kit, or AppKit.
| | 04:32 | Now, there is an equivalent framework
for iOS development containing the iOS
| | 04:37 | versions of these classes, and that's
called UIKit, but every Cocoa application
| | 04:42 | will use at least
Foundation and AppKit frameworks.
| | 04:46 | Now, there are many other frameworks
available to us when developing Cocoa
| | 04:51 | apps, but all the other frameworks are
optional choices, you use them if you need them.
| | 04:55 | There are frameworks for working with
audio or video, talking to Bluetooth or
| | 05:00 | USB for security or networking, or
working with QuickTime. And we'll see a few
| | 05:05 | of them in this course, but we will
always need Foundation and AppKit in Cocoa.
| | 05:11 | Now interestingly, there's a
difference between what Cocoa is officially and
| | 05:17 | what Cocoa is technically.
Here is Apple's official documentation.
| | 05:22 | They formally state that for OS X
development you need, quote, "Foundation and AppKit
| | 05:27 | frameworks, all other
frameworks are secondary and elective."
| | 05:31 | But it's interesting to see that what
they say and what they actually do is a
| | 05:36 | little different, because technically
in Xcode when you make a Cocoa project,
| | 05:40 | you get three existing frameworks--
not just two--and let me show you that.
| | 05:46 | A moment ago I showed that in a typical
out of the box command line application,
| | 05:50 | that is with no UI, not a Cocoa application,
we link to one framework, the Foundation Framework.
| | 05:57 | Well, in a typical right out of the box
Cocoa application--like the HelloWorld
| | 06:01 | one I just created--we also
link to one framework called Cocoa.
| | 06:07 | Well, okay, what is that?
Well, it's not really anything,
| | 06:10 | it contains no classes, no actual code.
| | 06:13 | If I expand the header file, what I see
is one thing, Cocoa.h. I click that, I
| | 06:20 | find that all we're doing is
linking to three other frameworks:
| | 06:25 | Foundation, AppKit, and CoreData.
| | 06:30 | Even if you don't need it, even if I
unselected CoreData as a check box when I
| | 06:34 | made this Cocoa project, it's there.
| | 06:37 | Apple consider CoreData to be a very
important framework--and I agree it is
| | 06:42 | important--but important is not the same
as necessary, which is why CoreData for
| | 06:47 | us will be a separate course, but we
will always be using Foundation and AppKit.
| | 06:53 | So Cocoa has an official definition, it
has a technical meaning, but when I use
| | 06:58 | the word Cocoa in this course, I am
going to use it the informal way most
| | 07:03 | developers refer to it.
The world of creating apps for Mac OS X.
| | Collapse this transcript |
|
|
2. Core Cocoa SkillsIntroduction to Xcode| 00:00 | If you have been using Xcode for a while,
you might find this movie a bit of a
| | 00:03 | do over, and you are welcome to skip it.
| | 00:05 | But if you are fairly new to Apple
development, or it has been a while since you
| | 00:08 | have used Xcode, I am going to take
a couple of minutes to go over it.
| | 00:12 | We will spend most of our time here.
| | 00:14 | Xcode is an IDE--an Integrated
Development Environment--like Visual Studio, or
| | 00:20 | Eclipse, or Aptana, and this just
means it does more than one thing.
| | 00:23 | You write your code in Xcode, you
design your interfaces here, you compile
| | 00:27 | your applications here, you use it to test and
debug, to browse documentation, to find help.
| | 00:33 | But at its core, Xcode is here to
organize the files in our applications, and it
| | 00:38 | groups them into projects.
| | 00:40 | Projects are just a way of grouping a
bunch of files together and giving them a name.
| | 00:45 | When you create a new project in Xcode,
and I am going to do one now--again,
| | 00:49 | selecting from the OS X Application
section and choosing Cocoa Application--we
| | 00:54 | are going to do a new project.
| | 00:57 | Again, it's going to ask me for the
naming information, I am just going to call
| | 01:01 | this project DemoXcode.
| | 01:02 | Leave everything else unchecked except
Use Automatic Reference Counting, and I
| | 01:08 | am going to go ahead and
just Save this onto my Desktop.
| | 01:14 | But before we go exploring this actual
project, I am going to take a look at
| | 01:19 | what was created when we did that.
| | 01:21 | If I go to my Desktop, I see here
that I have a folder called DemoXcode.
| | 01:25 | This just got created, and I had deleted
some of the other projects I created earlier.
| | 01:30 | If I go into that--and let's just expand
it so we can see a little more here--we
| | 01:35 | have quite a few files that have
actually been created for us. And what you will
| | 01:40 | see is that some of them match what I
see in Xcode and some of them don't.
| | 01:47 | If I compare the two, I can see that
there is kind of a slight difference to the
| | 01:53 | layout in there, expanding all the
folders in Xcode, while some of those folders
| | 01:57 | don't even seem to exist, or they have
different names ,or there is a different
| | 02:01 | arrangement of files here.
Don't worry about that.
| | 02:03 | Xcode allows us more ways of
grouping these files than just the actual
| | 02:08 | folders on the hard drive.
| | 02:10 | However, there is one file you will
see in the Finder, which is this one,
| | 02:14 | the .xcodeproj or the Xcode Project file.
| | 02:18 | This is the file that contains all the
settings for this particular project, and
| | 02:23 | if Xcode was closed, double-clicking
this file will be the quickest way to open
| | 02:27 | Xcode with this project loaded.
| | 02:29 | So switching back, let's talk about the
best way around the Xcode for interface.
| | 02:34 | We are, of course, in a programming
environment, so everything is oriented around
| | 02:39 | us editing something, and it's really
oriented around this middle section.
| | 02:43 | Whether that's letting us edit
code or change the user interface.
| | 02:47 | The toolbar up at the top of Xcode will let me
run the application, as we have seen already.
| | 02:53 | This center section looks like a
little LED screen, and it will show messages
| | 02:57 | about anything that Xcode is doing as
we work with our project. It's kind of
| | 03:01 | like how iTunes displays messages
when you are copying or syncing.
| | 03:08 | Over here on the top right of the bar
you have two groups of three buttons.
| | 03:13 | What I am just going to do right now
is make it so the first button of each
| | 03:17 | group is pressed in. And this first
means we are showing the Standard Editor,
| | 03:22 | there are different editors,
but we will see those later.
| | 03:24 | And in the second section we have these
three buttons with a dark left section,
| | 03:29 | a dark bottom section, and a dark
right section, and all these buttons do is
| | 03:34 | toggle the different sections on and off.
| | 03:38 | Unlike some other applications, in
Xcode you don't rearrange or detach and drag
| | 03:44 | and drop panes from one area to another.
This is Apple, this layout is this layout.
| | 03:50 | The section on the left stays on the
left, you can choose to make it visible
| | 03:54 | or not, but that's it.
And the left-hand section is the navigator.
| | 04:00 | The navigator is a way to navigate, to
get around everything in and everything
| | 04:04 | about this project, all the files,
the settings, the configuration options.
| | 04:09 | We have seen that we can
expand and collapse files.
| | 04:12 | If I single click on one of the files
in this project, and it's editable, it
| | 04:16 | will open up in the middle section.
| | 04:18 | If I were to double-click it, it
would open up in a separate window.
| | 04:22 | I am a fan of a single
clicking so that's what I tend to do.
| | 04:26 | Now, this left section
contains seven different navigators.
| | 04:29 | You can move between them by
clicking the buttons at the top.
| | 04:32 | There is really not much to see in the
other ones right now, but you will be
| | 04:36 | able to view things like issues or
log messages when looking at this.
| | 04:40 | And sometimes Xcode will switch you to
a different navigator if that's useful.
| | 04:46 | But you don't need to memorize them all
yet. The most important one of the seven
| | 04:49 | navigators is the Project Navigator, the
first button, the one that looks like a folder.
| | 04:55 | And a useful shortcut for
this is Command+1, and that will open the
| | 05:01 | Project Navigator even if the
left section is completely closed.
| | 05:04 | You just hit it, it will jump you right there.
| | 05:07 | The Project Navigator is a view, not
just of all the files in your project--
| | 05:11 | although you can do that by just
single clicking around them--but also the
| | 05:16 | project settings itself.
| | 05:17 | Clicking the very top icon, the one
with the same name as the actual project,
| | 05:22 | gets you the top level settings of the
project here, which can contain things
| | 05:27 | like the Application icon, what Version
is this, I can see places where it can
| | 05:32 | work with the bundle identifier.
| | 05:34 | We have checkboxes that allow us to
say whether we Allow Camera Access or
| | 05:38 | Microphone or USB Access.
| | 05:40 | And clicking across the top here,
there is different technical Build
| | 05:44 | Settings and Build Rules.
And we will see some of these little later on.
| | 05:48 | Now just as the left-hand side, the
Navigator Panel can be turned on or off so
| | 05:53 | can the right-hand side.
| | 05:55 | This side contains two separate parts,
the Inspector's at the top, and the
| | 06:01 | Library is in the bottom half.
| | 06:02 | Now, the arrangement here is not random,
there is a point to how these things
| | 06:07 | are grouped together.
| | 06:08 | We can think of the navigators on the
left as showing everything in the project
| | 06:13 | and the Editor section over here as the
one thing that I am working on and then
| | 06:18 | the Inspectors on the
right are context-sensitive.
| | 06:21 | The Inspectors change as
I select different files.
| | 06:25 | Just as the Navigator section on the
left had seven different sections you can
| | 06:29 | move between, the Inspector section
over here on the right also has different
| | 06:34 | sections you can move between, and that
changes based on what you have selected.
| | 06:38 | If I am editing a code file, I am likely
to find that I just have two Inspectors
| | 06:43 | over here, the File Inspector
and the Quick Help Inspector.
| | 06:47 | If I have a User Interface file
selected, an XIB file, I actually find that I
| | 06:52 | have eight Inspectors that I can move between.
| | 06:54 | Again, don't worry about memorizing them,
we will explore them later as we need to.
| | 06:58 | Now, below the Inspector section is the
Library section here, and the Libraries
| | 07:04 | are the simplest section and they do not
change based on what you have selected.
| | 07:09 | Libraries contain collections of things
you might wanted to add to your project,
| | 07:14 | like having a library of user interface
elements, or a library of code snippets,
| | 07:19 | and things in the library
can be dragged and dropped.
| | 07:21 | Now Xcode, like any other application
has Preferences, things you can customize
| | 07:27 | about this application to
make it work better for you.
| | 07:30 | Now, I am typically leaving it pretty
much as is straight out of the box, but I
| | 07:34 | have made two small changes just
to show you what I have got here.
| | 07:39 | From the Xcode menu I can select
Preferences, and in the Fonts & Colors section
| | 07:44 | I had switched to the Presentation
theme just to make the font size bigger and
| | 07:48 | more readable for this course.
| | 07:51 | And then in the Text Editing section I
have a check box selected so that we can
| | 07:56 | see Line numbers so that when I am
exploring the code, it's a little easier to
| | 08:00 | talk about line by line.
| | 08:01 | Now Xcode of course, does have options
to connect to Source Control Repositories
| | 08:07 | and Debugging options, Code Snippets
and ways to help us manage our projects.
| | 08:12 | But this is really enough to help us
get going, because some of the other
| | 08:15 | options really are not worth bothering with until
we have got a bit more code to play with.
| | Collapse this transcript |
| Using Model-View-Controller| 00:00 | Before we start adding more
interaction to an application, we should talk a
| | 00:04 | little bit about MVC, or Model-view-Controller,
which is a very important concept for Cocoa.
| | 00:09 | Now if you're coming from iOS, you'll
know that MVC is extremely formalized and
| | 00:15 | enforced over there.
| | 00:16 | Now it's a little less enforced in
regular Cocoa, but still essential.
| | 00:20 | Now as you probably know, MVC is not just
for Apple development, it's been around
| | 00:25 | for a long time, since the late 70s in fact.
| | 00:27 | MVC is a software design
pattern, meaning it's an idea.
| | 00:32 | You can do Model-view-Controller in Java,
you can do it in C#, you can do it for
| | 00:38 | the web or for mobile, or you can do
it for Desktop Applications on a Mac.
| | 00:42 | And at the core of MVC, it means the
objects that represent your data and the
| | 00:47 | objects that represent your
user interface are kept apart.
| | 00:50 | And you should be able to change
one without affecting the other.
| | 00:54 | And the model part of
Model-view-Controller is your data.
| | 00:59 | The information your app needs and
stores and manipulates, objects that
| | 01:04 | represent contacts in the contacts
application or emails in a mail application,
| | 01:08 | or customers or employees or orders,
but these objects do not inherently
| | 01:14 | define a user interface.
| | 01:15 | They don't say whether they show up
in a text field or a dropdown box or a
| | 01:20 | button or what font they use.
| | 01:23 | But on the other side of
things we have view objects.
| | 01:26 | view objects are your interface, your
User Interface elements what the user
| | 01:30 | actually sees, windows and menus and
buttons and sliders and text fields, these
| | 01:35 | are all view objects.
| | 01:37 | We might have different ones for a print
view and different ones for a web view.
| | 01:42 | And often we want to use generic User
Interface element, so they can be reused.
| | 01:47 | You can have multiple
buttons that do different things.
| | 01:50 | And a button knows if it's being
pressed or released and a text field knows
| | 01:55 | how to draw itself.
| | 01:56 | A text field knows if it's being edited,
but it doesn't do the job of retrieving
| | 02:01 | or storing or processing the data typed into it.
That would be the model's job.
| | 02:06 | And the Controller object then is the
glue that hooks one side to the other.
| | 02:13 | A view object talks to a Controller
object, the Controller talks to the Model.
| | 02:17 | But the Model and the view
don't talk directly to each other.
| | 02:22 | And the idea with pure MVC is that
every object in your program would fall
| | 02:27 | exactly into one of three roles,
either Model, view, or Controller.
| | 02:32 | Now that doesn't mean you
only have three objects.
| | 02:34 | You could have hundreds.
| | 02:35 | But each one is clearly a Model object,
or a view object, or a Controller object.
| | 02:40 | I mean in practice, in Cocoa, our
Model and Controllers are written as
| | 02:45 | Objective-C classes with header
and implementation files for each.
| | 02:50 | And the user interface view objects are
collected in a .xib, or xib file, which
| | 02:56 | is the one that gives us our
visual user interface builder.
| | 02:59 | And we will talk more
about what a xib file is later.
| | 03:02 | In a simple Hello World style application, we
can actually get away without defining formal model
| | 03:08 | objects, simply because we don't
have any data worth describing yet.
| | 03:13 | But if you want any kind of behavior to
occur, any kind of interaction between
| | 03:17 | your User Interface elements and your
code, one of the things that you do have
| | 03:22 | to define very well is the
relationship between your view and your Controller
| | 03:26 | objects, it's not automatic.
Let me show an example here.
| | 03:30 | If I build an interface in Xcode, and I
drag on some really basic UI element, a
| | 03:37 | text field, a button and the
label, these are all view objects.
| | 03:42 | The label is a view object, the button
is a view object, the text field is a
| | 03:46 | view object, the window itself is a view object.
| | 03:48 | So you can have multiple view
objects and one of them like the window can
| | 03:53 | contain other view objects.
| | 03:54 | But we have to define very specifically,
the relationship between these view
| | 04:01 | objects in any code we want to connect them to.
| | 04:04 | Now in Xcode you can do what you
might be able to do in other IDEs, which is
| | 04:09 | drag on a button, double-click
it, and write your code.
| | 04:12 | It doesn't work that way.
| | 04:14 | We need to first decide what code
file represents our Controller code.
| | 04:19 | And then we look at each view object
and think about what kind of connection it
| | 04:24 | needs to that Controller code.
| | 04:26 | So, for example, we have a button on
the user interface, and I want that button
| | 04:31 | to cause a method to be
run in the Controller code.
| | 04:35 | So we need to define this button
as causing what's called an Action.
| | 04:40 | This view object of a button causes
something to happen in the Controller code,
| | 04:45 | that's an Action in Cocoa.
| | 04:47 | Now on the flipside of that, we often
want to reach from our Controller code
| | 04:52 | back into view object, say, like the text
field to either read its contents or to change it.
| | 04:58 | If so, we need to define our text
field as being what's called an outlet.
| | 05:03 | And we might also want to write some
code to change the label, in which case the
| | 05:07 | label is also an outlet.
| | 05:10 | So when you're building Cocoa
applications, you are defining very specifically
| | 05:14 | your actions, where a view object
triggers something to happen in the Controller
| | 05:19 | and defining outlets, something in the
Controller code affects the view object.
| | 05:24 | Now some User Interface elements
could be both actions and outlets.
| | 05:29 | Perhaps, I want to click a button in the
view that causes some code to be run in
| | 05:35 | the Controller and then that reaches
back into the button and disables it, well
| | 05:38 | that would require the button to
be both an action and an outlet.
| | 05:42 | Well, let's see some examples of
actions and outlets in practice.
| | Collapse this transcript |
| Creating basic interaction| 00:00 | I am going to create a new Xcode project.
This will of course be a Cocoa Application.
| | 00:04 | I'll just give it a simple name, in
this case, BasicInteraction, because I want
| | 00:08 | to get the view and our
code to talk to each other.
| | 00:11 | Make sure that everything except Use
Automatic Reference Counting is unchecked.
| | 00:15 | I am just going to save that onto my Desktop.
| | 00:19 | This project template
gives me a handful of files.
| | 00:22 | We have the AppDelegate.h and AppDelegate.m
files here, and our interface MainMenu.xib.
| | 00:30 | Now you will hear these files referred
to as XIB files, which kind of makes sense
| | 00:33 | for .xib, but also as NIB files which might not.
| | 00:37 | That's because until a few years ago
the file extension for your user interface
| | 00:41 | files was .nib, which stood
for Next Step Interface Builder.
| | 00:46 | We used to use a separate program
called, Interface Builder, to work with these
| | 00:50 | files up until Xcode 4. When it was
integrated into Xcode itself and they have
| | 00:55 | actually been called XIB files for a
few years, but a lot of developers still
| | 00:59 | talk about the NIB file and adding
things to the NIB and customizing the NIB.
| | 01:03 | Now technically, this .xib file will
actually be quietly converted into a NIB
| | 01:10 | file during the compilation process,
but you never actually see that.
| | 01:14 | So informally the terms XIB file
and NIB file are interchangeable.
| | 01:19 | And by default, if I click this XIB
file, I just see the menu for this
| | 01:23 | application, with the name of the project,
File, Edit, Format, view, Window, and Help.
| | 01:29 | To see the actual Main Window I need
to find the Window object in the Dock.
| | 01:34 | Again this Dock can be collapsed or
expanded, it can't be gotten rid of.
| | 01:39 | So you should be able to
grab the window either way.
| | 01:42 | Now what I want to do next is drag some
user interface elements onto my window here.
| | 01:47 | I am going to drag on a text field, a
button, and a label, and these will be
| | 01:51 | in my Object Library.
| | 01:54 | If you happen to have the right-hand
section of the app closed, you get to it
| | 01:59 | through the view menu, down to view
> Utilities > Show Object Library.
| | 02:03 | I am going to drag that up a bit.
| | 02:08 | There are a lot of user interface
elements and different objects I can select from.
| | 02:12 | So if it seems a little intimidating, I
can use this box down at the bottom of
| | 02:16 | the library to filter.
| | 02:18 | I could type in, say, a word like button,
and just see all the buttons that I have
| | 02:23 | options to use or label
or text or whatever else.
| | 02:28 | Well, with buttons selected, I
am going to grab one of these.
| | 02:31 | I will grab the Rounded Rect
button, which is as good as any.
| | 02:34 | All the buttons are actually very
similar to each other, they just
| | 02:38 | have different styles.
| | 02:39 | We will go through the different user
interface controls in a little while.
| | 02:43 | Now by grabbing the button and moving it
around, I can actually see as I move it
| | 02:47 | that Xcode will give me some helper
information, the little lines here that will
| | 02:52 | tell me when it's positioned
correctly or in the middle.
| | 02:55 | I can just put that
anywhere that I want to right now.
| | 02:59 | We can also grab the handles of the window
itself to resize the window and bring it in a bit.
| | 03:05 | Double clicking the button will
let me rename the text that it shows.
| | 03:09 | I will just say click, and I can grab
the handles just to make it a little wider.
| | 03:14 | Next, I want to add on a label.
| | 03:17 | I could check that by typing
in label at the search box.
| | 03:20 | I see I have a Wrapping Label and a
regular Label that displays text. That will do.
| | 03:25 | So I'll drag Label on.
| | 03:26 | If I'm going to put a message in it,
I want it to be a littler wider.
| | 03:30 | So I will drag it the
width of this interface here.
| | 03:34 | What if I wanted to change
something about that label?
| | 03:37 | Well, over here in the Inspectors
section of the right-hand panel, the fourth
| | 03:43 | option that I have here is
the Attributes Inspector.
| | 03:45 | So I am going to click that one.
Now this is of course context-sensitive.
| | 03:50 | So it will show different things based
on whether I have the buttons selected or
| | 03:53 | whether I have the Label selected.
| | 03:55 | With the Label selected we can do
things like change the alignment to center
| | 03:59 | aligned, or change the Text Color or the
Background, and we will see a few of the
| | 04:04 | other options that we have
for this a little later on.
| | 04:06 | Now the last user interface element I
want right now is actually a Text Field.
| | 04:12 | If I type in the term text here I'll
see I have got Textured button, Rounded
| | 04:16 | Textured button, Text Field, Secure
Text Field for passwords and so on, Date
| | 04:21 | Pickers, Number Formatters.
Let's just grab the basic Text Field.
| | 04:25 | I'll drag that on there, drag it a
little wide and let the prompts tell me when
| | 04:29 | it's at the right position.
| | 04:31 | With that selected I am going to make
sure that I have my Attributes Inspector
| | 04:35 | selected, the fourth one here in the
Inspector section because I want to give
| | 04:39 | it a Placeholder String.
Let's type in Please type your name.
| | 04:44 | That will just give me the grayed out text
here that will disappear when I click into that.
| | 04:51 | Label I am going to double-click
and actually remove the text that's in
| | 04:54 | there so it's blank.
| | 04:57 | I'll drag the button up a little bit,
position it in the center and then just
| | 05:02 | shrink the actual window down a little bit more.
| | 05:04 | Now here is one of the issues. What
happens if I have removed the text from the
| | 05:10 | label, and I don't know if it exists anymore?
| | 05:12 | Well, there is a couple
of ways I could check it.
| | 05:15 | One is, over here on the Dock if I expand
it, so I can see the wider view what it
| | 05:20 | allows me to do is drill down
into the different elements here.
| | 05:24 | So if I collapse them in, and expand
this window I can see I have a view
| | 05:28 | inside that that has a Round Rect
button, and when I click that, it's
| | 05:31 | highlighted in the Editor.
| | 05:33 | Static Text which is the label that we
have, I can see that's now highlighted,
| | 05:37 | and the Text Field itself.
| | 05:40 | Another way of getting to it is up
here is what's called the Jump Bar and
| | 05:45 | clicking any particular section here
will allow me to jump between say that
| | 05:49 | Static Text or the Round Rect button,
or up another level between the window
| | 05:55 | and say the Main Menu.
| | 05:57 | So there are multiple ways to
get to the different pieces here.
| | 06:01 | So this is my impressive
interface, Text Field, button, Label.
| | 06:05 | I want to have people type something
into the text field, click the button, and
| | 06:09 | change the contents of the label so
we can see some basic interaction.
| | 06:13 | We now have to be very explicit
about how these user interface elements
| | 06:16 | connect into our code.
| | 06:17 | What we have to say is, what do we want
the relationship to be between the text
| | 06:22 | field and the button and the label and our code?
| | 06:24 | So first off we want the button to
cause something to happen in our code.
| | 06:29 | It will cause an action to happen.
| | 06:31 | And on the flipside, I want
the text field to be an outlet.
| | 06:34 | I want to reach into it from our code,
grab the contents of it and then be able
| | 06:39 | to reach to the label and
change the contents of it.
| | 06:42 | So those would be outlets.
I am going to show you two ways of doing this.
| | 06:46 | First, the older slower way,
and then the new quick way.
| | 06:49 | I am going to show you the slow way first so
you understand what the quick way is doing.
| | 06:54 | So every connection between these view
objects in our code is a handshake to it.
| | 06:59 | Something that needs to be done in the
code file, something that needs to be
| | 07:03 | done in the user interface file,
there is always two parts to it.
| | 07:06 | Let's go to the code first.
| | 07:08 | Well, I said we connect our view objects
to a controller object to a controller code.
| | 07:14 | So where's the controller?
| | 07:15 | Well, I could create a new class for
that, and we will do that later, but for
| | 07:21 | this simple example I am going to use
the only existing class that we have here,
| | 07:25 | the AppDelegate class.
| | 07:27 | Selecting my AppDelegate header file, I
can see I have something in here called
| | 07:32 | window, it's given me a
little bit of boilerplate code.
| | 07:35 | I have got this NSApplicationDelegate.
| | 07:37 | I might not know what that
means but that's okay right now.
| | 07:40 | We will talk about that later.
| | 07:42 | What I want to do is in my header,
I am going to define a method.
| | 07:45 | I am going to define a method that I
want the button to call when it's clicked.
| | 07:50 | Now usually if I define a method
I'd make a simple one like this.
| | 07:58 | Define it as a method called changeLabel
that takes no parameters and returns void.
| | 08:03 | Well, that's okay, but it's not really
going to work in this case, because I
| | 08:08 | need to create some kind of indicator
that the method I am about to write can be
| | 08:12 | called by a view object in the user interface.
To do this, we actually change the return type.
| | 08:19 | Instead of using void, we have a
special return type called IBAction.
| | 08:23 | So I am going to define that method and
start typing IBAction, upper case I, B,
| | 08:29 | and A. As I type we see that it
pops up here with the code sense.
| | 08:34 | I am going to hit Tab and jump to
selector which will be the name of the method.
| | 08:39 | So I will actually call this
changeLabel. It's not built-in, it's my own.
| | 08:44 | So I will just define it myself.
| | 08:47 | By default, IBAction should take a
parameter of ID, called sender, which is fine.
| | 08:53 | So I will just hit Tab and
finish the line off with a semicolon.
| | 08:57 | Now if you notice that by defining
this as returning IBAction, we get this
| | 09:02 | circle over here on the left-hand
side, and this is an indicator.
| | 09:06 | It's saying this method can be
connected to a user interface element.
| | 09:12 | If on the other hand I had just created
a method with a return type of void, we
| | 09:20 | would not get that circle.
So what is IBAction?
| | 09:23 | Well in truth, it's actually the same as void.
It means this method doesn't return anything.
| | 09:29 | IBAction is just an indicator, we are
announcing to Xcode, we are announcing to
| | 09:34 | Cocoa that this method can be
connected to a user interface element.
| | 09:38 | Now I don't need that doSomething method.
I just wanted to show that.
| | 09:42 | Now next, I want my code to be able to
have access to the label and the text
| | 09:47 | field objects that I defined and
dragged onto my user interface file.
| | 09:52 | So I need something that represents a
Label object and a Text Field object in my
| | 09:56 | class so I can hook them
up to the user interface.
| | 09:59 | We do this with properties, but these
properties won't be integers or string,
| | 10:03 | they need to be the correct kind of objects.
| | 10:06 | So I am going to put them beneath the
existing @property that I have here.
| | 10:12 | What I am going to do is use the word weak here.
We'll talk about that in a little bit.
| | 10:20 | I mentioned earlier that if I want
something in the view to affect the code,
| | 10:25 | it's an action. Whereas if it's
something in the code to reach out to the view,
| | 10:29 | it's an outlet. And I can actually see
on line 13 above it we have something
| | 10:33 | saying IBOutlet for interface builder outlet.
| | 10:36 | That was already there, but I'm going to
write my own, IBOutlet, and what is this?
| | 10:42 | Well, it's actually going to be an NSTextField.
That's part of the AppKit framework.
| | 10:50 | So NSTextField, and it is
of course a pointer object.
| | 10:55 | So I'll just call this one textField.
| | 10:57 | Right now, there is no connection
between this property and the actual text
| | 11:03 | field I have dragged on to the user
interface, but there will be in a moment.
| | 11:06 | Now next, I am going to write a property,
this will also be weak, very similar
| | 11:11 | to the previous one.
This will be IBOutlet.
| | 11:13 | Now you might think is this an NSLabel?
Actually no, it's another NSTextField.
| | 11:20 | In Cocoa, a label is simply an
NSTextField that isn't editable and doesn't have
| | 11:26 | a white background to it.
I will just call it myLabel.
| | 11:34 | Now these will be generated
properties, so we may have to jump into our
| | 11:37 | implementation file in a moment to
add the synthesize statement for those.
| | 11:42 | So I am going to jump cross into
AppDelegate.m, and after the opening
| | 11:48 | @implementation line, I am going to add in
synthesize for both textField and myLabel.
| | 11:58 | If you're using Xcode 4.4 on Mountain Lion or later,
you won't need the synthesize statement.
| | 12:05 | Now the only other thing that I'm
getting a complaint about right now for an
| | 12:09 | incomplete implementation, which I get
by clicking the little exclamation mark
| | 12:13 | here is, I haven't provided any kind of
implementation for the changeLabel method
| | 12:18 | which I need to do that now.
| | 12:21 | We use the same format which was IBAction,
and it was called changeLabel, and it
| | 12:28 | took that parameter of ID sender.
We have got a little bit of extra code in here.
| | 12:33 | That is about right.
| | 12:34 | So I want to say, well, what actually
happens when that button is clicked where
| | 12:38 | we change the label.
| | 12:39 | What I am first going to do is construct a
string, including the contents of the text field.
| | 12:44 | So I am going to create a new
NSString object and construct a message that
| | 12:50 | begins with Hello, and then what I am going
to do is grab the contents of the text field.
| | 12:56 | So how do I do that?
| | 12:57 | Well, I will have an object called textField,
and the property I need is called stringValue.
| | 13:05 | Just close the panel on the right-hand side
to give us a bit more screen real estate here.
| | 13:12 | So I construct that new message,
and then I better change the label.
| | 13:19 | On the same way that I used
stringValue as a property to grab the contents of
| | 13:24 | that text field, I will use
setStringValue passing in that new NSString object.
| | 13:30 | I am going to save that, hit Command+B to build,
I get Build Succeeded message. So I just run it.
| | 13:37 | So is it going to work?
| | 13:39 | No, absolutely not, because right now
I have only done one side of the connection.
| | 13:44 | I said that everything is like a handshake.
| | 13:47 | There is something you do in the code
unless something you do in the user interface.
| | 13:51 | And all I have done right now is in the code.
| | 13:53 | So I'll quit out of the BasicInteraction
app and jump back in here, grab my
| | 13:57 | navigators, and jump over into
MainMenu.xib. And this is where I define the
| | 14:05 | connections between these
view objects and our AppDelegate.
| | 14:09 | Well, how do I do it?
| | 14:11 | There is a couple of
different ways, but here's one.
| | 14:13 | We have seen that by clicking around
we have got objects in the Dock here,
| | 14:17 | one represents Main Menu, one
represents the Window itself, the one below it
| | 14:22 | represents App Delegate.
| | 14:24 | This App Delegate for us right now is
kind of the conduit between our .xib and
| | 14:29 | our AppDelegate.h and
AppDelegate.m. So here's what I do.
| | 14:35 | I want to connect this button
to the method called changeLabel.
| | 14:39 | So I hold down the Ctrl key, and I do
Ctrl-click on the button and then drag,
| | 14:45 | keeping the Ctrl key held down,
move over AppDelegate and let go.
| | 14:52 | What happens is Xcode scans the header
file for AppDelegate and says, hey, does
| | 14:57 | that header file have
anything defined as an IBAction?
| | 15:00 | Well, yes it does, it has
one method defined as IBAction.
| | 15:03 | It's called changeLabel.
| | 15:04 | Is this the one you want
to connect to? Well, it is.
| | 15:07 | So I mouse over changeLabel and click it.
| | 15:09 | We now have a connection
between the button and the code.
| | 15:12 | Now we go the other way around.
| | 15:15 | What I have defined in
AppDelegate.h are these two outlets.
| | 15:20 | I want to reach from the
code to that user interface.
| | 15:24 | So I am going to click back into the
MainMenu.xib, and now I'll Ctrl-click from
| | 15:30 | App Delegate, Ctrl-clicking there,
holding down the Ctrl key I drag over Text
| | 15:35 | Field, and if you notice as I drag
around it, it kind of highlights the
| | 15:39 | different objects that I can connect to.
So I drag over text field, I let go.
| | 15:43 | It again scans up delegate and says,
well, you have got two things defined as
| | 15:46 | IBOutlets that aren't hooked up to anything yet,
myLabel and textField. Which one is this?
| | 15:51 | Well, I move over textField, click, its
text field. Then hit Ctrl and drag again
| | 15:57 | from App Delegate, find the Label, even
though it's invisible, by mousing over I
| | 16:01 | can find it and let go.
| | 16:03 | It's given me a hint though that
textField is already connected to something,
| | 16:06 | but myLabel is not, that's the
little dash, so I'll click myLabel.
| | 16:11 | That's how we describe the connection
between our user interface and our code.
| | 16:16 | Now it's a very common problem for
people new to Cocoa or iOS development who
| | 16:22 | have to do this a lot as well to mess
up the connections, and it's one of the
| | 16:27 | first places you should look when
you're trying to diagnose where a problem is.
| | 16:30 | And here is one of the problems right now.
I can't see anything.
| | 16:34 | There is nothing obvious just from
looking at this that I just created three
| | 16:37 | connections between the
user interface and the code.
| | 16:40 | Well, there's a few ways of getting to this.
| | 16:42 | One is, if I open up the right-hand side
panel, select any of these view objects,
| | 16:49 | and go up to the Inspectors, what I
will find is the sixth one with the little
| | 16:53 | arrow is called the Connections
Inspector. And what it can show here is
| | 16:57 | different connections here, and it's
actually showing me as I mouse over that
| | 17:00 | this textField is connected to App Delegate.
| | 17:03 | If I highlight the button, I can
see here I have got a Sent Action.
| | 17:07 | This button is calling
changeLabel in App Delegate.
| | 17:10 | If I move over the Label itself,
myLabel is going to App Delegate.
| | 17:15 | Another way I can view them is actually
by right-clicking, say the App Delegate
| | 17:20 | object here which shows me the
connections between the Outlets, and as I mouse
| | 17:24 | over them, it even highlights them
and the Received Actions, changeLabel is
| | 17:29 | being called by the button.
| | 17:31 | So there are a few different ways of
getting to that, and we'll have more than
| | 17:35 | enough practice as we go through this course.
| | 17:38 | So let me go ahead and run this
application. Build Succeeded.
| | 17:42 | Please type your name,
this is the placeholder text.
| | 17:45 | As soon as I start typing it should go
away, and then we hit click, and we get
| | 17:49 | the message Hello, Simon.
| | 17:51 | So very basic interaction here,
obviously there is a lot more we can do with it,
| | 17:56 | but let's leave it at that for the moment.
| | 17:59 | So now it seems like it's
quite a chore to hook things up.
| | 18:02 | Well, I did say that that was the slow
way of doing it and luckily there is also
| | 18:06 | a quicker way, and we'll do that next.
| | Collapse this transcript |
| Creating quick connections| 00:00 | We have seen how to make connections
between our user interface view objects and
| | 00:04 | the properties and methods that we
have actually written out in our code, but
| | 00:08 | Xcode can help us speed this entire thing up.
I am going to make another Cocoa Application.
| | 00:12 | I will just call this one QuickConnections
and save it to my Desktop. Making sure
| | 00:17 | everything except Use Automatic
Reference Counting is unchecked.
| | 00:25 | I am going to jump over into MainMenu.xib
and from the Dock select the Window
| | 00:31 | object to make our Window interface
visible. And I am just going to go ahead and
| | 00:36 | layout a very straightforward and
simple interface having a Text Field button
| | 00:40 | and a Label. And just position them
pretty much anywhere on this interface, I
| | 00:51 | will make this little smaller.
| | 00:53 | So we know that we always have to be
very specific, very explicit about how
| | 00:57 | these connect to the code files that are
associated with this user interface.
| | 01:02 | And the way we can be really quick
about this is by using what's called the
| | 01:05 | Assistant editor in Xcode.
| | 01:07 | I am going to give myself a bit more
room right now just by turning off my
| | 01:11 | Navigators and Utilities panel.
| | 01:13 | You don't have to, I just don't have a
lot of screen real estate to work with.
| | 01:18 | So making sure that I am in the XIB file,
I am going to turn on my Assistant editor--
| | 01:23 | that's the second button up here on
the toolbar in the Editor section, looks
| | 01:27 | like a bowtie and tuxedo, your
personal butler or assistant.
| | 01:31 | Now the Assistant editor will show us
two files available for editing at the
| | 01:36 | same time, an original file and its counterpart.
| | 01:39 | So if I was looking at the .h header
file, the counterpart will be the .m
| | 01:44 | implementation file, but if I am here
in there .XIB, well the counterpart here
| | 01:49 | could potentially be a few different code files.
| | 01:53 | Right now, what I want to see is the
XIB file on the left-hand side and the
| | 01:58 | AppDelegate header file on the right-hand side.
| | 02:01 | Now, if it doesn't show me what I want
automatically on the right-hand side, I
| | 02:05 | can use the Jump bar and manually
select that particular file from here, but we
| | 02:11 | look good right now.
| | 02:13 | So AppDelegate.h has nothing inside it
that corresponds to our user interface
| | 02:19 | elements that I just dragged on the
text field, the button, the label.
| | 02:23 | They just don't exist there, and they need to.
| | 02:25 | So what I can do, for example,
is connect from the button.
| | 02:30 | Again, just by holding the Ctrl key down,
clicking and dragging. And if we drag
| | 02:35 | directly into the code file here, I will see
this little insert outlet, or action, pop-up.
| | 02:41 | Now notice that if I am above the
interface, or below the @end, it won't let me
| | 02:47 | put it anywhere there, so it's going
to give me an option for where I can
| | 02:51 | actually place this.
| | 02:52 | So after the @ sign property
line, I am going to let go.
| | 02:56 | What I get is this pop up window saying,
you can insert an Outlet, or an Action here.
| | 03:01 | It knows I want to make a connection,
it's just not quite sure with this button,
| | 03:05 | whether I want it as an Outlet, or an
Action because a button could be either.
| | 03:09 | Well, what I want to do is an Action.
| | 03:12 | I want this button to cause something to
happen in the code, to cause a method to be called.
| | 03:17 | Now if it is an Action, what it's asking
is, what's the name of the Action?
| | 03:21 | What is the name of the Method?
So I will call it changeLabel, and then hit Connect.
| | 03:26 | And it will create the method
signature here with the IBAction return type--
| | 03:32 | which is the correct one--and it will make
the connection between that button, and that code.
| | 03:37 | Not only that, but if I use the Jump bar
to just jump over to the implementation
| | 03:41 | file here, it will actually create
the implementation stub for that method.
| | 03:47 | So just by dragging from the
interface into the code, I get three pieces.
| | 03:51 | I get the part in the header file, I get
the implementation file, and I have the
| | 03:56 | connection defined as well.
| | 03:57 | So I am going to jump back into the
header file, I am using the Jump bar here,
| | 04:01 | and I am now going to make the
connections for the text field and for the label.
| | 04:06 | Once again, I do it the same way.
| | 04:08 | I am going to hold down the Ctrl key
and just drag from the text field, making
| | 04:12 | sure it's the text field that I
see selected there, into the code.
| | 04:15 | Again, it has to be within the @
interface and @end lines, doesn't really matter
| | 04:21 | where you put it, but I would like to
put all my properties before my methods.
| | 04:25 | So I will just drag it up here.
Now it's saying is this an Outlet or an Action?
| | 04:30 | Well, this would be an Outlet.
| | 04:31 | I want to write some code that will
reach from the code into the view.
| | 04:37 | So it's an outlet, whatever I want to
call it, I will call it textField, and we
| | 04:41 | should get into the habit of just
scanning this Type here, making sure that the
| | 04:46 | Type it selects is what you are expecting.
| | 04:48 | Sometimes it can be a clue if
you see something different here.
| | 04:52 | I would expect to see NSTextField.
| | 04:55 | So really all I have to do is give it a
Name and click Connect, and again, I can
| | 04:59 | do that from the label, hitting the
Ctrl key and dragging over, and I will call
| | 05:05 | this myLabel. It is of course
NSTextField, again, our label is an NSTextField
| | 05:11 | object, this is an Outlet,
and it's weak, I'll click Connect.
| | 05:15 | So it's correctly marking these things
as the IBOutlets and correctly marking my
| | 05:20 | methods as an IBAction.
| | 05:21 | Now if you are curious just
about the word, weak here.
| | 05:25 | Well, if you are defining your own
properties that are part of your own classes,
| | 05:29 | you would typically use the word
strong, but here these objects that I am
| | 05:33 | talking about, the text field and the
label, they really belong to the XIB, they
| | 05:38 | belong in that larger view and the
view is what owns those objects, not this
| | 05:42 | AppDelegate class file.
| | 05:44 | And that means what we are creating
are weak references to the objects that
| | 05:48 | exist somewhere else.
| | 05:49 | So we are using the word weak, but
really I am just letting Xcode do that for me.
| | 05:54 | But of course, these are properties
| | 05:56 | that mean they are generated in
our code with getters and setters.
| | 06:00 | So we need to make sure that they
are being synthesized correctly.
| | 06:03 | Again, I use the Jump bar, jump over to
the implementation file, I can actually
| | 06:08 | see that I even have the synthesized
statements are being added as well.
| | 06:12 | So just from dragging and dropping,
we are pretty much ready to go, but the
| | 06:16 | only thing that's missing is to actually provide
some behavior in the changeLabel method.
| | 06:21 | Well, what I am going to do is actually
just switch back to the standard editor,
| | 06:25 | which is the first button here and
then just temporarily select from my
| | 06:29 | navigator just so I can get a bit
more real estate here to work with.
| | 06:33 | And in the changeLabel method I will
write some code to grab the contents of the
| | 06:38 | text field and change the label.
| | 06:39 | So I will create a new NSString
object and use the initWithFormat way of
| | 06:45 | allocating this, to create a new
message that includes the words Hello, and then
| | 06:49 | grabs the content of the text field.
| | 06:52 | And we can get the contents by using
textField space stringValue, and that
| | 06:59 | should do that line, so now we have a
new constructed string together, and all I
| | 07:04 | need to do is use the myLabel
property and say setStringValue to message.
| | 07:12 | We are using Automatic Reference
Counting, so even though I use the alloc and
| | 07:17 | initWithFormat, I don't have to care
about releasing anything. So I can just
| | 07:21 | save this and go ahead and run it,
either by clicking Command+B just to build--
| | 07:27 | to double check that everything builds
without any errors--and then go ahead and
| | 07:30 | hit Command+R to run this.
| | 07:32 | Type something into the text field,
click, Click, and it seems to be taking the
| | 07:38 | contents out of there and changing the label.
| | 07:40 | So it's not the most exciting thing,
but what we have got here is full interaction.
| | 07:44 | We have Outlets, we have
Actions, we have a lot of code being
| | 07:47 | generated to hook our user
interface to our code files.
| | 07:51 | So we can just come along and put in
the code that we want to work, and we can
| | 07:56 | use exactly this method to create more
interesting and deeper user interfaces.
| | 08:00 | And we will do that shortly.
| | Collapse this transcript |
| Understanding the Cocoa application life cycle| 00:00 | By the time they have created a few--even
simple--Cocoa Applications, a lot of
| | 00:05 | developers really want to know
what's actually happening inside of a
| | 00:08 | Cocoa Application, inside of a
Cocoa project, even a basic one that we
| | 00:13 | have just created here.
| | 00:14 | What do these other files represent?
What really is this AppDelegate? And why, if
| | 00:20 | this is an Objective-C program, don't
we do anything with the main function to
| | 00:25 | begin an App? And if we are using
this MainMenu.xib, where is the code that
| | 00:30 | actually loads that?
Well, let's take a look at the processes here.
| | 00:33 | So I have made this straight out of
the box Cocoa Application in Xcode, and
| | 00:38 | there is a lot going on here. But the
most basic idea is, of course, this is an
| | 00:43 | Objective-C program, which means this
program will begin by running main and in
| | 00:48 | a Cocoa Application, we do have a
main.m file, that's actually in our
| | 00:53 | Supporting Files folder.
| | 00:55 | Now as a rule, you will never touch
main in a Cocoa Application.
| | 00:59 | You are going to leave it alone, which
is why Xcode puts it into that folder.
| | 01:03 | And main calls a C function,
called NSApplicationMain.
| | 01:08 | This is a predefined C function in Cocoa that
creates a new object called NSApplication.
| | 01:15 | So the basic process is main opens up,
calls the NSApplicationMain function that
| | 01:21 | creates this NSApplication object
that represents the standard Cocoa
| | 01:26 | Application, the foundation, the
plumbing, the core functionality that every
| | 01:31 | Cocoa Application is going to need,
setting up a run loop, so the application
| | 01:35 | stays active, responding to events and so on.
| | 01:38 | But our application is going to be
different from just this generic application
| | 01:43 | object, so we need to say how.
| | 01:45 | Well, in a lot of other languages,
on other platforms, you would use
| | 01:49 | inheritance for this.
| | 01:51 | You'd actually inherit from this
NSApplication object, or in other languages,
| | 01:56 | an application class.
| | 01:58 | Well, in Cocoa, we don't use
inheritance for this. We use delegation.
| | 02:03 | We need to have an Objective-C class
in our project that will act as the
| | 02:08 | delegate for the standard
built-in NSApplication object.
| | 02:12 | So the NSApplication object can let our
delegate class know about various events
| | 02:18 | we might be interested in, and we can
choose whether or not a respond to them.
| | 02:22 | Now at the same time, the
NSApplicationMain function knows we want at least
| | 02:27 | an initial user interface, so it's
going to look in a property list file in
| | 02:32 | our Xcode project that contains the
name of our main xib file.
| | 02:38 | And by default, that is MainMenu.xib.
| | 02:40 | And that xib file--and everything in
it--Menus, the Window, the other user
| | 02:46 | interface elements, will be loaded as
part of the startup process and exist for
| | 02:51 | the life time of the application.
| | 02:53 | Now in Cocoa, we can provide multiple
windows--but we will see that a little
| | 02:58 | later--and by default, that app delegate will
be connected to our main window object.
| | 03:03 | And all of this is
provided for us as a basic framework.
| | 03:08 | So in main.m, we call NSApplicationMain.
| | 03:12 | If I look at this Lifecycle-info.plist,
it's whatever your project is called
| | 03:18 | -info.plist, we will find an entry in
here called the Main nib file base name,
| | 03:23 | which here it says MainMenu, that's
what's loading in MainMenu.xib and
| | 03:28 | everything inside it.
| | 03:30 | And when looking at the project files,
you might also have a pretty good guess
| | 03:34 | of what class is acting as the
delegate for the application object,
| | 03:38 | it is of course here the AppDelegate object.
| | 03:41 | So this is where we could put the code
to respond to application level events
| | 03:47 | like, for example, our applicationFinishingLaunching
and later maybe the applicationTerminating.
| | 03:54 | Now as we have seen, we can also put
code in this class to react to events in
| | 03:59 | our interface, the same class can act as
an application delegate, and there is a
| | 04:04 | controller for our view objects,
although and anything nontrivial, will split
| | 04:07 | that out into another class. And if you
finding this all a little intimidating,
| | 04:12 | fair enough, there is a lot
going on here, but here's the thing.
| | 04:16 | You don't touch main, you
don't touch NSApplicationMain.
| | 04:20 | Most of the times you don't
need to touch this plist entry.
| | 04:25 | This is the framework that is provided for you.
| | 04:28 | Your interaction with this provided
structure is first off to add code into the
| | 04:34 | app delegate to deal with
application level events, laying out your user
| | 04:38 | interface in the xib file and then
creating Objective-C classes to behave as
| | 04:44 | models and controllers
and hooking them altogether.
| | 04:47 | So when the application first launches, you
will automatically have methods like
| | 04:53 | application:didFinishLaunching, triggered it in
that NSApplication object, and sent over
| | 04:58 | to our app delegate.
| | 05:00 | We can respond if we want to, to deal
with anything we need to do on startup,
| | 05:04 | and there are a lot of methods
that are automatically triggered.
| | 05:08 | When our xib is loaded, then our view
objects are all loaded for the first
| | 05:13 | time and they'll automatically get
send the message awakeFromNib, so they can
| | 05:18 | have their own startup code before we start
responding to mouse clicks and key presses.
| | 05:22 | Now part of our journey is knowing and
finding out the different methods that
| | 05:27 | will automatically occur during the
lifecycle of an app, as well as us
| | 05:31 | creating our own. And even though the
overall process is not something that
| | 05:36 | you need to memorize at all, what is
important to know is there's nothing
| | 05:39 | really hidden behind the scenes.
| | 05:42 | If you know where to look, all this
stuff is actually right there in the
| | 05:45 | provided project templates.
| | 05:47 | It's very specifically defined and the
order is very explicit in what happens
| | 05:52 | and what gets called and which
elements are connected to which other
| | 05:55 | elements, and the structure is provided for
you as part of the basic Cocoa Application template.
| | 06:01 | It's not a blank slate,
it's a working application you build on top of.
| | Collapse this transcript |
| Diagnosing connection issues| 00:00 | Once you get past things like
simple typos, missing semicolons, and
| | 00:05 | case-sensitivity problems in Objective-C.
The single-most common stumbling block
| | 00:09 | for new developers in Cocoa is making a
mistake with the connections, dragging
| | 00:13 | from the wrong object in your user
interface to the wrong part of your code.
| | 00:18 | And the symptom of these problems is
annoying because it's often nothing.
| | 00:24 | Incorrect connections rarely cause a
bug or a message, instead nothing happens
| | 00:29 | when you expect something should happen.
| | 00:31 | You click a button, and you expect it to
call a method to change a label, and it doesn't.
| | 00:36 | Well, here perhaps the button
isn't hooked up to the method.
| | 00:40 | Perhaps the Text field isn't hooked up
to the code, perhaps the method isn't
| | 00:43 | doing what it should, or perhaps they are
both fine, but the label isn't hooked up.
| | 00:48 | So if we have no actual error from Xcode
| | 00:52 | we first go looking at our connections. And
typically you drive this from the XIB file.
| | 00:57 | So I'm going to quit out of this
application and jump into this MainMenu.xib.
| | 01:03 | Now there is no one master view of all
the existing connections in your user
| | 01:09 | interface, you go object-by-object,
element-by-element, looking at the
| | 01:14 | connections for each object.
| | 01:17 | So know that you can view these
connections in several different ways.
| | 01:19 | You can right-click on each element--or
Ctrl and single-click does the same thing.
| | 01:24 | So if I right-click on this button,
for example, I get this pop-up appearing,
| | 01:29 | and I should see Push button at the top
in case you accidentally right-click on
| | 01:34 | the wrong thing, you might
want to just try it again.
| | 01:36 | Now this details all the possible ways that
this object could be connected elsewhere.
| | 01:42 | I can actually drag this
open to see everything here.
| | 01:45 | Now there are a lot of rows of data here,
but as all of these connections need
| | 01:50 | two pieces I can immediately tell
there is actually only one real connection
| | 01:54 | here in all the possible connections.
| | 01:57 | Now with the button this is actually
what I'd expect to see, one entry under the
| | 02:02 | Sent Actions section.
This button is causing something to happen.
| | 02:06 | It's causing an action
and sending that elsewhere.
| | 02:10 | And every Sent Action needs
two pieces of information,
| | 02:13 | the target and the action.
| | 02:15 | The target is the class this button
should point to, and right now it's pointing
| | 02:21 | to the App Delegate class,
although it could be any class.
| | 02:24 | And if you notice, as I mouse over
the App Delegate part of the pop-up, I
| | 02:28 | actually see it highlighting over in
the Dock as well, and that's the target.
| | 02:33 | The action is on the other hand
of the method that we want to call.
| | 02:37 | This is the idea of target action in Cocoa.
| | 02:41 | What class are we pointing to and
what method do we call in that class.
| | 02:46 | You will also hear the term
Selector used to refer to the method.
| | 02:50 | We are selecting the method
that we wanted to execute.
| | 02:52 | Now if I realized by looking at this
that this was pointing to either the wrong
| | 02:57 | class or the wrong method in that
class, I could click this little x to
| | 03:02 | disconnect this button from that class.
| | 03:05 | Now instead of right-clicking, another
way to see this information is using the
| | 03:10 | Connections Inspector which is part
of the Utility section on the right.
| | 03:14 | So I'm going to turn on the
Utilities Panel and find the Connections
| | 03:17 | Inspector, which--up here at the top--is the one
that looks like a circle with an arrow in it.
| | 03:23 | I'll just drag down the Library
section so we can see this a bit more.
| | 03:27 | Again, this is completely context-sensitive.
So with the Connections Inspector
| | 03:31 | highlighted, I click the Text field, I
see the connections with the Text field.
| | 03:35 | I click the button I see the
connections for the button.
| | 03:37 | Again, it's always element-by-element.
| | 03:40 | And I'm seeing exactly the same
information here that there is really only one
| | 03:44 | connection here, it's in the Sent
Actions section, going to App Delegate class,
| | 03:48 | calling the changeLabel method.
| | 03:50 | If on the other hand, I'm more
interested in Outlets, and a good example would be
| | 03:54 | this text field here.
| | 03:55 | I select that, the text field itself
does also have Sent Actions, but I might
| | 04:00 | not be interested in that, I'm
interested in it as an outlet, so I see this
| | 04:04 | Referencing Outlets area where we can
see what it's connected to, which in this
| | 04:08 | case is the App Delegate
class and the textField property.
| | 04:13 | Just jumping over into my App Delegate
header file that looks
| | 04:17 | about right. We have got a
textField defined as an IBOutlet.
| | 04:20 | We have got that changeLabel method.
| | 04:23 | Jumping back into the XIB file, if I
felt like it I can go the other way as well.
| | 04:28 | So I could come down into the Dock,
find the App Delegate class, which is where
| | 04:33 | I have my properties and methods
currently that I want to connect to, and if I
| | 04:38 | right-click that, or Ctrl-click it, I
see another view, the other way around.
| | 04:42 | The Outlets and the Received Actions,
that App Delegate is receiving from Push
| | 04:48 | button an action to call the changeLabel method.
| | 04:51 | Again, if you see as I mouse over Push
button it's even highlighting the right
| | 04:55 | part of the interface.
| | 04:57 | Now couple of these connections that I
can see by right-clicking App Delegate,
| | 05:01 | like the window and the delegate part
were created when the project was made, so
| | 05:07 | I don't want to delete them
just because I didn't make them.
| | 05:10 | Now here's another way of looking at it.
| | 05:12 | In the actual Code view I'm going to
switch to the App Delegate view here.
| | 05:17 | Here's the thing to look out for.
| | 05:19 | We already know that using the IBOutlet
and IBAction keywords can announce that
| | 05:24 | this property or this method can
be connected to the user interface.
| | 05:28 | Well, over on the left-hand side in
this bar here, a filled circle means this
| | 05:34 | can, and is, connected to part of the user
interface, but an empty circle means it
| | 05:41 | can be connected because it's
an IBOutlet here, but it isn't.
| | 05:45 | So I can actually see here that the
myLabel property is not hooked up to the
| | 05:50 | label in the user interface,
even though it could be, it isn't.
| | 05:55 | Switching back into the interface, if
I had right-clicked the label itself, I
| | 06:00 | could see that from the pop-up or
from the Connections Inspector there are
| | 06:04 | no connections at all,
no Outlets, no Actions, no nothing.
| | 06:09 | Now when I'm connecting Outlets I do
prefer to go--rather from the user interface
| | 06:14 | element--I prefer to go from the
code perspective. So in this case, App
| | 06:17 | Delegate, what I could do here is right-click,
and it's telling me that it has a
| | 06:21 | potential outlet called myLabel that is
not hooked up to something in the same
| | 06:26 | way that textField is
hooked up to the Text Field here.
| | 06:29 | So how can I do this?
Well, I just grab this circle.
| | 06:32 | I mouse over the circle from myLabel,
click--I don't have to hit Ctrl here--I
| | 06:37 | just click-and-drag, and as I mouse
over the different elements it highlights
| | 06:40 | them to let me know what I can let go on,
and I wanted to let go on this label
| | 06:44 | of static text, which is blanked out right now.
| | 06:47 | I let go, and now I see the connection
being displayed both in the pop-up, and I
| | 06:52 | see it over here in the actual
Connections Inspector as well.
| | 06:55 | It's giving me the same
information in both parts.
| | 06:58 | If I jumped over to the header file, I
should see that circle is now filled in,
| | 07:02 | so multiple ways to see that,
multiple ways to get to that information.
| | 07:07 | And if I go ahead and run it,
we should now have that working.
| | 07:11 | Now one last word of warning, which is
a very common issue here, I'm going to
| | 07:16 | jump into the Interface view and switch
into the Assistant Editor, which is that
| | 07:21 | very useful way of quickly
hooking up your interface to your code.
| | 07:26 | Typically speaking when you have this
you want to see the XIB on the left and
| | 07:31 | the header file on the right-hand
side, you may have to manually change.
| | 07:35 | If you're using the Jump Bar to
make sure that you're seeing that.
| | 07:38 | It's a great ability to be able to use
this to quickly create properties and
| | 07:42 | methods, but it's easy to make a mistake.
| | 07:46 | So let's say, for example, that I
have dragged on a new button onto this
| | 07:50 | interface, and I want to cause
something to happen in my code.
| | 07:58 | So I Ctrl-click quickly, come down here,
let go, and say I want to call a method
| | 08:04 | called doSomething, I
quickly typed that and hit Connect.
| | 08:08 | Here's the problem.
I did that too quickly.
| | 08:11 | What I have got now here is not an
IBAction but an IBOutlet, a button could be
| | 08:16 | either an Action or Outlet, and I
didn't look at that pop-up closely enough.
| | 08:22 | Now you might think, well no big deal.
| | 08:24 | Surely just I go through, and I'd
delete the code that was added there, I just
| | 08:28 | delete that out, it's gone.
We now look like we did a few seconds ago.
| | 08:31 | Here's the problem.
| | 08:33 | If I save and just hit Command+B to
build this project, we're going to
| | 08:37 | immediately get a failure.
| | 08:39 | Because me Ctrl-clicking and dragging
into the AppDelegate.h didn't just add
| | 08:43 | code there, but it also added the
synthesize statement in the AppDelegate
| | 08:48 | implementation file as well, and
also added the connection in the XIB.
| | 08:54 | So if I did this, and I have to make
sure it was gone from the h, and I have to
| | 08:59 | make sure that this line was gone from
the .m. I'd then want to switch back into
| | 09:03 | the XIB file, right-click that button
and make sure to delete that entry, the
| | 09:10 | connection that it's trying
to do to a nonexistent action.
| | 09:14 | So be careful when you're doing this.
| | 09:16 | In fact, sometimes if you're just
creating an interface, it's actually better
| | 09:20 | just to delete that button and
drag it on and start all over again.
| | 09:26 | And that's really the key issue here.
| | 09:28 | If you are using that Ctrl-drag method,
when you do that always pause for a
| | 09:34 | second, look at this pop-up window,
make sure is it an outlet that I want or is
| | 09:38 | it an action that I want.
| | 09:40 | Not only that, but when you're working
with Outlets make sure that the Type is
| | 09:45 | correct, that it's what you're
expecting to see, an NSButton or a Text field.
| | 09:50 | It's very easy, for example, to
accidentally drag from the Window or to
| | 09:55 | actually drag from some of what are
called the Layout Constraints that are
| | 09:59 | helping us set out our interface.
| | 10:01 | We'll get into that one a little bit more later.
But just pause for a second on that pop-up.
| | 10:05 | Is it the right kind of Outlet or Action?
What's it called and is it the right kind of object?
| | Collapse this transcript |
| Creating custom controller classes| 00:00 | We haven't written a lot of code yet,
but what we have written, we have put all
| | 00:04 | in the existing AppDelegate class just
because that class was there already.
| | 00:08 | I have a very simple, straightforward
interface here with one-button.
| | 00:12 | If I right-click the button, or use the
Connections Inspector, I can see that
| | 00:17 | the target of this button click is App
Delegate, and the action it will perform
| | 00:21 | is simpleMethod. And just jumping over into
that in the AppDelegate implementation file,
| | 00:27 | all that's going to do is, in NSLog
message to the console, to the debug area.
| | 00:32 | So if I run it, I would expect that
when I click the button, I will just have
| | 00:37 | the debug area appear, and
we'll get that message popping up.
| | 00:40 | All right, but what I prefer is to
have the AppDelegate act just as the
| | 00:44 | application delegate, and I want to
have a dedicated controller class where I
| | 00:49 | write my code that reacts and behaves
and interacts with the interface, and it
| | 00:54 | is very simple to do this.
| | 00:56 | So I will just stop the running program
and jump back over here into my project.
| | 01:00 | And here is the thing, to create a
CustomController class it doesn't have to be
| | 01:05 | anything special, any particular
kind of subclass. Just a regular plain
| | 01:09 | Objective-C class will work.
| | 01:11 | So in Xcode, I am going to go the
New > File section, select Cocoa and
| | 01:16 | Objective-C class, it actually
wouldn't really matter if you are under Cocoa
| | 01:20 | Touch, the basic Objective-C
class is the same for both.
| | 01:23 | Selecting that, I click Next, I
will call this Class MyController.
| | 01:28 | I could call it anything, the name is
not important. The dropdown box beneath
| | 01:32 | gives us many different classes we
could inherit from, but I'm just going to
| | 01:36 | select NSObject right at the top, the
most basic Objectives-C class there is, and
| | 01:41 | then choose to save that in my project.
| | 01:44 | So the class exists, there is nothing
in it, nothing in the header, nothing
| | 01:48 | in the Implementation file, and the
XIB, the interface does not know about
| | 01:52 | this class, there is no link between this
and the MyController class, so let's make one.
| | 01:57 | Here is the easiest and best way to do it.
| | 01:59 | I am going to open up the Utilities
panel and go to my Object Library, now I
| | 02:04 | could scroll down and find the thing
that I want here, but it's easier just to
| | 02:08 | filter on the objects and
controllers section of that Object Library.
| | 02:13 | Usually, what we use the Object Library
for is for dragging and dropping things
| | 02:17 | like buttons and text fields and
sliders, but we can also use it to represent
| | 02:22 | non-visual elements, in this case an Object.
| | 02:25 | So I am going to grab this Object, blue
box, but instead of dragging onto the
| | 02:29 | interface, I am going to drag it over
here into the Dock just right at the
| | 02:33 | bottom here, and I can do this
whether the Dock is expanded or collapsed.
| | 02:37 | Usually, we drag on these visual UI
elements, that means that any user interface
| | 02:42 | element, any object we drag into this
XIB will be instantiated when this program
| | 02:47 | loads, but we can do this with any
object, including a class we just wrote
| | 02:51 | ourselves, that means I won't have
to write a manual alloc and init to
| | 02:55 | instantiate that MyController object. It will
happen here, however, I need to do one more thing.
| | 03:01 | Dragging on the blue object is the
easy part, and the next thing is easy too.
| | 03:06 | But this is the important part, with
Object selected, I want to go to the third
| | 03:11 | inspector in my Inspector section,
which is the identity inspector.
| | 03:16 | Because just by dragging this on from the
Object Library, it thinks it's an NSObject.
| | 03:20 | Well I don't need it to be an NSObject,
I need it to be a new instance of the
| | 03:25 | MyController object that I had, I
should be able to type in--there we go--M, and
| | 03:30 | find it, and just hit Return to set that.
| | 03:33 | Now if I mouse over it, this is what
I'd expect to see, MyController, and now
| | 03:38 | when the main menus xip is loaded,
it will create an instance of this
| | 03:41 | MyController class just as it creates
an instance of all the visual elements
| | 03:45 | that have been dragged on.
| | 03:46 | I don't need to write code to
instantiate it, it'll just happen.
| | 03:49 | Now I can use this to write code that
interacts with this user interface, so I
| | 03:53 | am going to drag on another button
onto this interface here, onto the Window.
| | 03:59 | Just give it a basic name change, and
then give myself a bit more screen real
| | 04:05 | estate so that I can open
up the Assistant Editor.
| | 04:09 | Now bear in mind now that the
counterpart of this XIB file could be multiple
| | 04:15 | code files, so you will probably
need to use the Jump bar to change to a
| | 04:19 | different one, in my case I want to
jump to the MyController.h, the header file
| | 04:23 | here, and now I should be able to hit
the Ctrl key and drag into this new class.
| | 04:30 | It's going to pop up.
Do you want to make an Outlet or an Action?
| | 04:34 | I want to do an Action here for sure.
What do I want this to be called?
| | 04:38 | Well, I will also call this
simpleMethod, I could actually use the same name
| | 04:42 | that was in the other class, it
doesn't matter, they are completely
| | 04:45 | independent of each other.
| | 04:46 | Click Connect, and we get the
simpleMethod declaration in the header file, but
| | 04:50 | if I also a jump over into the
implementation file, I'll see the method stub
| | 04:54 | over there, and I will just put
an NSLog message in that one too.
| | 05:03 | So just to verify this, right
clicking that new button will say that we are
| | 05:08 | going to the target of MyController,
calling the simpleMethod as an Action.
| | 05:13 | And in this one, we are doing
AppDelegate as a target and doing simpleMethod
| | 05:18 | there as an Action.
Go ahead and run this, Build Succeeded.
| | 05:23 | I can call the first one, to Call a
method in AppDelegate class, and I can call
| | 05:28 | the second one to run code
in the new MyController class.
| | 05:31 | So very easy to start to break this out,
it would be very simple for me now to
| | 05:35 | copy any of the methods that I might
have put in AppDelegate and move them
| | 05:39 | across to the new class, if I wanted
to keep them separate from each other.
| | 05:43 | And if it made sense, I could
even add more controller classes
| | Collapse this transcript |
| Creating alert panels and alert sheets| 00:00 | One of the first questions I'm often
asked is how do I get Cocoa to pop up what
| | 00:05 | might be called a message box, or
an alert box, in other languages?
| | 00:08 | I am going to make a new Cocoa
Application--because it is an alert that we are
| | 00:13 | dealing with--this can either be done
as what's called an Alert Panel, or an
| | 00:16 | Alert Sheet, and I will show you both.
| | 00:18 | I will just Save that to my Desktop.
And all I'm going to do is create a very
| | 00:23 | straightforward application
with a couple of buttons on it.
| | 00:26 | I am doing this from scratch again
just so we're getting into that habit of
| | 00:31 | dragging on buttons and
connecting them to our code.
| | 00:37 | First one will cause an Alert Panel,
and then we'll do another one, which will
| | 00:41 | cause an Alert Sheet--and I don't really
need so big a user interface here, so I
| | 00:48 | will just shrink this one down.
| | 00:49 | Of course, these buttons right now
aren't doing anything, and I want them to, so
| | 00:54 | I'm going to switch into the
Assistant view, and hopefully we are seeing
| | 00:59 | AppDelegate.h, if not, we can just
select it from the Jump bar. And first I'm
| | 01:04 | going to grab on the Alert Panel
button and make it cause an Action.
| | 01:08 | So when the pop-up appears, I want to
make sure it's causing an Action here.
| | 01:12 | I will say this one is createAlertPanel.
| | 01:18 | And I will set up the second one here
to call another IBAction, in this case
| | 01:22 | createAlertSheet--it
nearly created an Outlet there.
| | 01:27 | So an IBAction createAlertSheet.
| | 01:33 | Now I am going to switch back into
the Standard Editor, so I can see a bit
| | 01:37 | more here, and I can either use the
navigator or the Jump bar here just to
| | 01:41 | switch to that code.
| | 01:42 | I'm interested in being in the
Implementation file here, the .m file for AppDelegate.
| | 01:47 | So in the createAlertPanel method
I'm going to write that C function.
| | 01:52 | The function is called NSRunAlertPanel,
and as I type, I can see it appear in
| | 01:58 | code sense, I am going to hit Tab. This
takes several different arguments, which
| | 02:03 | can all be put as NSStrings, the
Title, the Message, the Name of the
| | 02:08 | defaultButton, the alternateButton, an
otherButton, and then a possible list of
| | 02:13 | arguments, and we will see
what that's for in a moment.
| | 02:16 | So I am just going to
give it a bunch of NSStrings.
| | 02:19 | First one for Title, then hit Tab.
Then the string for the defaultButton.
| | 02:27 | I will just say, OK.
| | 02:30 | The alternateButton, I will just call
it Alternate, so it's obvious which one
| | 02:34 | that is when we see it, and then the
otherButton, and that will do the trick.
| | 02:39 | Now we are going to have to add a little
bit more to this, but let's just see it work.
| | 02:44 | I will go ahead and click Run, I am
going to click the Alert Panel button, and
| | 02:50 | we get the Basic alert message.
| | 02:52 | Title, Message, and the
three buttons that we listed.
| | 02:55 | Now this function is completely modal
and is blocking the application, so it
| | 03:00 | will not let me start to click
anything on the application behind it, until I
| | 03:04 | deal with this modal window, but they
are done as completely separate windows.
| | 03:10 | I will just click OK.
| | 03:12 | Now this function actually returns a
value of type NSInteger, so if I wanted to
| | 03:19 | find out what that was, I would just
create, say, NSInteger result, and get that
| | 03:23 | back as the result of that. And let's
just write it out in an NSLog message.
| | 03:33 | This is an NSInteger, which is a long integer,
so I'll put the li, as the format specifier.
| | 03:37 | And now when I run it,
I should see the message pop up.
| | 03:43 | If I click OK, we are
going to see the result is 1.
| | 03:48 | It actually returns an NSInteger that
can be treated as an enumeration, but
| | 03:52 | it's really just returning 1, 0, or -1, for
the defaultButton, the alternateButton,
| | 03:58 | or the otherButton.
| | 03:59 | Now if you don't want to show all of
the buttons, for example, you just want
| | 04:03 | the default one and the other one. You
can just use the word nil in place of
| | 04:08 | that NSString argument, and running this again,
the Alert Panel just has the two buttons on it.
| | 04:14 | Now the second parameter that we are
seeing here, the Basic alert message can
| | 04:20 | take a format string with format
specifiers. So we can enter in, for example, %
| | 04:25 | sign, @ sign to represent a couple of
objects at say two different places, it
| | 04:30 | can be 1, can be 2, it
can be a dozen if you want.
| | 04:33 | Then what you need to do is actually
follow the very last button argument with
| | 04:38 | your list of, in this case, objects.
| | 04:41 | I will just give it two
separate NSString objects.
| | 04:46 | We Save that, and run it again, and we
should see those placed into that message.
| | 04:51 | There we go, Basic First alert Second message.
| | 04:55 | That's about as complex as
the NSRunAlertPanel gets.
| | 04:59 | We can also do this alert as an
Alert sheet, rather than an Alert panel.
| | 05:04 | The difference being that a sheet is
an attached to an existing window. And that's,
| | 05:09 | strictly speaking, one of the ways
that's more officially approved by Apple.
| | 05:13 | Creating a sheet is more powerful,
but it's a little bit more involved.
| | 05:18 | So I am going to do that in the
second method here in createAlertSheet.
| | 05:23 | This I am going to do by creating a
Objective-C object called an NSAlert.
| | 05:29 | I'll call this myAlert.
| | 05:30 | We don't do this typically with the
usual alloc and init, we actually create an
| | 05:36 | NSAlert the way we might create an
NSDate by calling a static or shared
| | 05:42 | function on the object.
| | 05:43 | What does that mean?
Well, really this is the way we do it.
| | 05:47 | NSAlert, alertWith--and we get two options--
this is probably the classic one here.
| | 05:52 | Create an alert with a
certain MessageText, defaultButton,
| | 05:57 | alternateButton, otherButton informativeText.
| | 06:00 | It's very similar in essence to the
NSRunAlertPanel, we are loading it up with
| | 06:06 | the different things that
an Alert panel needs to show.
| | 06:10 | So I will just use my Tab button and
quickly go through and add some content
| | 06:14 | here, defaultButton is OK,
alternateButton I will once again call Alternate, to
| | 06:23 | make it obvious what it is.
| | 06:27 | And the last one here can also be a
format string with format specifiers, the
| | 06:32 | same way that the second
argument could be in NSRunAlertPanel.
| | 06:36 | This seems a bit more natural to put it
at the end if you're going to follow it
| | 06:39 | with optional arguments.
| | 06:45 | To make it easy, right now, I'm not going
to bother giving it any alternate arguments.
| | 06:49 | I am just going to use it as a regular string.
| | 06:52 | So this creates that object, but
we are not doing anything with it.
| | 06:56 | There is a very simple way to do this,
which is, we call the myAlert runModal
| | 07:00 | method, and I will just show you what
that does, which is almost identical as
| | 07:06 | the NSRunAlertPanel, as a
very separate Modal Window.
| | 07:13 | Quitting out of the application, I will
go and show you the recommended way to
| | 07:17 | do that, which is a more complex,
more involved, but more powerful method.
| | 07:21 | Instead of runModal, we are calling
beginSheetModalForWindow, and we have to
| | 07:27 | give it multiple arguments here.
First, what window are we attaching this to?
| | 07:31 | This is going to be a sheet,
meaning it's attached to a window.
| | 07:34 | Well, we are in the AppDelegate,
which has a property internally, which is
| | 07:40 | _window, which is the current window
that we are looking at of the application.
| | 07:43 | Now what I am going to do right now is
just pass in nil, as the remaining three
| | 07:48 | arguments, simply because we haven't
really gotten into delegation and selectors
| | 07:52 | yet, and we will see that a little later on.
| | 07:55 | Because this beginSheetModalForWindow
method does not immediately return a
| | 08:00 | value, but can call a delegate method
when somebody clicks one of the buttons.
| | 08:04 | So I am going to run this,
and we'll see the difference.
| | 08:07 | Here is the first way, the Alert Panel,
the separate window that's modal, and
| | 08:13 | here's the second way, the Alert
Sheet, attached to the main application,
| | 08:18 | still modal, and that I have to deal with it,
but this is the more recommended way by Apple now.
| | 08:25 | I'll quit and go back to the code, but
of course, this begs a few questions.
| | 08:29 | What are these remaining arguments,
like modalDelegate and didEndSelector?
| | 08:34 | Well we need to talk a little bit about
things like delegation, to really get
| | 08:38 | into the power of these kind of methods.
| | Collapse this transcript |
|
|
3. DelegationUnderstanding delegation| 00:00 | Like Model-view controller,
Delegation is one of the core design patterns,
| | 00:04 | one of the core ideas in Apple development,
and all Cocoa applications use delegation.
| | 00:10 | We are already doing it with the
AppDelegate, but that was provided for us,
| | 00:14 | that doesn't really count.
| | 00:15 | We are going to use
delegation in other places too.
| | 00:18 | Its how you accomplish tasks in Cocoa,
that in other languages you might do with
| | 00:23 | inheritance, or event handling. It's important.
But what does it mean?
| | 00:28 | Well, I like to say that a delegate in
Cocoa development is like the idea of a
| | 00:32 | delegate in real life.
| | 00:33 | If you look up the dictionary
definition of a delegate in politics or in
| | 00:37 | business, it's someone who
acts on behalf of somebody else.
| | 00:41 | And to delegate is a formal way that one
person hands-off responsibilities to another person.
| | 00:47 | Now for us developers, it's a formal way
that one object hands-off work to another object.
| | 00:54 | An object in Cocoa, often a built-in
object, including many of the user
| | 00:59 | interface elements, or even the application object
itself, has a lot of it's own internal processing.
| | 01:06 | But it can also be connected to
your objects, your custom classes.
| | 01:11 | And it can delegate other
responsibilities to them.
| | 01:15 | So instead of, say, subclassing an
application object, or subclassing a text field,
| | 01:21 | you create a new object connected as
a delegate, and then you can get that
| | 01:25 | original object to delegate behavior to
send behavior over to your custom class.
| | 01:31 | We refer to the object who is being
handed the work as the delegate, and it's
| | 01:36 | being handed the work by the delegating object.
| | 01:38 | So how do we do this? Well, how to be a
great delegate in Cocoa is like being a
| | 01:44 | formal delegate in business or in politics.
| | 01:46 | There are rules, there are steps, and
step one is know the rules. Know what you
| | 01:50 | have to do, what are the
responsibilities in that role.
| | 01:53 | And this is not casual.
| | 01:55 | If you want to be an official delegate
for a political party, or government, or
| | 01:59 | royalty, it often means there are formal
documents that describe exactly what is
| | 02:04 | expected of that delegate in that role.
| | 02:07 | Step two is to say, well I can do that,
this is where you are volunteering, you're
| | 02:12 | putting your hand up.
| | 02:13 | Now step three is that you need
to have a plan to actually do it.
| | 02:17 | If you are going to volunteer to be a
delegate, you better be able to follow through.
| | 02:21 | And step four, even after deciding,
even after planning how you are going to
| | 02:26 | approach this, you need to get the job of
the delegate to make sure you are in that role.
| | 02:31 | That whoever is handing those
responsibilities out is going to give them to you
| | 02:35 | and not to somebody else.
| | 02:37 | So if these are the four steps of how
to be a delegate in real life.
| | 02:41 | What is it in Cocoa development?
Well, exactly the same thing.
| | 02:45 | Step one is know the rules,
know what you have to do.
| | 02:50 | There are simple rules here, and in
Apple development the rules are called
| | 02:53 | the Delegate Protocol.
| | 02:55 | And there are different Delegate
Protocols for different objects that
| | 02:59 | can delegate behavior.
| | 03:00 | And each Delegate Protocol can be found
in the Xcode documentation, it's simply
| | 03:06 | a short list of method names,
no behavior just method names.
| | 03:12 | Basically saying, if you want to
write a custom class and be a delegate for
| | 03:16 | me, these are the behaviors you should
support, and we will see a few examples of these.
| | 03:21 | Step two is to say, I can do that. You
are volunteering, and you are marking
| | 03:26 | yourself as a volunteering.
| | 03:28 | You are being a delegate, not in general,
you are being a delegate for something specific.
| | 03:34 | And what you do in your code is after
the class definition you use the angle
| | 03:39 | brackets, to say in this case, I can be
a delegate for the NSApplication object.
| | 03:45 | So in this case, this declaration says we
are creating a class called AppDelegate.
| | 03:48 | It inherits from NSObject, and it can
act as a delegate for NSApplication.
| | 03:55 | And when creating an object you can mark it
as being a delegate for more than one thing.
| | 03:59 | Now step three is, have a plan.
| | 04:02 | That means you need to look at the
Delegate Protocol rules and implement
| | 04:06 | the necessary methods.
| | 04:08 | Create methods in your class that match
the method names in the Delegate Protocol.
| | 04:14 | And what you write in
your code must exactly match.
| | 04:17 | And step four then get the job.
| | 04:20 | Marking your class as
being a delegate isn't enough.
| | 04:23 | Implementing those methods isn't enough
because what ever object is handing
| | 04:29 | those responsibilities out, they are
delegating object that's handing them off,
| | 04:32 | needs to give them to give your
class and not to some other class.
| | 04:36 | So you're telling the object that's
delegating who it should delegate to.
| | 04:40 | Now this can sometimes be done in the
Xcode visually, it can actually connect a
| | 04:45 | delegate of one object to a custom
class, but it's also often done in code.
| | 04:51 | There is often a delegate property of one
object that can be set to another object.
| | 04:56 | Now if it your first time coming across
these concepts, you will probably still
| | 05:00 | sounds a little confusing.
| | 05:01 | But like being a delegate in business,
or in government, in all likelihood, you
| | 05:07 | would begin by having someone show you
around and walk you through a couple of examples.
| | 05:13 | And we're going to go through that
course, and that's someone's going to be me,
| | 05:16 | and I will walk you through a
couple of delegation examples.
| | Collapse this transcript |
| Using the application delegate| 00:00 | We are always using Delegation. Even if
I create a new Cocoa application right
| | 00:05 | out of the box in Xcode,
we are using it already.
| | 00:09 | And not surprisingly, the most
obvious example of delegation that's already
| | 00:14 | there is the AppDelegate class.
| | 00:16 | Now the actual name of this
class is not important at all.
| | 00:20 | This is a regular Objective-C class.
| | 00:23 | If we look at the header file for it,
we are just inheriting from NSObject.
| | 00:26 | But it has two things that are special about it.
| | 00:30 | After NSObject we use the angle
brackets to say, well I might be a regular
| | 00:35 | object but can also be a
delegate for NSApplication.
| | 00:39 | That means, an NSApplication object can pass
behavior to this object, if it knows it exists.
| | 00:45 | And this is one of the biggest
differences between Cocoa, and Desktop
| | 00:48 | Development on other platforms.
| | 00:51 | In Cocoa, we don't subclass an
existing application class and extend it.
| | 00:55 | We just let the regular built-in
NSApplication object, do what it does naturally,
| | 01:00 | but we create a completely separate
class to provide any extra behavior, and
| | 01:05 | that's the idea of a delegate.
| | 01:07 | Okay, so what does this mean and what can
we do if we say we're in NSApplicationDelegate?
| | 01:15 | Well, to find out, we read the rules.
| | 01:16 | So with this selected if I have my
Quick Help inspector here, I'll get a bit
| | 01:21 | of information about it that
NSApplicationDelegate points to the
| | 01:24 | NSApplicationDelegate Protocol Reference.
| | 01:27 | This is the list of rules
that we are supposed to support.
| | 01:30 | So I am going to find out what the
possibilities are if we volunteer this class
| | 01:34 | as being a delegate for an NSApplication object.
| | 01:37 | Now Protocol Reference is just a list
of method signatures, the names, the
| | 01:42 | return type, the parameters. No behavior,
no implementation, just a list of methods.
| | 01:48 | So as I come down here we see, I
have got a bunch of Tasks,
| | 01:52 | Launching Applications,
applicationWillFinishLaunching, applicationDidFinishLaunching,
| | 01:57 | applicationShouldTerminate or WillTerminate.
| | 02:00 | Various ones for hiding the
application that it will hide or it did hide.
| | 02:05 | Managing the Dock Menu.
| | 02:07 | And if we are a delegate for NSApplication,
we can choose to respond to any of these.
| | 02:13 | We don't have to answer to all of them.
| | 02:15 | We make our own mind up
about which ones are important.
| | 02:19 | Now it is important to understand
that this is not like inheritance.
| | 02:21 | We are not overwriting some
default behavior in NSApplication.
| | 02:26 | If we don't implement certain of these
methods in our AppDelegate, it doesn't
| | 02:31 | matter they are just ignored.
| | 02:32 | Now what I can do when I'm looking at
this set of rules is I can find out a
| | 02:37 | little bit more information about each of these.
| | 02:39 | Say, for example, I am curious about
applicationWillBecomeActive I will click that link.
| | 02:44 | And it just tells me a little more
sent by the default notification center
| | 02:48 | immediately before the application
becomes active, little bit cryptic but we'll
| | 02:53 | see what this means.
Here's how we would support it.
| | 02:55 | I will look at this information, and it
tells me the signature that this needs
| | 03:00 | to be a method that's void, called
applicationWillBecomeActive, and it takes one
| | 03:04 | parameter of type NSNotification.
| | 03:07 | I am just going to highlight that line,
copy it, jump back into Xcode, and in the
| | 03:13 | implementation of my AppDelegate,
I am going to paste it in there.
| | 03:16 | And this is a method so it obviously
needs the opening and closing curly braces.
| | 03:22 | And all I'm going to do in here
is put in a simple NSlog message.
| | 03:27 | And then hit Command+R to run the application.
| | 03:30 | What I can see happening in the console
is that message popped up, Application
| | 03:34 | will become active,
doesn't seem very impressive.
| | 03:38 | But here's the difference.
| | 03:39 | If I switch back at Xcode, then hit my
Command and Tab and switch back again,
| | 03:44 | what we're seeing is by switching back
and forth between the applications, that
| | 03:49 | method is automatically being called
every time we make this application active
| | 03:53 | when it's gets the focus.
| | 03:55 | Now that may or may not be something
that you're interested in, quitting out of
| | 03:59 | this and back into Xcode.
But that's the point of delegation.
| | 04:03 | We get to choose what parts
of it we are interested in.
| | 04:07 | When we act as a delegate, and I'm
jumping back here into the Delegate Protocol,
| | 04:12 | we choose the methods we want to respond to.
| | 04:14 | Now sometimes certain delegate
methods will be marked as required, and if
| | 04:18 | you say you're going to be a
delegate for a particular class, you are
| | 04:22 | supposed to put them in.
But otherwise, they're optional.
| | 04:24 | You use the ones you need you ignore the rest.
| | 04:27 | Now one thing you might be curious all
is well, I'm being a delegate I can put
| | 04:32 | in this method, and it will automatically work.
| | 04:34 | It will get called automatically
by the system at the right time.
| | 04:38 | But don't I have to put
something in the header file?
| | 04:40 | No we don't, that's taken care of by the fact
that we formerly say we're an NSApplication delegate.
| | 04:46 | That means we don't have to declare
the signatures of these methods in our
| | 04:50 | header file, we simply put the ones we are
interested in into our implementation file.
| | 04:55 | And when you create a Cocoa application
in Xcode, the one bit of code you do get
| | 05:00 | inside the AppDelegate is the
applicationDidFinishLaunching.
| | 05:04 | This is another delegate
method of the NSApplication class.
| | 05:09 | It's probably the most common one which
is why it's there in the skeleton code
| | 05:13 | that's provided, but you can use any of them.
But of course, this AppDelegate example is easy.
| | 05:20 | It's already here, it's already hooked up.
| | 05:22 | And it's a good example to get started with,
but it is a very substantial object.
| | 05:28 | All these methods are very large scale,
the application beginning and ending,
| | 05:32 | switching focus, switching back.
| | 05:34 | But delegation doesn't
have to be quite so impactful.
| | 05:38 | Sometimes it's used for just a small
piece of optional behavior, as we'll see
| | 05:42 | when using delegation with
some user interface elements.
| | Collapse this transcript |
| Delegation for UI elements| 00:00 | When you get comfortable with the
basic concept of delegation you'll find
| | 00:04 | yourself able to join in everywhere.
| | 00:07 | For example, several of the regular
user interface elements in Cocoa can
| | 00:11 | delegate some behavior if we
find it useful we can support that.
| | 00:15 | I will just create a brand-new Cocoa
application, save it, and jump into the XIB file.
| | 00:21 | And select the Window just so we
have something we can drop controls onto.
| | 00:26 | So there is a question. How would you
know if a user interface element has some
| | 00:31 | behavior it's able to delegate?
Well, here is one simple way.
| | 00:35 | You grab one of these UI elements out of the
library, and you drop it onto your interface.
| | 00:40 | I am going to drag on a button.
| | 00:42 | I'll come down a little bit and
find say a text field and drag that on.
| | 00:47 | Coming down a bit further, I will drag on
a combo box, and a Date Picker.
| | 00:54 | Just four fairly typical user interface elements.
| | 00:56 | Now here's what I want to do as a
clue to find out if they can delegate
| | 01:01 | any behavior or not.
| | 01:02 | I am going to go into my Inspector
section and open up the Connections Inspector,
| | 01:07 | which is the sixth one in the list here.
| | 01:10 | All I'm doing here is scanning
the section that says outlets.
| | 01:13 | I have currently got the Date Picker
selected, and I don't see anything that
| | 01:18 | says the word delegate.
| | 01:19 | If I highlight the combo box I am going to
see that I do have an entry for delegate.
| | 01:25 | If I select the button I
don't have an entry for delegate.
| | 01:28 | If I select the text field I
do have an entry for delegate.
| | 01:32 | What you will find is that if there is
a delegate outlet for a user interface
| | 01:36 | control then that control can
delegate some kind of behavior.
| | 01:40 | Now we don't know what.
| | 01:41 | We need to look at the details
of this specific class for that.
| | 01:45 | Just because a user interface control
can delegate some behavior it does not
| | 01:50 | mean we have to respond to that.
| | 01:52 | But if we want to, we want to find out
how to, here is one way to go about it.
| | 01:56 | Again, we said there was multiple
steps for being a delegate and step one
| | 02:01 | is know the rules.
| | 02:02 | So I am going to work with this combo
box here, and I'll just delete the others
| | 02:07 | to give us some clarity
about what we are actually doing.
| | 02:11 | Combo box is a very simple control in
Cocoa, if I by jump into my Attributes
| | 02:16 | Inspector I can find that this combo box
allows me to just add a few different items.
| | 02:20 | I am going to click the Plus button
three times and then double-click.
| | 02:25 | We will see later how to start adding a
bit more dynamic data into one of these.
| | 02:30 | I just need something simple right now.
| | 02:32 | So we saw that in this Connections
Inspector the combo box has a delegate outlet.
| | 02:37 | It can delegate something,
but I don't know what.
| | 02:39 | Well, how do we find this out?
| | 02:41 | I am going to jump into the Quick Help
Inspector here, and if that sometimes
| | 02:46 | happens Quick Help doesn't actually show
you the information you'd expect to see
| | 02:51 | I can always type in NSComboBox in
the Help menu and actually search that.
| | 02:56 | I can jump first to the NSComboBox
class reference, but if I look at the
| | 03:01 | search results here, I can immediately
jump to the fact that I have got the
| | 03:05 | NSComboBox delegate protocol reference.
What are the rules to be a delegate
| | 03:09 | for the NSComboBox?
Again, it's just a list of methods.
| | 03:13 | In fact, we see there really are only
four of them, comboBoxSelectionDidChange,
| | 03:19 | comboBoxSelectionIsChanging,
comboBoxWillDismiss, and comboBoxWillPopUp.
| | 03:25 | None of them are marked as required.
| | 03:28 | It's our choice of which
ones we want to respond to.
| | 03:32 | Technically speaking, we don't have to
respond to any of them, but if we are
| | 03:36 | going to be a delegate
we want to pick something.
| | 03:38 | So I am going to click on
comboBoxSelectionDidChange.
| | 03:42 | This just takes us to the method signature, returns
void, takes one parameter of type NSNotification.
| | 03:49 | So I'll copy that entire line.
Question is where am I going to respond to this?
| | 03:56 | Even if I know the rules I
need something to volunteer.
| | 03:59 | I need a class to say, yes, I am going
to be the delegate for that combo box.
| | 04:03 | I could create a brand-new class to do
it or, seeing as time of the essence, I am
| | 04:08 | just going to use AppDelegate.
| | 04:09 | AppDelegate is already volunteering
to be a delegate for the NSApplication.
| | 04:14 | It is the AppDelegate, but inside
these angle brackets what I can do is mark
| | 04:20 | this as also being an NSComboBoxDelegate.
| | 04:27 | This is the official way we are
volunteering this class and saying, we are
| | 04:30 | capable of being a delegate for an NSComboBox.
| | 04:32 | It will often work without this, but I
think it's always a good idea to do it.
| | 04:38 | This same class is now a delegate for
both the NSApplication and a delegate
| | 04:42 | for NSComboBox object.
Well step three was, have a plan.
| | 04:47 | So in the implementation of this class
what I'm going to do is paste in that
| | 04:52 | method signature that I just
copied for comboBoxSelectionDidChange.
| | 04:57 | Once again, just put in a simple message
that proves, yes, we actually called this.
| | 05:04 | Now we could right now go ahead and run
this, but this code would never get called.
| | 05:09 | We wouldn't have an error.
We wouldn't have a problem with it.
| | 05:12 | It's all perfectly valid, but
whenever I select one of the options from the
| | 05:17 | combo box I don't get any kind
of message that I'm looking for.
| | 05:21 | I am getting a warning at the moment that
the Content rectangle not entirely on screen.
| | 05:26 | This occasionally happens if you
accidentally nudge something around.
| | 05:30 | What I'm going to do is go back into
the XIB file, and I want to go to the Size
| | 05:35 | Inspector, which is the fifth one, and
just make sure that this is positioned on
| | 05:39 | screen there by dragging it down.
| | 05:41 | Hit Command+B to compile
again, and now I have no issues.
| | 05:46 | The reason that it's not working
yet is I have really done three of the
| | 05:50 | four necessary steps.
| | 05:52 | I read the rules--the Delegate Protocol
Reference--I volunteered my AppDelegate
| | 05:59 | class and said, it's capable of being
a delegate for the combo box, I have my
| | 06:04 | plan in place, which is the code I
wanted to run--if the combo box selection did
| | 06:08 | change--but what I haven't done is
actually tell that combo box where to look
| | 06:14 | for that delegate behavior.
| | 06:15 | That's what I'm going to use
the Connections Inspector for.
| | 06:18 | I could also do this by right-clicking.
| | 06:21 | I'm going to say that the combo box is
delegate, and I will click on the circle
| | 06:25 | beside that delegate outlet and drag it
over to AppDelegate that represents an
| | 06:30 | instance of our App Delegate class. Let go.
It will not pop anything up.
| | 06:36 | It doesn't ask me what method I am
going to call because all I'm doing here is
| | 06:40 | saying the AppDelegate is now
also a delegate for the combo box.
| | 06:44 | This could be done in code, but if were
working with everything having a visual
| | 06:49 | entry in our XIB file we
might as well do it this way.
| | 06:52 | So save that and run it.
| | 06:53 | Not the most exciting user interface in
the world, but now every time I select
| | 06:59 | a new entry, I get the message
popping up down here in the console that the
| | 07:04 | combo box is changing.
| | 07:05 | Now the question might be. What about
actually getting hold of the value of the
| | 07:10 | combo box when we are in that method?
Well, there are two ways of doing this.
| | 07:14 | One is that I would set the
combo box up as an IBOutlet.
| | 07:18 | I didn't do that, but I could do that to
give it a name and then refer to it in my code.
| | 07:23 | The same way we have set up labels
and text fields in earlier examples.
| | 07:28 | Now another way, is that when I get
this delegate method called I am being
| | 07:33 | passed a parameter here, an NSNotification,
and this is true with a lot of delegate methods.
| | 07:40 | We will talk more about notifications
later, but in essence anytime I get passed
| | 07:46 | on, what I am getting is a container
the generic box that holds three things, a
| | 07:51 | name, an object, and optional parameters.
| | 07:54 | The name is, what just happened, and the
object is, what caused that to happen.
| | 07:59 | So I will actually get passed a
reference to the combo box that caused this
| | 08:03 | delegate method to happen.
| | 08:04 | I am actually just going to add a
couple of things to this message here.
| | 08:10 | Adding in two formats specifies for objects
saying the notification was, and what I
| | 08:15 | am going to ask for there is the
notification parameter, that we just got passed,
| | 08:20 | and its property called, name, than a
Comma, and then notification.object.
| | 08:28 | Save that and run it.
| | 08:30 | Every time I change this now what we're
going to get is the message saying the
| | 08:34 | combo box changed, the notification was,
and we actually get the official name
| | 08:39 | of this notification, the
NSComboBoxSelectionDidChange notification and the
| | 08:44 | object was when it's being passed
there is a reference to the NSComboBox.
| | 08:48 | So I can certainly get to that if
I wanted to just in this method.
| | 08:53 | But bear in mind, this example is not
inherently meant to be about the combo box.
| | 08:58 | It's about the process of being able to
look up whether a user interface element
| | 09:03 | can cause some delegation of behavior,
what that behavior would be, how you
| | 09:08 | would support it, and how you
would connect them together.
| | 09:11 | Do you remember that just because a UI
object can delegate this behavior doesn't
| | 09:15 | mean you have to support it?
In many cases you won't need to.
| | 09:19 | There is more potential delegation
going on in a Cocoa application than you
| | 09:23 | would possibly want to deal with.
| | 09:25 | You decide where you want to join in
and what you want to react to by slowly
| | 09:29 | becoming familiar with what
objects can delegate what behavior.
| | Collapse this transcript |
| Delegation for simple objects| 00:00 | Here is one more use of delegation.
| | 00:03 | Sometimes we create a quick and almost
informal object that can use delegation
| | 00:07 | and just use it on an as needed basis.
| | 00:10 | Now, I'm going to do this example
completely in code, there will be nothing to
| | 00:13 | drag and drop, really nothing
in interface builder at all.
| | 00:16 | I am just showing I have a very basic
example, one button application that does
| | 00:21 | something we saw a little earlier.
| | 00:23 | This is calling a method in my AppDelegate
that is going to create an NSAlert object.
| | 00:28 | I am just going to widen this so we
have a bit more screen real estate here.
| | 00:33 | So in Line 12 we create a new
NSAlert object, loading it up with some
| | 00:37 | basic text, Alert Message, OK, an
Alternate button, and another button, and
| | 00:41 | some informative text.
| | 00:43 | And then on Line 19 we call its method
beginSheetModalForWindow: modalDelegate: didEndSelector:
| | 00:53 | contextInfo, a rather long-winded name.
But what it means is it's going to pop
| | 00:59 | up this as a sheet, it's going to
be attached to the underlying window.
| | 01:03 | I am just going to comment out Line
24, which is changing the background
| | 01:06 | color of the window itself, and go
ahead and run this just to remind us of
| | 01:10 | what it looked like.
| | 01:12 | We create an alert sheet which
attaches that alert to the window itself.
| | 01:17 | Nothing particularly remarkable.
| | 01:20 | Now, earlier we saw a way of
creating an alert panel, a separate panel by
| | 01:24 | calling a C function that
returned an integer value.
| | 01:29 | But here's the problem, this
beginSheetModalForWindow method doesn't return
| | 01:35 | a value, it is void, it doesn't return
anything. Not only that, it doesn't actually block.
| | 01:40 | Meaning, we immediately
continue and do code that's after it.
| | 01:44 | So if I wanted to try and say, well,
give me a return code and deal with it, I
| | 01:49 | don't have a return code yet.
| | 01:50 | To prove this, I am going to uncomment
that line that changes the background
| | 01:54 | color and run this again. And we will
see that immediately after this alert
| | 01:57 | sheet is popped up, we continue on
and do whatever code was after that.
| | 02:01 | So what's actually happening is
that modalSheet is being popped up
| | 02:05 | asynchronously on a different thread.
| | 02:07 | So the question is how do I
find out what button got pressed?
| | 02:11 | Well, to actually receive any
value back from that, we need to use a
| | 02:15 | little delegation, because if we look here,
this method takes an argument called modalDelegate.
| | 02:22 | What this means is this method wants
to know where to delegate some behavior
| | 02:26 | after this modalWindow is dismissed.
| | 02:28 | It wants an object to delegate to, and
it wants a method, which is the next one,
| | 02:34 | the didEndSelector argument.
| | 02:36 | A selector is Cocoa's way of letting
us pass a method name as a parameter.
| | 02:41 | And the didEndSelector entry here is
asking what selector, what method should
| | 02:47 | this Delegate object call when this window ends?
| | 02:50 | Now, you might think, well, am I
supposed to figure this all out for myself?
| | 02:54 | Well no, not really. What we can do
is do an either Option-click, or use the
| | 02:59 | Quick Help, to find some
information about this method.
| | 03:02 | This method is contained in part of the
NSAlert, so we could look at the NSAlert
| | 03:07 | Class Reference to get a little
bit more information about it.
| | 03:10 | And what it's telling us is
this rather long-winded method,
| | 03:15 | beginSheetModalForWindow, will pop up
this alert sheet, but it can call something
| | 03:20 | back, it's got an alertDidEndSelector argument.
| | 03:24 | Like a lot of delegation, one of the
big deals here is we really want to copy
| | 03:28 | this argument signature.
| | 03:30 | What I am going to do is copy this.
I need to paste it into a piece of code.
| | 03:36 | Again, for our purposes, just to be
kind of quick about this, I am going to
| | 03:40 | use the same class, the AppDelegate,
and I will paste this beneath the
| | 03:43 | createAlertSheet method, but before the @end,
doesn't really matter where you put it.
| | 03:50 | What is this?
| | 03:51 | Well, this method we are going to want
to call after somebody clicks a button in
| | 03:56 | that modalWindow, whether that's
two seconds later or two days later.
| | 04:01 | We are getting the signature of this
method from the NSAlert object itself.
| | 04:06 | And we will repass a
NSInteger called returnCode.
| | 04:13 | I am going to construct an NSLog
message here with a format specifier,
| | 04:17 | returnCode is NSInteger, so I'll use %li.
| | 04:19 | Now just having this method is not
going to do anything for us right now, I
| | 04:26 | could run this again, and it would make
no difference whatsoever, because we're
| | 04:30 | not actually telling the
modalWindow to call this back.
| | 04:34 | What we need to do is stop some
of these arguments from being nil.
| | 04:38 | We need to say, when this
modalSheet is dismissed, we want to call this
| | 04:42 | particular delegate
calling this particular selector.
| | 04:44 | Well, how do we do it?
Watch the delegate.
| | 04:47 | Well, what I want to do is have a
delegate that's the current object, the actual
| | 04:52 | AppDelegate that I am
looking at right now, this code.
| | 04:54 | And the way we are going to do this
might be the word, this, in other languages,
| | 04:59 | in Objective-C it's, self.
| | 05:01 | We have created this new alert object,
we are popping it up, and we are saying,
| | 05:06 | hey, your delegate is me,
you are going to call me back.
| | 05:09 | And in the next argument I say, what
part of me, what part of the AppDelegate
| | 05:13 | are you going to call, which is the selector.
| | 05:16 | This is the way that we write a
selector in Objective-C so we can pass the name
| | 05:21 | of a method as a parameter.
| | 05:24 | So it's the @selector keyword, and then
in brackets, the actual method name with
| | 05:29 | no parameters just the
colons for each individual part.
| | 05:32 | In our case it's the alertDidEnd, as I
start typing it, it should pop-up, that
| | 05:37 | will work, alertDidEnd:returnCode:contextInfo.
| | 05:43 | Now, contextInfo is just here
being basically an open-ended object.
| | 05:46 | It means we can call this method, we
can pass in an object of contextInfo, and
| | 05:51 | when we get call back, we will
get that same object passed back.
| | 05:56 | I am not going to use it right now so I
am going to leave that argument as nil.
| | 06:00 | So we will pop up that modalSheet
saying that your delegate itself, the
| | 06:04 | AppDelegate class, that the selector
you call is the alertDidEnd method, and
| | 06:08 | let's see what happens. We run it.
| | 06:12 | I should of course expect that it
will pop up that, it will change the
| | 06:15 | background, that's fine, but whenever
we click this we should expect to see the
| | 06:20 | log message come up here, the return code was 1.
| | 06:22 | If I click it again and click the
other, I will see -1, and if I click the
| | 06:27 | alternate button, I should see 0. There we go.
| | 06:32 | So another free form simple
code based used of delegation.
| | 06:37 | In other languages the equivalent
idea of a selector would be a function
| | 06:41 | pointer, how we can pass the address
of a function around, but this is how we
| | 06:44 | pass the name of a method in
Objective-C as an argument.
| | 06:49 | And in other languages and platforms
you might refer to this as a callback
| | 06:52 | situation, yes, I am going to call this
method, passing in the name of a method
| | 06:57 | it should call back when it's finishing.
| | 06:59 | And a possible bit of trivia for you,
when you see a built-in method in Cocoa
| | 07:04 | that starts with the word begin, such
as beginSheetModal for window, it's a
| | 07:09 | pretty good sign that this is an
asynchronous method, and it will execute on
| | 07:13 | another thread and
immediately return to this one.
| | 07:15 | So it's very common to have begin
methods take delegate callback parameters.
| | 07:21 | So we have gone through three examples of
delegation pretty quickly, but hopefully
| | 07:26 | you are beginning to see why
delegation is a powerful technique and hopefully
| | 07:29 | seeing why it's often underestimated.
| | 07:32 | See, the more experienced you are on
another platform, the easier it is to get
| | 07:36 | the wrong impression about delegation, and
that's why I have gone through several examples.
| | 07:40 | Because if I just show the
AppDelegate examples some people assume, oh,
| | 07:45 | delegation is a kind of inheritance equivalent.
| | 07:48 | Or if I just show you a user interface
element example, some people think, oh,
| | 07:53 | delegation is just some kind
of event handling equivalent.
| | 07:56 | And if I just showed you the alert
example here, it would be easy to think,
| | 08:00 | okay, delegation is just some
kind of callback equivalent.
| | 08:03 | And it's none of the above and kind
of like all three at the same time.
| | 08:08 | Delegation is a remarkably flexible
way of supporting optional behavior while
| | 08:13 | still keeping our classes very
independent and loosely coupled.
| | 08:17 | We support what we want to support,
we ignore what we want to ignore.
| | Collapse this transcript |
|
|
4. Creating User InterfacesExploring the XIB file| 00:00 | Let's explore what we find in a typical
XIB user interface file, just so we can
| | 00:05 | start to explore some of the other controls.
| | 00:08 | I will make a brand new project, and
I'm just going to go into the MainMenu.xib
| | 00:13 | file and to make sure that I can see
my Utilities panel, so I can get to my
| | 00:17 | Libraries and Inspectors.
| | 00:19 | We have seen that we have the Dock
area over here on the left of the canvas
| | 00:23 | which can be maximized or
minimized, but not hidden.
| | 00:27 | And it has two main sections inside it,
what are called Placeholders and Objects.
| | 00:32 | Now, the Placeholders represent
shortcuts to important objects, and often objects
| | 00:38 | outside of this actual user interface file.
| | 00:40 | So in the Placeholders section I see
File's Owner, First Responder, and Application.
| | 00:45 | And you will always see these three
placeholders in every Cocoa user interface.
| | 00:50 | The easy one is application.
| | 00:52 | It represents the running
application object itself.
| | 00:55 | Now, we won't do much with this icon
in this course, but it's good to have a
| | 00:59 | visual representation of the actual app.
| | 01:02 | For example, if I drill into the
standard menu that's generated for a new Cocoa
| | 01:09 | application, we have got the menu
that's being generated for the project itself,
| | 01:13 | which includes the Quit option.
| | 01:15 | We will go into the menus in more detail,
but just if I were to right-click on
| | 01:19 | that, I could actually see that like
having a button or some other control, it
| | 01:24 | can send actions, it can be an outlet
and right now this is set up to send the
| | 01:29 | terminate action to the Application object.
| | 01:31 | And if you notice, as I mouse over
application, it's actually highlighting up
| | 01:35 | there in the Placeholder.
| | 01:37 | So it can be useful to be able to
grab hold of something that represents
| | 01:41 | that application object.
Well, what about the other two?
| | 01:44 | Well File's Owner, is an icon that
represents a connection from this user
| | 01:48 | interface file to the object that owns
it that was responsible for loading it.
| | 01:53 | Now here, this MainMenu.xib is
actually loaded by the NSApplication object
| | 01:59 | because this part of the interface
lives as long as the application lives.
| | 02:04 | So here File's Owner and the
Application Placeholder both point to the same
| | 02:09 | thing, but that's not always the case.
If we were to create another window that
| | 02:13 | didn't need to live as long, say
our Preferences panel, it could have a
| | 02:17 | different File's Owner.
| | 02:19 | And the last one is First Responder.
This is a somewhat cryptic name.
| | 02:24 | This is a placeholder that can represent
different objects at different times in
| | 02:28 | the application lifecycle.
| | 02:29 | But it refers to the fact that there's
always one object in the UI that should
| | 02:34 | get the first opportunity
to respond to an event.
| | 02:37 | As a very basic example, say we have
been manipulating this interface, and we
| | 02:42 | have dragged on a couple of text fields.
| | 02:44 | Well, if you click into a text field,
that text field that you have just
| | 02:48 | selected, should now be the
thing that responds to key presses.
| | 02:51 | But if you click into a different text
field, it should be the First Responder
| | 02:56 | to those key presses.
| | 02:57 | So sometimes it's useful to be able to
ask who is the current First Responder
| | 03:02 | or even set a First Responder
programmatically, and we will see more about this later.
| | 03:07 | But we have got the main section here
below that, the Objects section, and there
| | 03:11 | are far more of these, mostly
representing visual user interface elements on our
| | 03:17 | canvas, but can be non-visual too.
| | 03:20 | Because this is an Apple operating
system, we have two primary sections set up
| | 03:25 | for us in a basic Cocoa application.
| | 03:27 | The Main Menu object, which itself
contains a collection of Menu Items and
| | 03:32 | other menus, and the Window object
itself, these things are both contained in
| | 03:37 | the user interface file,
but they are separate chunks.
| | 03:40 | And of course, Objects can contain other objects.
| | 03:44 | Beyond the most basic interaction, it is
useful to have the expanded view of the
| | 03:49 | Dock rather than the minimized view of
the Dock when you're looking at this.
| | 03:53 | So I can click the disclosure
triangle and start to drill down into the
| | 03:57 | different sections inside,
for example, the Menu.
| | 04:00 | Selecting any of these objects should
highlight it correctly on the actual
| | 04:05 | screen and the reverse is true as well.
| | 04:08 | You can treat the menu as a menu to be
able to drill down into optional settings
| | 04:13 | inside it, and you will find that
each individual piece of the menu is
| | 04:17 | essentially its own separate object.
| | 04:20 | Selecting any particular entry from any
particular part of the menu allows us to
| | 04:25 | look at that individual piece such as
Show Toolbar, I could use the Connections
| | 04:30 | Inspector, see if it has any actions
or outlets and just treat it completely
| | 04:34 | independently of other menu items.
| | 04:37 | Some of these menu items, you'll find,
are hooked up such as the Quit option in
| | 04:41 | the main application menu.
| | 04:43 | Right-clicking or using the
Connections Inspector, we can see that that's
| | 04:46 | sending the terminate
action to the Application object.
| | 04:49 | Others say Preferences might be very
common, but right-clicking that one I can
| | 04:54 | see that might be there, but
it's hooked up to nothing yet.
| | 04:57 | And that would be our job to do this
to create say a Preferences window.
| | 05:03 | Below the Menu section we have the main
Window section, which itself contains a
| | 05:08 | view, this main visible area that we
can drag and drop buttons and text fields
| | 05:12 | and other controls onto.
| | 05:13 | And we will see a lot more about what we
can do with this view in the next few movies.
| | 05:18 | Below this are a couple of non-visual
objects meaning, just objects.
| | 05:22 | These represent an object, an
instance of a class, like the App Delegate
| | 05:26 | represents an instance of the
AppDelegate class that's written in our project.
| | 05:31 | And we have seen this one already.
| | 05:33 | Having it here visually you know our
XIB file allows us to connect to it and to
| | 05:38 | call certain methods inside it.
| | 05:40 | We also have, in our basic
Cocoa application, the Font Manager.
| | 05:43 | This is a built-in Cocoa object
that's provided here by Xcode so that the
| | 05:48 | standard font menu inside
Format can have an object to talk to.
| | 05:52 | And we can just ignore Font Manager for now.
| | 05:54 | But here's the question. What is Xcode
actually doing when we say drag on a
| | 05:59 | button from the Object
Library? What does it do here?
| | 06:03 | On many, perhaps most IDEs, when you
work with a visual user interface design
| | 06:08 | like this, it's actually generating
programmatic code behind the scenes.
| | 06:12 | It might be generating lines of Java,
or C#, or VB.NET. That are instantiating
| | 06:18 | objects and setting their X and Y
positions based where you drag them on the window.
| | 06:22 | Well, this is not the way that Xcode works.
| | 06:25 | When we start arranging different
buttons and controls on the screens are
| | 06:29 | working with the menus, it's not
generating Objective-C, or C, or C++, or any other
| | 06:36 | procedural language.
A XIB file, behind the scenes, is made of XML.
| | 06:40 | It's not procedural, it's like an
XML snapshot of all the objects the way
| | 06:45 | you have arranged them and the
attributes you have set on them, the things that
| | 06:49 | you have connected them to.
| | 06:50 | If I right-click this MainMenu.xib
file in Xcode, I can choose to open it as
| | 06:56 | source code, and I actually see that
it is just seriously a list of XML in
| | 07:02 | different settings about how the menu is
created, what objects have been dragged
| | 07:06 | on, and information about those objects.
| | 07:09 | You do not need to edit the XML, as a
rule you just stay in Interface Builder,
| | 07:14 | so to get back to that I just
told it to open as Interface Builder.
| | 07:18 | So whatever we do, whatever we arrange,
whatever we change in an XIB file is
| | 07:23 | basically saved in a snapshot of XML.
| | 07:26 | You will often hear the term freeze-dried
for this, but when you arrange and
| | 07:29 | save this XIB file, it's like having
a bunch of objects frozen in place.
| | 07:34 | And when that XIB is loaded, everything
is unfrozen, or reconstituted, exactly how
| | 07:40 | you define the interface in Xcode.
| | 07:41 | But what we are going to do in the next
section is explore more of what we can
| | 07:46 | do with a user interface in Cocoa, talk
about some of the most common controls
| | 07:50 | you are likely to use from the Object
Library, how to lay out an interface well,
| | 07:54 | make it flexible, and some user
interface conventions in Cocoa that you may be
| | 07:58 | aware of and a few you
may not, but you should be.
| | 08:02 | So I won't be writing a great deal of
code in the next few movies until we have
| | 08:06 | seen what we can do by
just using the visual options.
| | Collapse this transcript |
| Working with buttons| 00:00 | The first time you create a new Cocoa
application and you open up the Object
| | 00:05 | Library to see your available user
interface elements, there looks like there's a
| | 00:10 | tremendous amount of things here to
choose from, and it's true there are a
| | 00:14 | lot, but not quite as many as it might seem.
| | 00:17 | For a little bit more information on
any of them, you can select them, then
| | 00:21 | hover the mouse, you'll get a pop-up
that tells you a little bit more
| | 00:25 | information about that particular control.
| | 00:28 | And this is what I mean by saying there is
not quite as many controls as it might seem.
| | 00:32 | The first bunch here, for example, are all
exactly the same class, the NSButton class.
| | 00:37 | In fact, I have to come down 14 entries
to find something that isn't an NSButton.
| | 00:42 | And in fact, NSButton is actually a
really good place to start when we want to
| | 00:48 | get familiar with the Cocoa controls.
So let's see a few of them.
| | 00:51 | I'm going to jump into my MainMenu.xib
file here and just select the Window object.
| | 00:56 | Drag on a few of the basic buttons here.
| | 00:58 | We have got a Push button, Gradient button,
Rounded Rect button, I won't do every
| | 01:04 | single one, but I'll have a few of them.
| | 01:08 | Textured button, Disclosure Triangle,
and let's go with a Square button.
| | 01:12 | They're all based on the same underlying class,
although they obviously look substantially different.
| | 01:19 | If I open up my Inspector section and
go to my Attributes Inspector, which is
| | 01:23 | the fourth Inspectors Panel here, I
can actually see that each button has a
| | 01:28 | style, and it looks like I could change
this from say a Square button to a Push
| | 01:33 | button, to a Disclosure Triangle and back.
| | 01:35 | But I would say that if you
accidentally dragged on the wrong kind, and you
| | 01:39 | haven't hooked it up to anything yet.
Don't just ever change the style.
| | 01:43 | Delete the button, go back and drag on
the one you wanted because there is a
| | 01:47 | lot more to a button than
style, as we'll see in a moment.
| | 01:50 | But this Attributes Inspector is, in
fact, a great way to get an idea of the
| | 01:56 | options for these buttons and for any controls.
| | 01:59 | Though for more on each control,
with it selected, selecting the second
| | 02:03 | Inspector will give you the Quick Help menu.
| | 02:06 | Now, the first abstract here doesn't
give you more than you can get just by
| | 02:10 | clicking in the Object Library and
waiting for the pop-up, but you also have a
| | 02:14 | link here to say the NSButton Class
Reference, which will jump us to the
| | 02:19 | Documentation and tell us the kind of
things we could do in code, giving us an
| | 02:23 | idea of what this button is capable of.
Apparently we can set the sound on it,
| | 02:27 | we can set it to Transparent.
It's got things like bezelStyle.
| | 02:32 | Switching back to the main environment,
there is also a link to a guide called
| | 02:36 | button Programming Topics, although
this at least at the time of recording for
| | 02:41 | Apple is surprisingly out of date.
| | 02:43 | So let's go back and take
a look at a few of these.
| | 02:46 | I'm going to switch back
into my Attributes Inspector.
| | 02:48 | Many buttons have, as we can see, a Title.
| | 02:50 | You can double-click in here to change
it to something else, or of course, you
| | 02:55 | can change it in the Attributes
Inspector, which will do the same thing.
| | 02:59 | But several buttons, a Square button,
for example, does not have a title, even
| | 03:03 | though there is a space for one.
| | 03:05 | You can add one, or you can give a button an
image instead of, or in addition to, a title.
| | 03:11 | But if a button doesn't have a title
when dragged on, it can be a clue that this
| | 03:15 | kind of button is expected to have an image.
| | 03:18 | So with the Square button selected I
can see that I do have a dropdown Image
| | 03:21 | section here in the Attributes Inspector,
and just by clicking that I'm going to
| | 03:26 | see several entries.
| | 03:27 | What we're looking at here are some of the
official Apple button and Toolbar images.
| | 03:32 | We have got ColorPanel here, we have
got Computer, we have got the images for
| | 03:37 | Everyone, we have got the images
for DotMac and Advanced settings.
| | 03:42 | However, just because you can select
an image here, doesn't mean you should.
| | 03:45 | Some of these are only supposed to be
used in Toolbars, and most of them really
| | 03:50 | do represent a very specific meaning for Apple.
| | 03:53 | So you don't want to use, for example,
NSUserGroup for your button thinking that
| | 03:59 | might be a good icon for chat, when in
fact this is a very specific Apple icon
| | 04:04 | meant to be used for user group permissions.
| | 04:07 | Now, your question might be, well, how
am I supposed to know which one of these
| | 04:11 | I can use and which ones I
can't and in what circumstances?
| | 04:14 | Well, bear with me, we will get to that.
| | 04:17 | Of course, what's often likely is that
you'll want to have your own images for icons.
| | 04:21 | Now, unlike some platforms, including
iOS, there is no one particular size that
| | 04:26 | you must provide for a button icon
because buttons can be large, they can be
| | 04:30 | tiny, they can be anywhere in between.
| | 04:32 | But a Square PNG file is best
with a transparent background.
| | 04:37 | I have one on my Desktop at the moment, what
I'm going to do is just add it to this project.
| | 04:42 | I'll click the Supporting Files folder
because that's usually where I'd want
| | 04:45 | this to be, and in Xcode I could just
drag and drop this, but I can also go to
| | 04:50 | File and then Add Files to this
project, the project is called buttons.
| | 04:53 | I'll go and find this, it
should be on my Desktop.
| | 04:56 | I have something called SimpleImage.
It's just a PNG, a very small file here.
| | 05:01 | With that selected, I want to check
the box to say Copy this item into the
| | 05:06 | destination group folder, to make
sure I'm not just linking to it on the
| | 05:09 | Desktop, but I'll keep it in my
Project folder, click OK, and now I can see
| | 05:15 | SimpleImage.png, very
straightforward turn up there.
| | 05:19 | Switching back into the interface,
what I should now be able to do with that
| | 05:23 | button selected is go over here into
the dropdown Image, and I should find it
| | 05:27 | show up in the list.
There we go, SimpleImage.
| | 05:33 | Now, the most common thing of course to
do with a button is hook it up to some
| | 05:37 | code, meaning cause an action.
| | 05:38 | A button that doesn't cause an
action isn't really all that useful.
| | 05:42 | Now, we have seen this already, but
let's just take another look at it again.
| | 05:45 | I'll give myself a bit more screen
real estate here and switch into my
| | 05:49 | Assistant Editor mode.
We want to see the AppDelegate over here.
| | 05:53 | I could create a new class, but just for
the purposes of a quick demo this is fine.
| | 05:58 | I'm looking at the header file.
| | 05:59 | I'm going to Ctrl-drag from any of
these buttons in here to insert an action.
| | 06:05 | The pop-up, by default it pops up as Outlet.
| | 06:08 | buttons can be both Outlets and Actions,
but it's certainly more common that
| | 06:12 | they're all actions.
I'll call this doSomething.
| | 06:16 | We have now connected that button
up to this little piece of code.
| | 06:20 | But while all of my buttons
are likely to cause actions.
| | 06:23 | oftentimes I'll want to also talk to the
button in code, I'll want to change its
| | 06:27 | title or set it from Enabled to Disabled.
| | 06:30 | Now, to talk to a specific button
directly in code, it's useful to define that
| | 06:35 | button as an Outlet and give that Outlet a name.
| | 06:39 | So, for example, I'm going to
select this Gradient button here.
| | 06:43 | Ctrl-drag that into the interface.
| | 06:48 | I prefer to put all my properties
before my methods, it doesn't really matter
| | 06:51 | what order the properties are in.
| | 06:53 | So this on the other hand, is not an
action, it's an Outlet, and I'll give it a
| | 06:57 | name of myGradientButton.
| | 07:00 | It's of Type NSButton, that looks
correct, and it's weak, there we go.
| | 07:03 | The reason that I wanted to do this is
to show what's probably the second most
| | 07:07 | common thing to do with a button.
| | 07:08 | If the first is hook it up and make it
cause an action, the second most common
| | 07:12 | thing is to make a button enabled or disabled.
| | 07:14 | Now, this can be done in the Interface
Builder, so if I have my Utilities Panel
| | 07:19 | open, I can select that Gradient button
and down towards the bottom here we have
| | 07:25 | a check box here called Enabled.
| | 07:28 | If I uncheck that, we immediately see
the different visual style over here in
| | 07:33 | the Interface that suggests
we can't click this button.
| | 07:36 | But we often want to do that too in code.
| | 07:38 | We want to affect whether a
button is enabled or disabled in code.
| | 07:42 | So what I'm going to do now is switch to the
Implementation and turn that button back on.
| | 07:51 | Because we have defined it as an
Outlet called myGradientButton, I can just
| | 07:55 | use the name of that.
| | 07:58 | myGradientButton has a method
called setEnabled, and it's a BOOL, which
| | 08:04 | for Objective-C is YES.
| | 08:06 | Alternatively, I could have used dot
syntax here, myGradientButton.Enabled = YES.
| | 08:12 | Save that and Run it.
| | 08:14 | The application should begin with the
button Disabled, but not surprisingly we
| | 08:19 | click the first Push button, and we
should get the option to Enable it.
| | 08:23 | Of course, very simple and very
straightforward stuff, but the two most common
| | 08:28 | things to do, drag on buttons, hook
them up and make them cause actions, or
| | 08:33 | enable and disable them.
| | 08:34 | And those might be the two most common
tasks, but there is certainly a few more
| | 08:38 | we can take a look at.
| | Collapse this transcript |
| Exploring button states and types| 00:00 | We have seen that buttons can be
enabled, or they can be disabled.
| | 00:04 | If they're enabled, we can click on
them. If they're disabled, we can't.
| | 00:08 | But buttons also have something called State.
| | 00:11 | And it's an easy beginner mistake to
confuse the state of a button with whether
| | 00:15 | that button is enabled or not.
| | 00:17 | And State and Enabled in Cocoa, are
two very different things. So I have just
| | 00:21 | created a brand-new Cocoa application,
and I'll jump onto the window in my
| | 00:26 | MainMenu.xib, and drag on
a regular push button here.
| | 00:30 | Now if I look in the Attributes
Inspector for this button, Apple won't really
| | 00:35 | helping me understand the difference
here because I do have this dropdown
| | 00:39 | option called State here.
| | 00:42 | But if I go down a little bit further to
find where I have got the check box for Enabled.
| | 00:46 | It's in a section called State, and these
are completely different from each other.
| | 00:50 | So let me make this a little clearer.
Enabled is simple, it's the easy one.
| | 00:55 | All buttons care about
whether they're enabled or not.
| | 00:58 | The value of this can be
changed in interface builder.
| | 01:01 | I can uncheck it, or I can do it
in code with the Set Enabled method.
| | 01:06 | If it's enabled, I can click
on it, if it's not, I can't.
| | 01:09 | It's simply true or false.
| | 01:11 | We're seeing as this is Objective-C,
it's yes or no, but State is different.
| | 01:16 | State--I'll go back up to the top of
the Attributes Inspector to find it here.
| | 01:20 | State is a property that can be
officially On or Off or Mixed. And this has
| | 01:26 | nothing to do with whether
this button is enabled or not.
| | 01:29 | But here is the thing, with many of
the buttons that you might drag on, State
| | 01:33 | doesn't matter. You start changing the
State of a regular push button like this
| | 01:38 | one, you'll see no visual impact
whatsoever. So what's the difference?
| | 01:42 | Well, here is what I consider the best
example of the difference between State and Enabled.
| | 01:48 | I'm going to go into my Object Library
here and drag on a check box, and just
| | 01:54 | copy and paste that.
Do it a couple more times so that I have four.
| | 02:06 | And yes, in Cocoa, a check box is not some
special kind of class, a check box is an NSButton.
| | 02:13 | That is its type,
| | 02:14 | if I click over there and hover, you
will see a check box is an NSButton class.
| | 02:18 | So I'm going to change the
properties of three of these.
| | 02:21 | I'll leave the first one as it is.
| | 02:23 | Take the second one, and
change its State from On to Off.
| | 02:29 | Take the third one, leave its State as
it was, which is On, but uncheck Enabled.
| | 02:35 | Check the fourth one, I want to
uncheck Enabled, and change its State to Off.
| | 02:42 | And that's the difference
when we're looking at this.
| | 02:45 | The first two are enabled,
the second two are not.
| | 02:48 | But the first one is enabled with the
State of On, the second one is enabled
| | 02:53 | with the State of Off, third one not
enabled and On, fourth one not enabled and Off.
| | 02:59 | So state is a property that does
exist for every button in Cocoa but only
| | 03:04 | matters for certain types of button.
Because in Cocoa buttons don't just have a
| | 03:09 | style, they have a Type.
| | 03:11 | The style is the way they look, the
Push button, Check, Square, Disclosure
| | 03:16 | Triangle, but the Type, which is also
available as a dropdown here, is the way they behave.
| | 03:22 | Often these two are very closely
linked, but they're not the same thing.
| | 03:25 | For example, a regular Push button has
a certain appearance, a certain Style,
| | 03:31 | but it also has a particular behavior,
a specific behavior when pressed.
| | 03:35 | You click it, it is momentary.
It's got the Type of Momentary Push In.
| | 03:40 | Now I can go ahead and run this
application or another quick way I can do this
| | 03:45 | is go to my Editor menu and just say
Simulate Document, which is a quicker way
| | 03:49 | of just taking a look at this screen
without worrying about compiling code.
| | 03:54 | button behavior is
momentary push in. I click it,
| | 03:57 | it turns blue for a second and
returns to the way that it was a moment ago.
| | 04:01 | On the other hand a check box, which is
still a button, has a different kind of behavior.
| | 04:06 | I check it,
| | 04:07 | it changes its State, it moves from
Off to On or On to Off, quitting the
| | 04:12 | simulator, go back here.
| | 04:15 | So selecting a check box we have
a different type of Type switch.
| | 04:19 | If you drag down a button like a
Recessed button, then you would find a slightly
| | 04:23 | different behavior there, which
is the Push On Push Off behavior.
| | 04:27 | But typically you don't have to worry
about the Type because buttons dragged
| | 04:32 | from the library have the Type
that is most usual for that Style.
| | 04:36 | But it can mess you up if, for example,
you decided to have a check box and then
| | 04:41 | change its Visual Style to Push
button but leave its Type as Switch,
| | 04:45 | that would be a nonstandard
use of an interface control.
| | 04:48 | But there are the occasional
times you want to change the type of a
| | 04:51 | button, here's an example.
| | 04:52 | I'm going to select this regular Push
button here, which by default has a Type
| | 04:57 | of Momentary Push In, and I'm going to
change that to Momentary Change.
| | 05:01 | What's the difference here?
| | 05:02 | Momentary Change allows us to put in an
alternate title so that while it's being
| | 05:07 | pressed, it actually shows something different.
So I'll just change this to the word, Pressed,
| | 05:15 | and then go back to the Editor
menu and say, Simulate Document again.
| | 05:18 | I could just run the application,
and we'll do the same thing.
| | 05:21 | Now when we click the button, we get
the alternate state of that, this is the
| | 05:26 | momentary change of the button.
| | 05:27 | And occasionally that kind of thing
might be useful, but most of the time you
| | 05:32 | drag on a button with the right kind of
Style from the Object Library, you will
| | 05:37 | automatically have the right type.
| | Collapse this transcript |
| Exploring the Apple Human Interface Guidelines for OS X| 00:00 | If you have been using a Mac for a while,
several of the button choices in the
| | 00:04 | Cocoa Application are pretty obvious.
| | 00:07 | You can tell the difference between say
using a Push button, and when you might
| | 00:11 | use something like a Disclosure button.
| | 00:15 | However, most developers even with long
histories on the Mac are less sure when
| | 00:20 | the question is something like when
should you use a Gradient button as opposed
| | 00:24 | to a Square button as
opposed to a Bevel button?
| | 00:27 | What's the difference between using a
Recessed button and an Inline button,
| | 00:31 | particularly as they look almost
identical in the Library section?
| | 00:35 | And of course, this is Apple, so we
can presume that all these choices
| | 00:38 | matter, it's not arbitrary.
| | 00:40 | Well, we need to step up our knowledge of
Apple's official Human Interface Guidelines.
| | 00:46 | Now this is a document that you can
get from the Apple developer site.
| | 00:53 | And if I go into the Mac Dev Center, I
often don't even need to be logged in
| | 00:58 | to be able to find it.
| | 00:59 | I'm going to jump into the Guides
section of the Mac OS X Developer Library.
| | 01:06 | It's usually fairly obvious somewhere on this page,
but if not, you can of course search for it.
| | 01:12 | This is what I'm looking for, the
Mac OS X Human Interface Guidelines.
| | 01:16 | There are actually separate
documents for OS X and iOS development.
| | 01:21 | You can get this document on the web,
but you can also download a PDF version of
| | 01:27 | it if you prefer to put it
on a reader or print it out.
| | 01:30 | PDF is over 300 pages, but this is not
your usual dry technical documentation,
| | 01:36 | it's not primarily about code,
and it is written very, very well.
| | 01:40 | Over here on the left-hand side I can
see it is split up into several sections.
| | 01:44 | We go to section on the basics of the
Mac OS X platform, there's some high-level
| | 01:48 | content like the Philosophy
of User Interface Design.
| | 01:51 | Everything from Consistency,
Forgiveness, and Aesthetic Integrity, but it
| | 01:56 | also gets into very specific low-
level content like Designing icons for the
| | 02:01 | Sidebar or the Toolbar.
| | 02:02 | And there are two sections certainly
worth becoming very familiar with early on.
| | 02:07 | If I come down to the sections here
that talk about the User Interface Element
| | 02:11 | Guidelines, I'm going to
select the Windows section here.
| | 02:15 | And if you want to make sure that
you're good with the differences between a
| | 02:18 | window, a document, a panel, an alert
and a sheet, this is going to break it
| | 02:23 | down, give you a nice quick reference for that.
| | 02:25 | It will break down some of the
terminology that you will read in Apple
| | 02:28 | documentation, talking about say the
window-frame area, the title bar and the
| | 02:33 | toolbar, the window-body, because
what you'll find is a lot of buttons and
| | 02:37 | different elements are suggested that
they only exist in the window-frame or
| | 02:42 | they only exist in the window-body.
| | 02:43 | What this document is great for
is making explicit what is often only
| | 02:48 | implicit when you have just been a Mac user.
| | 02:50 | After you have gotten familiar with the
Window Guidelines, take a look at the User
| | 02:55 | Interface Element Guidelines for Controls.
| | 02:57 | Here is where you'll find very specific
guidelines for things like button usage.
| | 03:02 | There is an entire section
on Window-Frame Controls.
| | 03:05 | Again, if you're looking at something
that appears in the toolbar that kind
| | 03:09 | of button there, if it's a separate button the
suggestion being it's a Round textured button.
| | 03:15 | If the visual appearance is something
like this the four groups together you're
| | 03:19 | looking at the Textured
rounded segmented control.
| | 03:22 | It will break down the differences
between pop-up menus and pop-down menus.
| | 03:27 | So when you're asking which button
should I use in which circumstance?
| | 03:30 | This is a great part of the document to get to.
| | 03:33 | In fact, if you jump into the buttons
section, it will break down guidelines on
| | 03:38 | when Push buttons should be used.
| | 03:40 | As you read this document, you'll
find the guidelines on things like if one
| | 03:43 | of these buttons is going to pop-up
another dialog box, then you should have
| | 03:47 | be ellipses after it.
| | 03:49 | As we come down further this
guidelines about when to use Icon buttons, what
| | 03:52 | size you should be working with, there.
| | 03:54 | Scope buttons, recessed scope buttons
versus round rectangle scope buttons.
| | 04:00 | Again, all of the things we kind of
take for granted using the Mac that we now
| | 04:04 | have to make explicit as Cocoa Developers.
| | 04:07 | An example of when to use a Gradient
button, Gradient buttons often being used
| | 04:12 | without text, using one of the built-
in icons for Apple to add or subtract or
| | 04:17 | work with settings and preferences.
| | 04:19 | When specifically to use the Bevel
button, and you'll find the Notes that
| | 04:24 | they're not recommended for
apps using OS v10.7 or later.
| | 04:28 | You should use a Gradient
button or Segmented Control instead.
| | 04:31 | Now earlier I showed examples of
selecting images on a button from using some of
| | 04:37 | the built-in Apple icons.
| | 04:38 | Well, in Appendix B of this document
you can actually find more about what
| | 04:42 | images are available and
exactly when they should be used.
| | 04:46 | It will break down which one should
only be used in Toolbars, which ones are
| | 04:50 | allowed to be used in Controls.
| | 04:52 | You see a preview of the image and then
what you should expect that image to be
| | 04:56 | called in the dropdown box.
| | 04:58 | Images for locking and unlocking,
going forward, going back, adding an item
| | 05:02 | removing an item, they are already there,
and these are the ones you should be
| | 05:06 | using in Cocoa if you need that functionality.
| | 05:08 | Further on, it has some of the images
that are suggested for use, but only if
| | 05:13 | you're using this in a toolbar, and
when certain icons should be used for
| | 05:18 | Advanced Preferences or User Accounts.
| | 05:21 | But overall, a hugely important and
useful document, something that you should
| | 05:26 | have downloaded or at least Bookmark and
check back with regularly. And it's the
| | 05:30 | source I'll be using and referring
back to several times during this course.
| | Collapse this transcript |
| Using text fields| 00:00 | After working with buttons, the next
classic control is the Text Field, and
| | 00:04 | we have seen several of these already.
| | 00:06 | Now, like buttons, several of the
entries in the Object Library are from
| | 00:11 | NSTextField just differently
configured examples ready to drag and drop, but
| | 00:16 | there is not quite so many this time.
| | 00:18 | We have the classic text field, that is
NSTextField. We have Label which we have
| | 00:23 | also discussed is NSTextField,
it's just a non-editable one.
| | 00:26 | I will just select my MainMenu.xib
file and drag a couple of these so we can
| | 00:32 | start to work with them.
| | 00:38 | A couple of text fields and a label,
| | 00:43 | basic Text Fields, Regular or Label,
have one line and don't wrap, but there
| | 00:47 | are two draggable objects that you will find in
the Object Library that can have multiple lines.
| | 00:52 | We have a Multiline Label, and
we have a Wrapping Text Field.
| | 00:58 | There is nothing
particularly remarkable about these.
| | 01:02 | Again, they come from the NSTextField
class, so they have the same capabilities.
| | 01:05 | It's just worth knowing they exist.
| | 01:08 | Now, if you need large amounts of text,
more than a few lines, we would typically
| | 01:13 | look at something called a Text view.
| | 01:15 | But that's a very different
class, and we'll see that later on.
| | 01:18 | But what you'll also find in the
Object Library is there are several classes
| | 01:22 | here that inherit directly from NSTextField
and extend it to provide additional behavior.
| | 01:29 | Now sometimes when I first say
that, I have people ask me, hey!
| | 01:33 | I thought we didn't use inheritance
as much in Cocoa. Well, that's true.
| | 01:36 | As application developers, we don't
tend to use inheritance as much as you
| | 01:41 | might do in Java, C#, C++, as we're often using
delegation instead to provide extra behavior.
| | 01:48 | But if I was building or using a
framework of reusable objects, inheritance is
| | 01:53 | great in Cocoa or in any other language,
and it's certainly heavily used when it
| | 01:58 | makes sense to do so like here.
| | 02:00 | So there are three
classes I am going to show you.
| | 02:02 | First off, I'm going to drag a
container from my Layout view here just drag on
| | 02:07 | something called a Box.
Box is very simple.
| | 02:11 | It's just a way of grouping a
few other controls together.
| | 02:14 | I am going to drag on this Box and just
give it a name of NSTextField Subclasses.
| | 02:23 | I don't have to do this, but it
allows me to group them together.
| | 02:27 | First, I'm going to find the Secure Text Field.
| | 02:30 | This is NSSecureTextField, but it's a
subclass of NSTextField, mostly behaves
| | 02:36 | exactly the same as a Text Field except
this one just shows bullets instead of
| | 02:41 | characters, and you can't copy from it.
| | 02:43 | There is the NSSearchField
with a little magnifying glass.
| | 02:49 | Well, this adds a Search and a Cancel
button to the text field, and it also
| | 02:55 | stores an array of recent search
strings available in the pop-up menu.
| | 02:59 | Now, it's still just a text field,
it has no knowledge of how to search.
| | 03:03 | That would be up to you and your
application, it's just really an Apple style
| | 03:07 | user interface control to support
searching in a recognized way, and there is
| | 03:12 | also this Token Field here.
| | 03:17 | Again, behaves very much like a normal text field
but supports what's called tokenized editing.
| | 03:23 | Well, let's see a couple of these running.
| | 03:25 | I am just going to go to the
Editor menu and say Simulate Document.
| | 03:30 | The first couple were normal text fields.
| | 03:34 | Nothing special about them, you can
see that as we're typing we get the blue
| | 03:39 | highlight around them,
that's all built-in by default.
| | 03:42 | We have the Wrapping Text Field below,
then we have the Secure Text Field where
| | 03:47 | everything pops up as bullets,
and we can't copy out of that.
| | 03:50 | Next is the Token Field which
supports what's called tokenized editing.
| | 03:55 | Think about when you type in multiple
email addresses in mail, it recognizes
| | 03:59 | each email address as one piece, one
unit, and it surrounds that with a blue
| | 04:06 | outline, that's what tokenized
editing is, and finally the search box here.
| | 04:11 | Working with all these different
text fields is actually very similar.
| | 04:14 | The Text Field is a capable intelligent object.
| | 04:17 | It can even do delegation to let
another class know when it's being edited,
| | 04:21 | and a lot more besides.
| | 04:23 | But in a lot of circumstances, you
really don't need that level of capability.
| | 04:27 | The most important property that you're
interested in is really how do you get
| | 04:32 | to the contents of a text field?
| | 04:34 | And while of course we can change any
of the attributes in the Text Field when
| | 04:39 | we're in Interface Builder, it's much more
likely we'll get to the contents in code.
| | 04:43 | The property we're interested in is stringValue.
| | 04:46 | We read the contents with stringValue,
we change it with setStringValue.
| | 04:50 | Now, it's very common as we have seen that
what we want to do with a text field is
| | 04:55 | make it an IBOutlet.
| | 04:57 | So using a System view, I can do a
Ctrl-drag into a class, in this case App
| | 05:02 | Delegate and create this as an IBOutlet.
And I could do the same with any of them.
| | 05:09 | But a text field can also be an IBAction.
| | 05:13 | You can connect it to an IBAction
method like connecting a button.
| | 05:17 | So if I Ctrl-drag, I will do it here from
the first text field, and drop it in there.
| | 05:21 | But instead of inserting an Outlet,
insert an Action, let's call this
| | 05:27 | generically doSomething.
We can have some behavior occur.
| | 05:31 | Now, the question might be,
well, what is the action?
| | 05:33 | It's very obvious, when it's a
button click, you click the button.
| | 05:36 | So when does this occur for a Text Field?
| | 05:38 | Well, the way it works is that once the
user is typing in the text field, then
| | 05:42 | if they hit Return or click out or hit
Tab while they're in that text field,
| | 05:47 | that will cause the action to happen.
| | 05:50 | So I could simply jump across and put in
a little bit of code into that implementation.
| | 05:54 | I will jump into Standard Editor just
so I can see a little bit more here,
| | 06:01 | and we'll do a good old NSLog message just
saying the contents of the first text field.
| | 06:06 | Well, we did set it up as an
output, so it should have a name,
| | 06:10 | firstTextField, and again, we get
its contents by saying stringValue.
| | 06:17 | Save that and run it.
| | 06:22 | Here, I'm getting a small warning
about the Content rectangle not entirely on
| | 06:26 | the screen, that's something I'll
occasionally get when I'm dealing with a very
| | 06:30 | restricted amount of screen real estate.
It really doesn't matter here.
| | 06:35 | So I start typing in that first area.
| | 06:39 | If I hit the Return key, it
will kick off that action.
| | 06:41 | In fact, if I hit the Return key again
and again and again, we'll actually have
| | 06:45 | that message appearing multiple times.
The first text field is first text.
| | 06:52 | Change the value again, hit
Return, we see that happen.
| | 06:56 | It will also happen if I tab out, or if
I'm in there and I click out, and the
| | 07:01 | same method would work for any of these text
fields, or anything based on this text field.
| | 07:07 | So text fields can be an outlet, you're
typically interested in the stringValue
| | 07:11 | property, and text fields can be an
action which will occur when we hit Return,
| | 07:15 | click out, or hit the Tab.
| | 07:16 | Now, this class can get a little deeper,
but being able to get to its contents
| | 07:20 | and respond to someone changing it is
really all we need a lot of the time.
| | 07:25 | Now, one thing to be aware of is if you
drag several text fields onto a window,
| | 07:29 | then either run that app as I have
done now, or use the interface simulator.
| | 07:34 | Even if you drag them out of order,
it's going to do a pretty good job of
| | 07:38 | ordering them the way you want and
allowing you to just tab through them every time.
| | 07:43 | And it does this by default based
on the top-left position of the user
| | 07:47 | interface element itself.
| | 07:48 | So good to know that most of the time
that just works, but after getting to the
| | 07:53 | Text Field contents and being able to
respond to an action, the next most common
| | 07:57 | request is what if we need that
actual interface, what if we need that Text
| | 08:02 | Field to be something other than
freeform text, like a date or a price?
| | 08:07 | Well, we'll get to that next.
| | Collapse this transcript |
| Using number formatters| 00:00 | We'll work with text fields and labels
a lot, and it's common that the value we
| | 00:04 | need to put in them is not actually
a string object, it's something else.
| | 00:08 | So if in our code we have say an
NSDate object, we want it to be easy to put
| | 00:14 | that directly into a text field,
formatted the way we want it, without writing a
| | 00:18 | lot of code to convert it, and we can
use something called a formatter for that.
| | 00:22 | A formatter in Cocoa changes a string
into another data type or the other way
| | 00:26 | around, another data type into a string.
Let's see a couple of examples.
| | 00:30 | So I have a very simple application that
I have created just to save us a little time here.
| | 00:35 | The interface has a text field which
I want to set to a date value and a
| | 00:39 | label here, which of course is just a text
field that I am going to set to a float value.
| | 00:44 | I have already declared these as
outlets in my AppDelegate header file and
| | 00:48 | hooked them up so that I can address
them in code. And what I am going to do is
| | 00:53 | in the applicationDidFinishLaunching
method, I am going to set their values.
| | 00:58 | And on Line 19 and 20, this
is what I want to put in them.
| | 01:02 | I want to grab an NSDate object and put
that value in the first text field, then
| | 01:06 | I want to create a float and
put that in the second one.
| | 01:09 | Well, we know that text fields have
the set string value method, and new
| | 01:13 | developers in Cocoa often do something like
I am showing here in what I call Method one.
| | 01:18 | Manually converting those other data
types into strings and then using set
| | 01:23 | string value to change the
contents of the NSTextFields.
| | 01:26 | And this works, if I go
ahead and run this application.
| | 01:31 | I am indeed putting the date into
the date field, and this floating point
| | 01:36 | number into the number field, but that might
not exactly be the look that we are going for.
| | 01:41 | So what are my options here?
| | 01:42 | Well, while set string value might be
the most common way to change the contents
| | 01:47 | of an NSTextField, we also have the
methods set int value, set float value, set
| | 01:53 | object value, and a few more besides
that allow us to pass in a different data
| | 01:57 | type into that NSTextField
without converting it first.
| | 02:01 | Now, we're still not using formatters yet,
but let's do that as kind of an in-between step.
| | 02:06 | So instead of on Line 24 converting the
date into a NSString, what I am going to
| | 02:13 | use is setObjectValue and just pass in
the NSDate object I have called today.
| | 02:21 | And then instead of converting the
float variable, I am going to call
| | 02:27 | setFloatValue, passing in that
float variable I created on Line 20.
| | 02:33 | Save that and Run it just hitting Command+R.
Less code, slightly similar result.
| | 02:41 | Using this method we actually get a
different result for both a floating point
| | 02:44 | version and for the date, it's probably still not
what we're looking for, but it is a step closer.
| | 02:51 | Let's see what formatters
can add to this picture.
| | 02:55 | Quitting out of this and going back
into Xcode, I am going to jump into my
| | 02:59 | MainMenu.xib file, and I am
opening up my Object Library.
| | 03:03 | I can either come down or filter on
the word formatter, and I'll find a few
| | 03:10 | formatter entries in the Object Library.
| | 03:12 | There are two that I am interested in here,
the Date Formatter and the Number Formatter.
| | 03:18 | And these really are the two
built-in formatters in Cocoa.
| | 03:22 | You can also create things like a
custom formatter to handle your own classes
| | 03:26 | being converted to
strings and back if necessary.
| | 03:30 | Using these formatter
objects is a little different.
| | 03:33 | You don't drag a formatter
onto the interface by itself.
| | 03:37 | The whole point of a
formatter is to format something.
| | 03:40 | In this case with the Date Formatter, I
want to format that date field, so I am
| | 03:45 | going to click it, drag it, and drag
it on top of the text field itself.
| | 03:49 | I should see it highlighted
in blue, and then I let go.
| | 03:52 | I see no actual visible difference, but it
has had an impact, we'll see it in a second.
| | 03:57 | Next, I grab the Number Formatter and
drag that over the label and let go.
| | 04:02 | I am going to just Save that and Run it
again and see the impact that, that has.
| | 04:07 | Haven't written any code,
haven't changed anything, but now we're
| | 04:11 | certainly getting a different kind of
impact. We are formatting the values
| | 04:15 | of those NSTextFields.
| | 04:17 | It might not be what we want, so let's
take a look and see what else we can do.
| | 04:20 | Formatters are customizable.
| | 04:23 | One of the problems is when they're on
the interface, you can't really see them
| | 04:26 | just from looking at it, what we have
to do is look at the expanded Dock view.
| | 04:31 | Selecting that first text field,
making sure the disclosure triangle is open,
| | 04:35 | what I can see nested a couple of
levels in there is the Date Formatter.
| | 04:39 | And we can use the
expanded Dock view to select it.
| | 04:43 | With the Date Formatter itself selected,
we can go to the Attributes Inspector
| | 04:47 | over here on the right-hand side, and we
have a bunch of choices to select from.
| | 04:52 | Date Style, do we want Short Style, and it
gives us a little sample of that, Medium,
| | 04:59 | Long Style, giving the full name of the month.
So I'll change it to Long Style.
| | 05:03 | Again, when you're using a formatter,
you always have to be careful here,
| | 05:07 | because if I just click the text field itself, I
am looking at the attributes of the text field.
| | 05:12 | I need to either use the Dock here, or I
can drill down using the Jump bar into
| | 05:16 | the Date Formatter to change its attributes.
| | 05:19 | Same idea with the second
one I am using as a label here.
| | 05:23 | We have applied a Number Formatter, we
can't see anything on the actual canvas
| | 05:27 | itself, but over here in the Dock I
can see I have got a Number Formatter kind
| | 05:31 | of embedded in there.
| | 05:32 | With the Number Formatter we
have a few different choices.
| | 05:35 | We can go for Decimal,
we can go for Currency.
| | 05:38 | And down at the bottom it will give us
a sample of, well, if the unformatted
| | 05:42 | value was 1234.75, the formatted one
will use the dollar sign for our sake.
| | 05:47 | This is localizable, so it can change
based on the culture of the operating system.
| | 05:52 | So we have several options here:
| | 05:53 | we have Currency, Decimal,
Percent, Scientific, and so on.
| | 05:57 | If you need a little more than that,
select from the Behavior the Custom option,
| | 06:03 | which itself gives you a lot more
option for things that you can do in terms of
| | 06:08 | grouping separators and
currency symbols and so on.
| | 06:13 | I am going to just switch back to
default, and I'll select Currency.
| | 06:17 | We go ahead and run this again, and
we're using the new formatter rules.
| | 06:21 | And it is important to consider that
when using these formatters, they do
| | 06:26 | want say a date object or a number to work
with, so don't do your own conversion first.
| | 06:32 | Rather than the set string value of the
text field, use the set float value or
| | 06:36 | set double value or set object
value for a date and then format that.
| | 06:41 | I do find that formatters are easier
to grasp when using them for output.
| | 06:45 | They can be used for input, too, although there
are often better options than formatters for this.
| | 06:51 | Even though, for example, I am setting
that date and formatting it into a text
| | 06:55 | field, I wouldn't typically require a
user to type a date into an open text
| | 06:59 | field then use a formatter to verify
and write code to pop-up errors if there
| | 07:04 | is a problem, I just use a date picker.
| | 07:06 | If I am working with say a fixed
range of numeric values, I'd use a stepper
| | 07:10 | control or a slider.
| | 07:11 | Now, if you have something truly
specific, and you need to format either the
| | 07:15 | output or the input, you're going to
need a Custom Formatter, and there is a
| | 07:19 | class called NSFormatter in Cocoa. It's
an abstract class, it's intended to be
| | 07:24 | subclass to help you do that.
| | 07:26 | Now, it's a little specialized and
beyond our scope right now, so look at the
| | 07:30 | documentation for NSFormatter for more on that.
| | Collapse this transcript |
| Using the slider control| 00:00 | Going to make a new Cocoa application
so we can explore the slider control.
| | 00:05 | Jump into my MainMenu.xib file, select
the window and then in the Object Library
| | 00:12 | either come down to or filter on slider.
| | 00:17 | We have Horizontal, Vertical, and
Circular, that's something called a slider Cell
| | 00:21 | but that's really just the
interior part of an NSSlider.
| | 00:24 | I am going to drag on a horizontal one
because these are the most commonly used in OS X.
| | 00:29 | But they all worked the same way,
and if you get familiar with one, the
| | 00:33 | others hold no mystery.
| | 00:34 | I have dragged it onto the center, and I
am just going to grab the handles of the
| | 00:39 | edge and drag it wider just so we
have something to play with here.
| | 00:42 | I am not going to do much else with this
interface, so I will shrink it down a bit.
| | 00:47 | Jumping over into my Attributes
Inspector here, I can see that we have this idea
| | 00:52 | of a Maximum and Minimum values. By
default it's 0 through 100, and the Current
| | 00:57 | value is 50. You can either use the
stepper control here, and as you do this you
| | 01:01 | should see the head of the slider is
actually moving on our Design view.
| | 01:06 | You can change the Minimum and
Maximum values, of course, to be anything
| | 01:10 | that's meaningful for you.
| | 01:11 | There is something called Tick Marks
here, and you don't actually see any tick
| | 01:14 | marks until you change this
value to greater than zero.
| | 01:18 | I am going to change it to say six here.
| | 01:20 | What happens then is that the actual
head--what's often called the thumb or the
| | 01:24 | knob of the slider--changes
from a circle to this pointer.
| | 01:28 | And the tick marks are showing up, but
they're positioned above by default which
| | 01:32 | I find kind of odd because Apple nearly
always positioned tick marks below the
| | 01:36 | slider, so let's change that,
Tick Marks Position Below.
| | 01:40 | And we have the choice also
to only stop on the Tick Marks.
| | 01:44 | Going ahead and running the
application, it behaves as we'd expect to do.
| | 01:48 | I am not locking to the Tick Marks, so I get
a continuous movement from side to side here.
| | 01:52 | But one of the best ways to figure
out how they can and should be used to
| | 01:57 | replicate a familiar Apple feel
is go and see how Apple use them.
| | 02:01 | Now if you want to see a lot of Cocoa
controls in the same place quickly, there
| | 02:05 | is no better place than going to System
Preferences, because you can jump around
| | 02:09 | in here and blast through a whole bunch
of different screens that are going to
| | 02:13 | show you the most commonly used
Cocoa controls and how they're used.
| | 02:17 | And sure these aren't pretty
conventional Cocoa screens, they are not going
| | 02:21 | to win any design awards, but it is a great
place to become familiar with classic usage.
| | 02:25 | So if I am in Sound I can see a
couple of sliders being used there.
| | 02:29 | Then in the Keyboard section I see
sliders being used here for Key Repeat
| | 02:32 | and Delay Until Repeat.
| | 02:34 | And these are typically using
Tick Marks with the Tick Marks below.
| | 02:38 | Now Apple suggests having labels and at
at least the start and the end if you
| | 02:43 | are using Tick Marks.
So let's go ahead and do that.
| | 02:46 | I am going to jump back into Xcode
and make sure my running application is
| | 02:50 | stopped and just giving myself a bit
more space for this slider, drag on a
| | 02:54 | couple of normal labels.
| | 02:59 | I will position one at the start
and then for speed purposes just do an
| | 03:03 | Option-click to put one at the end here.
And change their value.
| | 03:08 | Double-click that from None to Lots.
They are looking a little big right now.
| | 03:16 | That's because if you go to label beneath a
slider it shouldn't be using the normal font.
| | 03:20 | In my Attributes Inspector here I'm
going to change the Font sections for this
| | 03:25 | label to System Small, do
that for the second one as well.
| | 03:35 | And that's more like it.
| | 03:36 | Now you'll actually find switching
back into System Preferences as an example
| | 03:40 | that Apple usually capitalize the words
being used for the certain end of tick
| | 03:45 | marks but not always. Sometimes they don't.
| | 03:49 | And occasionally, you'll also find some
tick marks used without labels at all.
| | 03:53 | Now the value of a slider should
typically be enough by itself. It doesn't have
| | 03:58 | to be shown anywhere else on the screen.
| | 04:00 | If I'm changing this Alert value,
I'm just changing the Alert value.
| | 04:05 | If I'm using a slider with a keyboard
to effect the Key Repeat, it's between
| | 04:09 | Slow and Fast and Off, but I don't see
it updating some other piece of text that
| | 04:14 | says this is 80% or 90%.
But if it's helpful, you might want to do that.
| | 04:19 | One example would be in the
Energy Saver section of Preferences.
| | 04:24 | We have a long slider here.
We have several different labels being used.
| | 04:29 | But as I grab the head of the slider I
get this label above it kind of showing
| | 04:33 | me exactly what these are pointing to.
When I let go, that label disappears again.
| | 04:39 | Again this should only be done if this
is useful, but I'll show you a quick way
| | 04:43 | we can actually replicate
that in our program with no code.
| | 04:46 | I am going to go over into my Object
library and just find a regular label, drag
| | 04:52 | that up here above the slider.
| | 04:55 | And with that label selected I am going
to go over into my Connections Inspector.
| | 05:00 | And so far we have seen using a Delegate
connection, we have seen using Actions
| | 05:04 | and Outlets, but I am
going to do something else now.
| | 05:07 | With the label selected I am going to
come down into Received Actions where I
| | 05:12 | have some interesting ones like
takeFloatValueFrom from takeIntegerValueFrom.
| | 05:15 | I am going to grab the circle beside
takeFloatValueFrom, click and drag over to
| | 05:22 | the slider and let go.
| | 05:25 | I can see the connection being taken up
here. If have done it on the wrong thing
| | 05:29 | I could just hit the little X to break it.
| | 05:31 | I actually don't need this label to
say anything, so I am just going to delete
| | 05:36 | the contents of it and go ahead and run this.
| | 05:41 | So grab the handle of this, move and let go,
move again and let go, move again and let go.
| | 05:47 | We're partway there, but
we have got a couple of issues.
| | 05:50 | One is its not updating until we
actually let go off the slider head.
| | 05:54 | And two is it's little more
information than I needed to know about the exact
| | 05:59 | value of this slider.
So let's fix those.
| | 06:03 | Quit and back into Xcode, I am
going to select the slider here.
| | 06:06 | Now the first problem we were having is
it was only updating when I paused, when
| | 06:10 | I let go of moving the slider.
| | 06:12 | I am going to jump into my Attributes
Inspector, and that's because the default
| | 06:17 | behavior of the slider is to
only update when you let go.
| | 06:20 | But down in the Control section, if I
find the check box marked Continuous and
| | 06:24 | selected that, then just running this
quickly again, we'll find that it updates as
| | 06:29 | soon as possible, and it updates as we
are dragging the slider along, but we are
| | 06:34 | still getting a little bit
too much information here.
| | 06:36 | So back into Xcode and stop the application.
| | 06:39 | I have got two methods that I
could use to take care of this.
| | 06:42 | First I am going to grab the label,
now because it's blanked out its little
| | 06:46 | difficult to grab hold of so I
could use the Expanded view here.
| | 06:50 | And just click around a little bit
until I find the correct one which is this
| | 06:53 | static text area, and I
can see it being highlighted.
| | 06:56 | Well, one thing that I could do is in
the Connections Inspector instead of
| | 07:00 | hooking that up to takeFloatValueFrom, I
could cancel that and then just hook it
| | 07:05 | up to takeIntValueFrom.
| | 07:08 | And that would just truncate
that value, which would work fine.
| | 07:11 | Another way we could do seeing as we're
working with a format as recently is I
| | 07:16 | could find the Number Formatter,
just drag that on top of the label.
| | 07:21 | It's not letting me do that right now
because it's a bit too empty to drag on top of.
| | 07:26 | So let me highlight that static text
field and just give it a simple bit of
| | 07:35 | text here so I actually have
something to grab hold of.
| | 07:42 | Drag on the Number Formatter, let go.
| | 07:45 | And then we can blank out
that value again and run.
| | 07:51 | We have the slider, as soon as I click it
and drag down we have the Integer value.
| | 07:56 | I might change the alignment
of that, but it's working just fine.
| | 08:01 | And what I wanted to demonstrate by
doing this is the ability as we get more
| | 08:06 | and more aware of the different
controls in Cocoa that's very common to connect
| | 08:09 | them to each other.
| | 08:11 | To have one control directly affect
another without having to write any code at all.
| | 08:15 | Now in Code if I wanted to get the
value of the slider, I could set it up as
| | 08:20 | an IB outlet, give it a name, and then
use the floatValue property to get its
| | 08:25 | current value as a float, or the Int
value to get as an Int, or String value
| | 08:29 | to get as a string.
| | 08:30 | And you might be thinking, oh, so NSSlider has a
String value property just like NSText field?
| | 08:36 | Well, yes it does because they all do.
| | 08:39 | Every control has those same properties,
Int value, Float value, String value,
| | 08:44 | Object value and many more besides,
because all of the controls we have been using
| | 08:48 | and all of the ones you'll find here
that you can drag and drop onto the screen
| | 08:52 | end up inheriting from a class called
NSControl, selecting the Classic Controls
| | 08:58 | here, everything like a
Gradient button or a Push button.
| | 09:01 | If I let the pop-up come up, it will
tell me it's a subclass of NSControl.
| | 09:08 | The Text field is a subclass of
NSControll or kind of NSControl, as are the rest
| | 09:13 | of them even say a secure text field
inherits from NSText field which itself
| | 09:18 | inherits from an NSControl.
| | 09:19 | Now that's an abstract class that defines
the core attributes of all controls in Cocoa.
| | 09:25 | And one of the great things about that
is as you start to learn a few of the
| | 09:30 | controls deeply, you realize
that they're often very alike.
| | Collapse this transcript |
|
|
5. Arranging User InterfacesUsing layout views| 00:00 | As we begin to make interfaces with
more controls and more choices on them, we
| | 00:04 | need to start organizing some of those
controls, or at least making it explicit
| | 00:09 | which ones belong together.
| | 00:11 | And when you first start building Cocoa
Applications it is a really good idea to
| | 00:15 | keep in mind some of the things that
Apple do and some of the precedents that
| | 00:18 | they set, whether you're looking at
things like iWork Applications or even just
| | 00:22 | the good old System Preferences.
| | 00:24 | I'll give you some ideas about what
might we expected in an Apple environment.
| | 00:28 | That will give you everything from
say the basic General section in System
| | 00:33 | Preferences which simply uses some
horizontal lines to separate some Radio
| | 00:38 | buttons and check boxes and a few of
these controls what are called Pop-up buttons
| | 00:42 | that we haven't really explored yet.
| | 00:44 | If I jump back in and go over to the
preferences for Mission Control, we'll see
| | 00:48 | these ones here just having several
control like these check boxes inside a box,
| | 00:53 | and in fact, that is what this is
called in Cocoa is just a Box, it's a way of
| | 00:58 | grouping some controls together and
optionally giving them a name like this
| | 01:01 | Keyboard and Mouse Shortcuts box.
| | 01:03 | Jumping over to Desktop & Screen
Saver, we have the first of many what are
| | 01:08 | called Tab Views, where we have two or three or
four clickable links at the top of this window.
| | 01:14 | I'll jump to Security & Privacy.
I have four different Tab views, each one
| | 01:20 | containing an independent collection of controls.
| | 01:23 | And Keyboard, for example, we have
just a couple of sliders, some labels,
| | 01:27 | check boxes, and regular buttons.
| | 01:29 | And in the second Tab, Keyboard
Shortcuts, we have something this little more
| | 01:33 | complex here. We have something called a
Split view that separating these two
| | 01:37 | sections, allowing me to
resize the amount that I see.
| | 01:40 | Now while we have seen buttons and
check boxes and sliders, we haven't seen these
| | 01:45 | controls yet. We're going to explore these in the
next chapter, the ones with the lists of selections.
| | 01:51 | What I'm focused on right now on the
Containers themselves, the Dividers, things
| | 01:55 | like the Tab Views and the Boxes and
everything that I have just mentioned
| | 02:00 | Horizontal Lines, Vertical Lines, Boxes,
Tab views, Split Views all the typical
| | 02:04 | ways to contain surround and set out
controls inside the same window. These are
| | 02:10 | all the available for us to drag and
drop in Interface Builder there in the
| | 02:14 | Object Library in a section called Layout Views.
| | 02:17 | There's eight of them here, ranging from the
very simple to just being able to drag
| | 02:22 | on say a Vertical Line and resize that,
to more complex like the Vertical Split
| | 02:28 | view or Horizontal Split view.
| | 02:30 | Going to just delete that vertical line
and drag on a couple of things to help
| | 02:35 | me set out this window.
| | 02:37 | First I'll drag on a Tab view here. I'll
use the guidelines to help me laid out.
| | 02:41 | And with the Tab view itself selected, I
can see that we start off with two tabs.
| | 02:45 | It's invisible on the page.
It's visible here in my Attributes Inspector.
| | 02:49 | I can change that to three or to four.
| | 02:52 | I do want to be careful because each
individual tab will switch my focus here, so
| | 02:57 | if I click on the word Tab again,
we're actually jumping into that first tab
| | 03:02 | which will allow me to drag
and drop different controls here.
| | 03:05 | So this is occasionally where it's
useful to expand the Dock to allow me to
| | 03:09 | select the Tab view itself rather than
the independent pieces, what are I refer
| | 03:14 | to as the Tab view Item, which
themselves are very useful to use such is the
| | 03:18 | second item, the third, or the fourth.
| | 03:22 | Selecting any of them allows me to drag on
the regular controls or even other views.
| | 03:27 | The Push buttons, Labels, Text Fields, and so on.
| | 03:31 | And each of these are completely
independent, supported both in your program when
| | 03:35 | it runs and in Interface Builder
itself. If I click the second tab twice we'll
| | 03:39 | shift into that mode, and I can
drag on some new content here.
| | 03:43 | In this case perhaps Date
Pickers and a Combo Box or two.
| | 03:48 | Now if necessary, one of the things you can
also do is have containers inside containers.
| | 03:53 | I could switch back to my Layout view
section here and decide to drag a Box
| | 03:58 | into that second tab.
| | 03:59 | Now if I made up my mind that what I
really I wanted to have was these three
| | 04:04 | controls inside that box, well I could
move them across, but another way to do
| | 04:08 | it is use the Command key and select all
three of those, and I want to be sure it's
| | 04:13 | just those three selected.
| | 04:14 | And come up to the Editor
section and say Embed In > Box.
| | 04:20 | And that gives me the Box with just
those three controls. And if you notice,
| | 04:24 | that as I move the box around
those are considered enclosed in it.
| | 04:28 | And that's the way you'll see
them over here in the expanded Dock.
| | 04:34 | Just collapsing some of these
disclosure triangles to make it a bit more
| | 04:37 | obvious, we have the Tab view which
itself includes the separate items, but if I
| | 04:42 | select the second item and expand
that, we have the view inside that that
| | 04:47 | contains two boxes. One of the boxes
itself can be expanded, and that contains
| | 04:52 | the Combo Box directly.
| | 04:53 | The thing you have to be careful of here
is if you're rearranging an Interface I
| | 04:57 | don't want to select the Box--I'm
thinking I can delete it without deleting
| | 05:01 | what's inside it because if I do hit
the Delete key it all goes away, including
| | 05:05 | all of its contents.
| | 05:07 | So I'll just Command+Z here to bring that back.
| | 05:11 | But of course the Tab view that I'm
looking at here is completely independent of
| | 05:14 | whatever else is happening on that window.
| | 05:17 | So if we drag on the Box underneath it,
and I can double-click the name of that
| | 05:21 | just to give it a new name, or you
can set it to blank if you want to.
| | 05:27 | Just to quickly drag on the couple of
things, if I did expect to create say a
| | 05:31 | few Text Fields and a few Labels at
the same time, one quick way of doing that
| | 05:36 | is coming down and finding what's called a
form which begins by adding two at a time.
| | 05:40 | Though, if you have more space you can
actually increase that to three or four or
| | 05:45 | however many you need. I'm going to
bring that back down to two rows.
| | 05:49 | Now just quickly running this, we have no
code whatsoever, nothing has been hooked
| | 05:53 | on, no outlets, no actions.
| | 05:55 | But it's very easy to start to set
this out and just start to emulate some of
| | 06:00 | the kind of presentation styles that
you'd see in say System Preferences.
| | 06:05 | The last thing that I wanted to show was
in that Layout view section, the Split view.
| | 06:09 | I'm going to select the third tab
which right now for me is blank.
| | 06:14 | We can drag one of these on--say a
Vertical Split view--and position that,
| | 06:19 | arrange it, resize it.
| | 06:21 | Right now, the individual sections
inside the say Custom view have nothing in
| | 06:25 | them whatsoever. We can drag our
own controls in to it if we want to.
| | 06:29 | But what's more usual is that you
use a Split view in conjunction with a
| | 06:32 | couple of the controls we haven't
really explored yet, most of which are found
| | 06:35 | in Data Views, such as the Browser and the
Outline view that are showing lists of content.
| | 06:42 | It's unusual that we'd use a movable
Split view and have just buttons and
| | 06:46 | check boxes on either side of it.
| | 06:48 | And while I could drag and drop in a
Table view or Outline, we can actually
| | 06:53 | use the same technique that we used
on the second view here with embedding
| | 06:58 | controls inside another one.
| | 07:00 | So I'm going to jump to that fourth
tab, and just ignoring the Split view
| | 07:04 | completely, I'll drag on first a Browser.
Browser we'll see a little later.
| | 07:10 | That's something that you might use and
say a Finder window, and then after this
| | 07:15 | I'm going to grab a Table view just to
have a different control to work with.
| | 07:18 | I'll drag that into that tab as well.
| | 07:21 | Now if I decide what I want it once to
have a Split view between these two, I
| | 07:27 | really need to combine them together.
| | 07:29 | So I'm going to select the second
one--which is the Table view--then use my
| | 07:34 | Command key and select the first one.
| | 07:36 | And again go up to Editor > Embed In and
one of the choices here is Split view.
| | 07:42 | Things about it for a second and
gives us that. We may need to resize some
| | 07:46 | that content, as you can see.
| | 07:47 | Just to make it little more even, I can
of course still get to each individual font.
| | 07:53 | If I expand this Split view I'll
see that it shows me it's containing both
| | 07:57 | the first Browser here and the Table view.
| | 08:02 | So I'm just going to go ahead and Run
this, and I can see up at the top I have
| | 08:07 | this scrollable Split view here.
| | 08:09 | We can switch to one which has no
content in either end. We have got the boxes,
| | 08:13 | we have got the regular controls.
| | 08:15 | So in just a few moments, pretty easy
to see how we can emulate something that
| | 08:19 | we'd see in, say, System Preferences.
| | 08:20 | But one thing that is actually
missing between that and a typical System
| | 08:25 | Preferences is the Toolbar, a very
common thing in OS X Applications, and we'll
| | 08:30 | see how to work with those in a moment.
| | Collapse this transcript |
| Exploring Auto Layout| 00:01 | In 2011 Apple released AutoLayout, a
new method for how Cocoa user interfaces
| | 00:05 | arrange and resize and lay themselves out.
| | 00:08 | Now AutoLayout replaces the older
technique called Struts and Springs, which is
| | 00:13 | still currently what you
used in iOS development.
| | 00:15 | And with Xcode 4.3, AutoLayout became the
default layout method for Cocoa projects.
| | 00:22 | And I am in 4.4 now, and it's what we
are going to be using in this course.
| | 00:26 | I won't be talking about the
older Struts and Springs methods.
| | 00:29 | Now we have been using AutoLayout
already, and a lot of the time it just works.
| | 00:33 | It's worthwhile to know a little
bit more about what's going on.
| | 00:36 | So I have just created a new out-of-
the-box Cocoa application, haven't
| | 00:40 | done anything to it yet.
I am going to drag on a button or two.
| | 00:44 | Now we have seen the guidelines
that appear when you do this.
| | 00:47 | And let me tell you that AutoLayout is
not at all about these guidelines, and
| | 00:52 | it's not really even about the button,
it's about what happens when you let go.
| | 00:58 | We see the guidelines here on the left
and on the top, the dotted blue lines,
| | 01:02 | but if I let go you'll see another
couple of lines appear, in this case to the
| | 01:06 | top and to the left.
This is what AutoLayout is all about.
| | 01:11 | These are what are referred to as Constraints.
| | 01:14 | And Constraints describe a relationship
between two visual elements, two views,
| | 01:18 | like the relationship between the
button and the top of the window here or the
| | 01:22 | relationship between the button
and the left-hand side of the window.
| | 01:26 | If I click on the button over here on
the right, I see two different constraints
| | 01:30 | again to the top but this time to the right.
| | 01:33 | As I'm dragging on different elements
onto the page, different constraints are
| | 01:38 | added depending on which part
of the window that I put them on.
| | 01:42 | Oftentimes those constraints are based
on say the right-hand or left-hand side
| | 01:45 | of the window, but if I'm trying to
arrange buttons beside each other, say down
| | 01:49 | here, for example, I will also get constraints
between the user interface elements themselves.
| | 01:55 | So this selected button doesn't have a
constraint to the right-hand side of the
| | 01:59 | window, but it does have a
constraint to the button next to it.
| | 02:02 | And depending on the circumstance, a
constraint might try and keep things
| | 02:06 | together or keep things apart or both
at the same time, in this case keep these
| | 02:10 | buttons close but never allow them to touch.
| | 02:13 | Well, Constraints aren't actual objects
and Cocoa, it's the NSLayout constraint object.
| | 02:18 | They are added by Interface Builder
as we edit our XIB files.
| | 02:23 | So if you click any of the objects,
whether they are buttons or any other kind
| | 02:27 | of user interface elements, you'll then
see the constraints that affect that object.
| | 02:31 | For this one now I have three
constraints, the right-hand, the bottom, and the
| | 02:35 | one to the next button.
| | 02:37 | You can then actually click any one of
these constraints. Sometimes they are a
| | 02:41 | little difficult to grab hold
of, but you can usually manage.
| | 02:44 | When you click that constraint, you'll
see an amber highlight that will show you
| | 02:48 | what objects that constraint affects,
so this one between the two affects these
| | 02:53 | two buttons, this
constraint just affects this button.
| | 02:56 | Now as a side note it's a common
mistake for new Cocoa developers to
| | 03:00 | accidentally have a constraint
selected when they think they have a button or
| | 03:04 | some other element selected.
| | 03:06 | So if you see the amber highlight, know
that you have a constraint selected, you
| | 03:10 | don't want to be trying to Ctrl-drag
from a constraint to a code file.
| | 03:14 | When buttons are properly
selected they should be blue.
| | 03:17 | You can also get to
constraints from the expanded Dock view.
| | 03:22 | So here, for example, inside the Main
view I can see the different constraints I
| | 03:25 | have and actually take turns and
selecting different ones vertical space,
| | 03:29 | horizontal space, and so on.
| | 03:31 | These are true objects. With any one of
them selected, I actually have elements
| | 03:36 | in the Attributes Inspector that I can
affect, and we'll see this in a moment.
| | 03:40 | Now most of the time you don't add
constraint yourself, you just let Xcode do it.
| | 03:45 | But occasionally you can,
occasionally it's needed and worthwhile.
| | 03:49 | As I am dragging on elements, Xcode
makes a pretty good guess of where the
| | 03:52 | constraints should be, whether that's
dragging them on for the first time--
| | 03:56 | in this case it's choosing to add
constraints to the left and to the bottom--or
| | 04:01 | if I move things around, say up to
the center here it's going to add two
| | 04:05 | constraints, this one which is making it
a center constraint, and this one which
| | 04:10 | is tying it to the top.
| | 04:12 | So you can feel free to rearrange
the object, Xcode will rearrange the
| | 04:16 | constraints for you.
| | 04:17 | I have added nothing but buttons right
now so I am going to grab a couple of
| | 04:22 | other things here, and let's grab a Layout view.
| | 04:25 | I am just going to drag on a Tab view here.
| | 04:28 | And drag that wide allowing the
guidelines to give me suggestions for where it
| | 04:32 | should be positioned, but noting
that with this Tab view selected I have
| | 04:36 | multiple constraints here, to the
left and to the right, to the bottom, and
| | 04:40 | you know there is a constraint above
that button, and there is a constraint
| | 04:44 | below the button here.
| | 04:46 | It's interesting often to see how
Xcode rewrites this as you are editing it.
| | 04:50 | If I delete that button and select
the Tab view again, we'll see now the
| | 04:54 | constraint that's focused
is really this one over here.
| | 04:57 | And as I keep on going adding
different things, say a pop-up button over here
| | 05:04 | on the left and deleting the button on the right,
we'll see a different kind of focus going on.
| | 05:12 | Sometimes it will take you a bit of
rearranging if you want to get the
| | 05:16 | constraints back to where
you thought they should be.
| | 05:18 | And the guidelines can be very useful for that.
| | 05:20 | In this case I rearranged it a
little bit to make sure that there was a
| | 05:24 | constraint between the Tab
view and the button above it.
| | 05:27 | And we'll get more into
rearranging some of these in a minute.
| | 05:30 | So I am going to go ahead and run this
just with Command+R. As we'll see in a
| | 05:35 | moment, we don't actually even need to
run this application to see the impact of
| | 05:38 | AutoLayout, because it works
in the Interface Builder view.
| | 05:43 | But as I resize this, it's
actually looking pretty good.
| | 05:46 | The Tab view is expanding both
horizontally and vertically, the buttons at the
| | 05:51 | bottom right are keeping
together the way they should.
| | 05:54 | Although if I start to collapse it a bit,
we are getting some impact we probably
| | 05:58 | don't want, so we'll see how to fix that a bit.
Quit out of that and back into Xcode here.
| | 06:04 | Well, first, I am going to rename a
couple of things because it's important to
| | 06:09 | understand how Xcode is going to work with this.
| | 06:11 | I will rename this button down at the
bottom left to Import..., which will make
| | 06:16 | the button a little bit wider, but
because of the constraints it will still be
| | 06:19 | fixed on the left-hand side.
| | 06:22 | On the other side, if I change this
button to the words OK, take a look at the
| | 06:25 | button to the left of it.
| | 06:27 | The OK button will collapse, and this
one will move to the right based on the
| | 06:31 | constraint that's written there.
| | 06:33 | Essentially what's happening is what
you would hope would happen, and most of
| | 06:37 | the time it just works.
| | 06:39 | So we don't have to actually run the
application, as even in design view we can
| | 06:43 | see the impacts of the
decisions that we are making here.
| | 06:46 | One of the problems is that entire
Tab view is collapsing, which is not
| | 06:51 | something that I really want.
How can I fix this?
| | 06:54 | Well, we are going to add a manual
constraint. I am going to select this Tab
| | 06:58 | view, making sure that it's highlighted,
and I could double-check that in the
| | 07:03 | Jump bar or in the Dock.
| | 07:04 | And then go up to the Editor section,
and what we are interested in is the Pin
| | 07:09 | menu, this is where most of your
manual constraints can be added.
| | 07:12 | I want to stop this from shrinking
too much when we move it up vertically.
| | 07:17 | So I'm going to give it a
specific minimum height.
| | 07:20 | So I will say Pin > Height, and it adds
into this constraint and selects it for me.
| | 07:26 | And right now this is set to a
height constraint of being equal to 240;
| | 07:31 | it has to be equal to 240.
| | 07:33 | That's not what I want,
which is fine. I can change that.
| | 07:36 | I just don't want to get too small, so
I am going to say it should be greater
| | 07:40 | than or equal to 100.
| | 07:43 | I don't care if it's more than
that, but it shouldn't be any less.
| | 07:46 | I will go ahead and hit Command+R
just to see this running. We can continue
| | 07:51 | to resize, we can drag this wider
but as I make it shrink I can't make it
| | 07:56 | close anymore than that because
it's actually now staying at 100,
| | 07:59 | that's the minimum size.
| | 08:00 | We're still having problems this
way, though. It's collapsing too much.
| | 08:05 | Well, I could do another fixed width
constraint, perhaps even based on say the
| | 08:11 | button width to make sure that these ones
don't collapse too much, but that's a bad idea.
| | 08:15 | In fact, as much as we possibly can
we want to avoid any fixed numbers.
| | 08:20 | Because say if I go ahead and localize
or internationalize this application, I
| | 08:25 | might automatically have the text on
these buttons changing and being replaced
| | 08:30 | with different amounts of text based
on the culture settings of the operating
| | 08:33 | system that user is running this App on.
| | 08:35 | So I don't know exactly how
wide these buttons will always be.
| | 08:38 | Plus, more than that, I don't want to have
to stop measuring the width of my buttons.
| | 08:42 | I really would just like the Import
and the Cancel button to maintain a good
| | 08:47 | distance from each other.
| | 08:48 | But what is that distance? Is that 20
pixels or 40 pixels? What might it be on
| | 08:53 | perhaps a Retina display
versus a normal display?
| | 08:56 | Well, I don't care, and I don't want to have
to think about that, luckily I don't have to.
| | 09:01 | I am going to add another constraint,
and I am going to do that by first
| | 09:05 | selecting both buttons.
| | 09:06 | So select the Import one, then the
Command-click the Cancel one. We have both
| | 09:10 | buttons and nothing else selected.
| | 09:12 | Up to the Editor menu, down to Pin, and
this time what I'm interested in is the
| | 09:18 | Horizontal Spacing, though again, I am
going to have to tweak it a little bit.
| | 09:22 | We add that, and we get a new constraint.
The constraint is selected. I have the
| | 09:26 | amber outline, telling me
which two object this affects.
| | 09:29 | What it's saying right now is this need
to be equal to 229. That's not what I want.
| | 09:35 | Again I want just a minimum size. I want
some kind of distance between the two.
| | 09:40 | So I want a greater than situation
going on here, and it's asking well do you
| | 09:45 | want a greater than 229, well no, I don't.
| | 09:47 | Now I could put in something like 20 or
15, what's a better idea here is that I
| | 09:53 | just click standard, and
that makes it automatic.
| | 09:57 | I'm telling AutoLayout you go figure
it out based on your own internal rules.
| | 10:02 | So go ahead and Command+R with this
one, now we drag it wider we get the
| | 10:07 | interface resizing itself correctly, if
I move it up towards the top we have the
| | 10:12 | minimum height of the Tab view, and as
we close here we see that the buttons get
| | 10:17 | the perfect distance from each
other and don't get any closer.
| | 10:21 | Very flexible. AutoLayouts are great way
to allows us to easily create apps than
| | 10:26 | in other environments would often
require writing code to handle window resizing
| | 10:30 | and measuring the relative
distance between objects.
| | 10:33 | Now this is just an introduction.
It can get more complicated than that.
| | 10:37 | One thing to be aware to be aware of
is that all constraints--and I have one
| | 10:41 | selected here--have priorities,
which by default begin at 1,000.
| | 10:45 | Sometimes you can get some worthwhile
behavior by having different constraints
| | 10:49 | with different priorities.
| | 10:50 | Now that's beyond what we
need to do in this course.
| | 10:53 | So take a look at Apple's
documentation on AutoLayout for more on that.
| | Collapse this transcript |
| Adding and editing toolbars| 00:00 | So a very common need for a Cocoa
application is adding the classic Macintosh
| | 00:05 | style Toolbar, as we're
looking at right now in Xcode.
| | 00:08 | I have a new Cocoa application, I have
just created, I haven't done anything to it
| | 00:13 | yet, and I'm going to switch over to
these Windows & Menus section of the Object
| | 00:17 | Library, and this is where we find the Toolbar.
| | 00:20 | Simply drag and drop it. It's one of
the few times it doesn't matter exactly
| | 00:24 | where you put it because Xcode is
going to say, "I don't care where you drag
| | 00:28 | this, the Toolbar always goes at the top."
| | 00:30 | Now begins with a couple of icons for
Color, Fonts, and Print, just to give you
| | 00:36 | something to work with, but you
can delete those if you want to.
| | 00:39 | Now the Toolbar itself
doesn't have a lot of options.
| | 00:42 | If I have it selected and look at my
Attributes Inspector, I get a choice here
| | 00:46 | of whether to show the Icon and Label
or just the Icon or just the Label, but
| | 00:52 | other than that, there is not
really a lot going on here.
| | 00:55 | So I'll leave at the
default state of Icon and Label.
| | 00:58 | The first request of most people
is how do I add something to it?
| | 01:01 | Now I have seen people try and quickly
say drag and drop things like a Push
| | 01:06 | button onto the Toolbar.
| | 01:08 | That is not going to work
and has no effect at all.
| | 01:12 | First, you need to be editing the
Toolbar correctly, and you do this slightly
| | 01:16 | differently from most of
the things we have seen so far.
| | 01:18 | So if the Toolbar is deselected,
click it to select it, and if nothing pops
| | 01:24 | up, click it again.
| | 01:26 | You're looking for this,
the Toolbar Editing Sheet.
| | 01:29 | This is how you make any changes to the Toolbar.
| | 01:33 | And again, just to show that's usually
from a deselected state, you need to
| | 01:37 | select the Toolbar then click
it again to pop up the sheet.
| | 01:40 | So there is two sections to this.
| | 01:43 | What is Allowed on the Toolbar and below
that what is the Default arrangement of
| | 01:48 | these icons, because Cocoa supports user-
driven customization of the Toolbar, so
| | 01:53 | an application can have many more
options available than just the one shown when
| | 01:57 | they open the app for the first time.
| | 01:59 | So the lower section is what
describes what we currently see on the user
| | 02:03 | interface and what arrangement it has.
| | 02:06 | And we can delete from the lower
section to change that, you'll just drag off.
| | 02:10 | So I'll grab the Fonts, drag out of
that square, and let go, and we get
| | 02:14 | the little puff cloud.
| | 02:16 | The Font option is still there, but
it's no longer on the shown Toolbar.
| | 02:20 | So to add new items to the toolbar, you
first need to add them to the top area so
| | 02:25 | they become Allowed
Toolbar Items. What do you add?
| | 02:29 | Well, you actually can add
just a regular Push button.
| | 02:32 | I see the plus sign there, but I'm
not going to do that, it's a bad idea.
| | 02:37 | Regular Push buttons should not be
added to a typical Mac style toolbar.
| | 02:42 | There are specific controls
we should be adding to it.
| | 02:45 | One of the easiest ways is that in the
Object Library here I just filter on the
| | 02:50 | word Toolbar, and I'll
have several options appear.
| | 02:54 | There is a handful of these, several
of them are really the ones that are
| | 02:58 | already there, the Print Toolbar Item,
the Show Colors Toolbar Item, the
| | 03:01 | Show Fonts Toolbar Item.
| | 03:04 | There are three here for a Separator
and Spacing, and this is probably the
| | 03:08 | classic nonspecific one, the Image Toolbar Item.
| | 03:12 | I'm going to drag that across
into the top area and let go.
| | 03:16 | This supports an image but doesn't
have one yet, and it's called the
| | 03:19 | Generic Label Toolbar item.
| | 03:21 | With that selected, I'm going to go
over into my Attributes Inspector and give
| | 03:25 | it a more useful name, I'll call this
one Inspect for a Label, and I'll also
| | 03:30 | change its Palette Label to Inspect.
| | 03:33 | And this is the label that shows up
when you're actually editing the Toolbar,
| | 03:37 | either here or if you're
allowing the user to do that.
| | 03:40 | So typically your Label and
Palette Label are the same.
| | 03:44 | And with that Toolbar item selected, I can
select from the dropdown here of the Image Names.
| | 03:48 | We currently have the Apple images here.
| | 03:51 | Again, you can get a breakdown of all of these
images in the Human Interface Guidelines.
| | 03:56 | I'm going to select a fairly simple
one here which is the NSInfo Image.
| | 04:00 | You can of course add your own by
dragging your own PNGs into your supporting
| | 04:06 | files folder and they will show
up here as well in the dropdown.
| | 04:10 | So that icon is now Allowed, but it's
not on the Toolbar, we can see it's not
| | 04:14 | showing up in the background here,
because I have to now drag it from the top
| | 04:18 | into the bottom section.
| | 04:21 | After I have dragged it there, I
could if--I wanted to--rearrange it.
| | 04:24 | Move it to the left on the left-
hand side of the Flexible Space here or
| | 04:28 | back over to the right.
| | 04:29 | However, if you notice, and this would
be the same if we run this application,
| | 04:33 | it's currently showing up as being
grayed out, and that's because it will by
| | 04:38 | default kind of analyze itself to
understand whether it's calling a method or
| | 04:42 | not, and this one isn't.
| | 04:44 | Going back in to edit this, again,
select the Toolbar, and then click it again.
| | 04:49 | If I select that item, we do all the
configuration from the top section, the
| | 04:53 | bottom section is simply
what's there and how it's arranged.
| | 04:57 | That's what we have got is the
Auto Validation Behavior going on.
| | 05:00 | It's detecting, but it's not doing
anything, so it's graying itself out.
| | 05:04 | I could either turn off Auto Validation,
or I could of course just hook this up
| | 05:09 | to some background code, and you'd do this
exactly the same way you do it with a regular button.
| | 05:14 | In this case, I could just shift into
Assistant mode in the Editor and Ctrl-drag--
| | 05:20 | and again we do all the changing and
configuration from the top section--
| | 05:24 | Ctrl-drag into my AppDelegate
header file or into a custom class.
| | 05:28 | And here I could set it up as an
Outlet if I wanted to address this in code.
| | 05:33 | But if I want to make it an action,
and we'll just call that action,
| | 05:37 | doSomething, we have now connected it.
I'm going to shift back to the regular Editor.
| | 05:42 | Occasionally, depending on your
screen size, you may find a bit of screen
| | 05:45 | corruption in Xcode there but just
scroll up and down usually fixes it.
| | 05:49 | So now I'll click Done.
| | 05:50 | It hasn't yet Auto-validated here, but
if I hit Command+R to go and run this
| | 05:55 | application, I should expect to see
it's showing up properly, because it is
| | 06:00 | hooked up to a method even if
there's nothing actually in that method.
| | 06:03 | And there we go, it is clickable.
But this isn't the only option.
| | 06:08 | These are the classic image-driven
Toolbar icons with the optional label
| | 06:12 | beneath, but sometimes you
want something a little different.
| | 06:15 | If we take a look at Xcode itself, for
example, we don't have those image icons,
| | 06:19 | we have these Segmented
controls or the Run button.
| | 06:23 | If I were to open up Safari, we see a
different style in the Toolbar, usually
| | 06:27 | with this classic Back and Forward
button, and these are a very different style
| | 06:32 | but we can do these too.
| | 06:34 | Well, know that you don't mix the big
icon style that we're looking at here with
| | 06:38 | that smaller style most of the times, so
what I'm going to first do is just drag
| | 06:42 | off the ones I'm using.
| | 06:44 | If I wanted to completely delete them
from the Toolbar I drag them off the
| | 06:48 | Allowed Toolbar Items section, like
taking the Colors one and just dragging it
| | 06:52 | off, but I don't have to.
| | 06:55 | So my Toolbar is currently empty, and
what I'm going to do is go into my Object
| | 06:59 | Library, into the regular Controls section--
making sure I don't have anything on the filter.
| | 07:05 | I said I didn't want to add a Push
button, and I don't. The one I want here is
| | 07:09 | the Rounded Textured button
that's allowed on the Toolbar.
| | 07:13 | And if you're curious about remembering that,
it's in the Human Interface Guidelines.
| | 07:17 | Take a look at that, and it will tell you
what buttons are allowed in the toolbar.
| | 07:21 | So we drag on a Rounded Textured button, again,
into the top section, which is where we say
| | 07:25 | what's allowed and where we configure them.
| | 07:28 | Well, when I do that, what it's doing is
enclosing that button in a toolbar item,
| | 07:33 | so we have really a container going on
here, and if I'm editing this toolbar and
| | 07:39 | select that, click off first.
| | 07:42 | First I see the Toolbar Item
which just has the label, and this is
| | 07:46 | containing the button itself.
| | 07:48 | So I'd click it again and see my Inspector
change into the actual button inside there.
| | 07:53 | So I'm going to strip out the title
here, because I want to have an icon on
| | 07:58 | that, not a message, and in the
button itself I'm going to find the Image
| | 08:03 | section and just drill down and find--
let's go for the refresh template, which
| | 08:08 | is just a little Refresh icon.
| | 08:10 | Well, that button is now a little too
wide, so I'm going to drag it a little
| | 08:14 | smaller, again making sure to click it a
couple of times to, edit it, and there we go.
| | 08:20 | And then clicking off to deselect it,
I'll drag it into the lower section.
| | 08:25 | Occasionally what you'll have
happened here is it will show up a little too
| | 08:29 | large, and that means that some
place it thinks it's got a minimum width.
| | 08:33 | Even though that's not showing up
probably here in the Allowed Toolbar Items
| | 08:37 | section, I'm going to click it.
First, take a look at the Toolbar Items section.
| | 08:42 | It's got the label here, Custom view.
| | 08:44 | We really don't need that
because I don't want a label on it.
| | 08:47 | And then I'm going to click into the
Size section here, we have got a Minimum
| | 08:52 | and Maximum width here.
| | 08:55 | I'll change the Maximum down to say 40,
and I can immediately see it had an
| | 09:00 | impact there on that icon itself.
| | 09:02 | You may have to do a little bit of
experimentation to figure out what the best
| | 09:06 | size is, but that seems to do the trick.
| | 09:08 | The only problem we have right now is
this is on the wrong side of the Toolbar;
| | 09:13 | I do have a flexible Space arranger
here so I'm going to drag that to the
| | 09:17 | left-hand side, and we move
over there. Well, what's next?
| | 09:19 | Another common thing we'd have in this
style of toolbar would be a Search Field.
| | 09:23 | That one is very easy to add, so I
can just drag that into the top section.
| | 09:28 | I'll change its label here to
Search, which often is allowed,
| | 09:32 | and then grab and drag it into the
lower section where it does typically appear
| | 09:37 | on the right-hand side.
| | 09:39 | And the last thing I'm going to add
here is the classic kind of Back and Forth
| | 09:43 | icons that you see in Safari and in
quite a few others programs as well, just the
| | 09:48 | Left Right options here.
| | 09:50 | This is done by using what's called a
Segmented Control, and we haven't seen that one yet.
| | 09:55 | You don't have to add this to Toolbar,
you can add this anywhere, but I'm
| | 09:59 | just going to filter on the Object
Library on this segment, and we'll find
| | 10:02 | the Segmented Control.
Drag that into the top section.
| | 10:05 | By default it has three elements, in
fact, what's being used for Segmented
| | 10:10 | Control up here is these Editor
Icons and the view Icons in Xcode itself.
| | 10:15 | That's not quite the effect that I want
here, so I'm going to look at it, and go
| | 10:19 | okay, this is my Segmented Control.
| | 10:21 | Currently I have the Toolbar Items
selected, the container, I need to click on
| | 10:26 | it again to get into the
Segmented Control itself.
| | 10:30 | This is what I wanted to see.
| | 10:32 | In the Attributes Inspector, I want to
change it from three segments down to two
| | 10:37 | because it's just back and forth is
all I want, and in the same Attributes
| | 10:42 | Inspector this allows us to
select between Segment 0 and Segment 1.
| | 10:46 | So Segment 0, I'm going to select
the Image there to be the GoLeftTemplate,
| | 10:52 | NSGoLeftTemplate will work and then switch to
Segment 1 and change that to the NSGoRightTemplate.
| | 10:58 | Now currently one all of them is
depressed, meaning it's Enabled and Selected.
| | 11:05 | It's not the behavior that I actually
want of this Segmented Control, it can
| | 11:10 | support multiple behaviors, including
the style that we see in Xcode where one
| | 11:14 | stays depressed, it stays pressed.
| | 11:17 | You jump from Standard Editor
to Assistant Editor and back.
| | 11:20 | I want these really to behave more
like regular Push buttons, just momentary.
| | 11:24 | So I'm going to uncheck Selected.
It takes us back to that default view.
| | 11:30 | Programmatically what you'd also often
do here is work with the Enabled state of
| | 11:34 | it, so if going back wasn't actually
valid, you would set that particular
| | 11:39 | segment to not Enabled,
and it would gray it out.
| | 11:42 | But I'll just leave them both on
for purposes of our Toolbar here.
| | 11:46 | So with that selected, I will grab it
and drag it down into the bottom section.
| | 11:51 | First often having to deselect it just
to come out of the Editing mode, drag
| | 11:55 | it in there, and once it's dragged into the
lower section over onto the left-hand side.
| | 12:00 | Now currently it has a label which I really
don't need, so I'm going to strip that out.
| | 12:06 | Click Done, and then let's
take a little look at this.
| | 12:11 | Now one of the problems that we have
is the segmented control is still acting
| | 12:15 | like a segmented control which is just
a option that we have in there, so I'd
| | 12:19 | have to go back in and edit it again,
clicking it once to first select that.
| | 12:24 | Looks like we might be standing a
little bit too wide, so I'm going to shrink
| | 12:28 | that one down to a Maximum Width of
say 60 to bring those two together.
| | 12:33 | But after I have added the Toolbar Item,
click again inside it, because what I
| | 12:37 | want to do is find the Segmented
Control itself, find the Attributes Inspector
| | 12:41 | and change its mode from Select One, which
means one of them will be selected, to Select None.
| | 12:47 | It will respond to the presses, but
neither of the buttons will actually stay
| | 12:51 | in the pushed state.
| | 12:53 | Come out of that and click Done, and I
think what we could do it here is select
| | 12:57 | the Toolbar and just change it to Icon
Only, Command+R, and we now have a pretty
| | 13:04 | classic Mac style custom Toolbar with
custom rounded textured buttons, segmented
| | 13:09 | controls, and search field.
And that's the basics of using the Toolbar.
| | Collapse this transcript |
|
|
6. Using Data ControlsAdding data views| 00:00 | We have seen a couple of controls so far
like the Combo Box, where if I drag that
| | 00:05 | onto a window I can then use the
Attributes Inspector and manually add different
| | 00:10 | items here as the list of entries.
| | 00:13 | But this kind of thing is not going to
work very well when we have something
| | 00:16 | more complex, when there's lots of
data or multiple columns or data that
| | 00:21 | changes all the time.
| | 00:22 | So with the several controls, we need to be
able to load them with data from our own objects.
| | 00:26 | Everything from simple arrays to
complex objects that change every time the
| | 00:30 | program runs, and even
while the program is running.
| | 00:33 | And you'll find these controls in the
Data Views section of the Object Library.
| | 00:38 | Now the first looks like there's a lot
of stuff here, but most of the elements
| | 00:42 | you see here are ingredients, different
cells, tiny customizable pieces that fit
| | 00:48 | into the larger controls.
Like the first four here at the top.
| | 00:52 | Right at the top is the Table view,
this is the most common, most used the
| | 00:56 | classic data-driven control
of rows and columns of data.
| | 01:00 | It starts off very basic
but can be hugely customized.
| | 01:04 | A classic example might be in System
Preferences in the Sound section, if we're
| | 01:09 | selecting a sound effect.
This is a Table view here.
| | 01:12 | It's got two columns, Name and Type, so
we have the headers with the name and
| | 01:16 | type at the top, we can scroll up and
down and select different entries on it.
| | 01:21 | The Table view can be as basic as
something that we would see in the Displays
| | 01:26 | section, just a simple list.
| | 01:28 | One column, no header, just a
list of entries we can select from.
| | 01:33 | Or at the other end of the scale, we
could take a look at something like the App
| | 01:37 | store, the list of purchase software.
This could be done in a Table view too.
| | 01:41 | It's still multiple rows and
multiple columns to spend more time on the
| | 01:45 | presentation of each individual row.
We also have the alternating lines here as well.
| | 01:51 | I'm going to jumping back into Xcode.
| | 01:53 | Well, if that was the Table
view, what else do we have?
| | 01:56 | We have here the Outline view, the
Browser, and the Collection view.
| | 02:00 | Here is the best way to explain these.
I'm going to jump into a Finder window.
| | 02:05 | Now for a second here, I'm just focused
on the main section of content, forget
| | 02:10 | about the left-hand side, I'll
talk about that in just a second.
| | 02:13 | What I'm looking at here, which you
should be very familiar with, where we
| | 02:16 | have the Disclosure Triangles that allow us
to expand and collapse different sections.
| | 02:21 | This is the Outline view that
you see in that part of Xcode.
| | 02:26 | Rows and columns of data but we can
expand and collapse different parts of that.
| | 02:31 | Classic example here is of course a
file system, but you can use the Outline
| | 02:35 | view for your own data, too, if your
data is best presented as multiple levels.
| | 02:40 | Now from the Finder I switch this to
the Column view, where we can actually
| | 02:45 | drill down into multiple columns here. That is
the browser that we can drag and drop in Xcode.
| | 02:51 | Multiple columns again allowing us to
drill down into multiple levels of data,
| | 02:56 | and it's important to realize of
course that this is the same data that we're
| | 03:00 | looking at in the Outline
view versus the Browser view.
| | 03:03 | It's just a different
visual presentation of that.
| | 03:05 | And the same idea if I go back to the
first icon where we just see a grid being
| | 03:10 | laid out here that allows me again to
drill down into different levels, this can
| | 03:15 | be done with the Collection view
that I see in the Object Library.
| | 03:19 | This will display an array
of content as a grid of views.
| | 03:22 | Again, same data, different visual
presentation, and your choices will be
| | 03:27 | driven mainly by do you have multiple
levels of data or can you just present
| | 03:32 | them one level at a time?
| | 03:33 | Well, while we're in the Finder window
here, what about this area over here on
| | 03:37 | the left-hand side, the typical sidebar
in OS X? Well, what's that? Because we're
| | 03:42 | still seeing multiple rows of data.
Well, that is actually also an Outline view.
| | 03:47 | It's just been configured to look a
little differently, and in fact, you will
| | 03:51 | actually find it way down in the
bottom in the Date Views window here as
| | 03:55 | something called a Source List.
| | 03:56 | And if you hover over that you can
see it's actually an NSOutline view
| | 04:00 | configured as a Source
List for use as a sidebar.
| | 04:03 | And pretty much everything else in
this section of the Object Library is for
| | 04:08 | when you want to customize
these top-level controls.
| | 04:11 | I want to have more visual control about
what each row and each column looks like.
| | 04:16 | So how we're going to start going through this?
| | 04:18 | Well, we're going to focus here on the
NSTable view. This is the classic Data
| | 04:23 | view control in Cocoa.
| | 04:25 | It's the most commonly used one, it's
the one we want to learn first, because
| | 04:29 | the concepts we learn with it
could be applied to the other controls.
| | 04:32 | In fact, the Outline view is
just a subclass of NSTable view.
| | 04:36 | So we're going to show how to use it, how to
customize it, and a couple of different
| | 04:41 | ways of how to get data into that up next.
| | Collapse this transcript |
| Adding table views and data source classes| 00:00 | I have created a new Cocoa application,
yet haven't done anything to it yet, but
| | 00:04 | I want to add a Table view to this window.
| | 00:06 | So I am going to jump over into the
Data view section of the Object Library and
| | 00:11 | right at the top should be the Table view.
| | 00:13 | I am going to bring that onto the
window here and just drag it wider to take up
| | 00:17 | as much space as it should.
| | 00:19 | And the key question is
how do we get data into this?
| | 00:22 | Well, when you're loading data into a
control, there are two primary ways,
| | 00:26 | both very different.
| | 00:28 | We can use code, and we can use
something called Cocoa Bindings.
| | 00:31 | I am going to show the code method
first, and in the next section we'll talk
| | 00:35 | about Cocoa Bindings.
| | 00:37 | But here's the thing to
understand about Table Views.
| | 00:39 | Table Views don't store data.
These are view objects.
| | 00:43 | When we have a Table view in our
application, what we need is another object, a
| | 00:49 | helper object that can act as
that Table Views' data source.
| | 00:53 | This is very similar to the idea of
delegation. We are asking another object
| | 00:58 | to do some work for the Table view, and then we
will point the Table view to that data source.
| | 01:03 | The data source can be any class.
| | 01:05 | It could even be AppDelegate, but
whatever class it's going to be needs to have
| | 01:10 | specific methods that answer the
questions, how many rows are in this Table view
| | 01:14 | and what's in each row?
| | 01:17 | If you have multiple columns, it's what's
in every single column of every single row?
| | 01:22 | And whatever the data source answers
here will be used to fuel the Table view,
| | 01:27 | and we'll see this in just a second.
| | 01:30 | As well as a Data Source object, the
Table view often needs to be connected to a
| | 01:35 | delegate object too. It uses delegation.
| | 01:38 | The delegate object needs to have
methods to answer the questions, what happens
| | 01:42 | if a row is selected?
| | 01:44 | If anything, what happens if a
row is double-clicked on to edit it?
| | 01:48 | What happens if you have a plus
button to add a new row or perhaps the data
| | 01:52 | source itself changes to
add a row or delete a row?
| | 01:56 | So we're looking for very
specifically named methods for both of these.
| | 02:01 | Now, you could put the data source in
one class and the delegate in another one,
| | 02:05 | but it's very common to
combine the two into a custom class.
| | 02:09 | So let's go see how this is done.
| | 02:11 | So back into Xcode, what I now need is
a class file, an object that can provide
| | 02:17 | those methods that we need to
fill this Table view with data.
| | 02:21 | I could actually put that in AppDelegate,
but I have been doing a bit too much in
| | 02:25 | AppDelegate, so let's jump up to the File Menu.
| | 02:27 | I am going to say New > File, and
making sure that the Cocoa section is
| | 02:32 | selected, I'll have an Objective-C class.
| | 02:35 | This one does not need to be
any special kind of inheritance.
| | 02:38 | I am going to give it the name of
MyTableViewHelper, the name is not important.
| | 02:45 | And I'll make sure we're just
inheriting from NSObject, click Next, add it to
| | 02:49 | the project, and we jump into it here.
| | 02:54 | Being a data source is like being a
delegate, which means we really want to mark
| | 02:58 | our class as actually supporting this
official protocol, these official rules.
| | 03:03 | You don't have to, it would almost
certainly work without this step, but I think
| | 03:08 | it's good practice to get into.
| | 03:10 | What I mean by this is we're going to
do something very similar as to what's
| | 03:13 | in AppDelegate, we need to mark the
class as supporting this particular
| | 03:18 | protocol, this set of rules.
| | 03:19 | So jumping back into my new class here,
I am in my header file here, and after
| | 03:24 | the NSObject, I am going to use the
angle brackets and start typing that I want
| | 03:28 | this class to officially support the
NSTableViewDataSource protocol and closing
| | 03:35 | angle brackets around that.
| | 03:37 | One of the best reasons for doing this
is I can now use my option key, mouse
| | 03:41 | over this and click it and get the
little pop-up that it will point me to either
| | 03:46 | the header file or the official
NSTableViewDataSource protocol reference.
| | 03:50 | What are the rules to be a data source?
What am I supposed to do? What are the
| | 03:55 | method names that I should support
if I am going to be in this role?
| | 03:59 | Now, there is quite a few different
method names for things like Pasteboard
| | 04:03 | Support and Drag and Drop, but really what I
am interested in are just the first two here:
| | 04:08 | Getting the Values in the Table view.
| | 04:10 | And it's numberOfRowsInTableView, how many
rows are there, and then what's in each row?
| | 04:15 | So for each Table view, what's the object
value for the table column and row number?
| | 04:21 | So click the first one and grab that.
| | 04:24 | I am going to just copy that full method
signature, jump back to Xcode, and I am
| | 04:29 | going to paste this in the implementation file.
| | 04:32 | I don't need to add it in the header file,
because I am officially saying that I
| | 04:36 | am supporting that protocol.
| | 04:38 | I'll add the opening and closing curly
braces just to make that a method signature.
| | 04:43 | Back into the DataSource Protocol
Reference, and I need that second method here,
| | 04:47 | which is tableView:objectValueForTableColumn:row.
| | 04:53 | Grab that method signature, copy it,
jump back over into the implementation file
| | 04:58 | of my new helper object, and paste that in.
Then what? We need some data.
| | 05:05 | I could create my own classes here,
create an array, load data from a file from
| | 05:09 | a database over a web service.
| | 05:11 | What I am going to do for purposes of
time is just ask OS X to give me a little
| | 05:16 | bit of data that I can use
for the lifetime of this object.
| | 05:19 | I am going to say NSArray and just
create an array that will last for the
| | 05:23 | lifetime of this class,
and I'll call it languages.
| | 05:25 | What I am next going to do is just
create a new method called awakeFromNib.
| | 05:30 | We have mentioned this a couple of times.
| | 05:32 | What it means is any object that's
going to be instantiated as part of the load
| | 05:36 | up process of a NIB file,
this method will be called in it.
| | 05:40 | So I know that this method will
be called as I start to wake up.
| | 05:44 | And what I am going to do here is just
call a built-in method that's part of OS X,
| | 05:48 | choosing something called the
NSLocale object, and it's going to give me
| | 05:53 | something called preferredLanguages,
which is an array of language codes.
| | 05:58 | This has nothing inherently to do with
the Table view, I just want a little bit
| | 06:02 | of data to work with.
| | 06:03 | So that will fill an array
with a bunch of language codes.
| | 06:07 | The important parts are on Line 19 here,
where it says how many rows are in the Table view?
| | 06:13 | This method will be called
automatically from the Table view control, and we
| | 06:17 | need to return a number, which for us
will be returning the count, the length of
| | 06:22 | that array, so it's languages count.
| | 06:27 | And down in the next, the most important
method here, we need to say what's in each row.
| | 06:34 | This method, we return an ID, it's an
object value, so we can return a string is
| | 06:39 | probably the classic example here.
What's the text that should be there?
| | 06:43 | Well, I know that I had an array with
a bunch of language codes, so what I am
| | 06:47 | going to do is return and use that array,
languages, but instead of count, I am
| | 06:52 | going to say whatever
object is at a particular index.
| | 06:55 | We are being passed an index every
time this method is called, and it will be
| | 07:00 | called for every single row.
| | 07:02 | We have this parameter rowIndex so
that's what I am going to use here.
| | 07:07 | So we create an array and load it
with a bunch of codes, then we say to the
| | 07:10 | Table view, this is how long that array
is, and then we say to the Table view,
| | 07:14 | this is what's in every single
individual entry in that array.
| | 07:18 | Now, if I go ahead and run this, we're
going to see absolutely no impact at all,
| | 07:23 | because there's two pieces left to do.
| | 07:27 | The first is that this Table view Helper
object isn't being instantiated anywhere.
| | 07:32 | I have defined it, but it's
actually not part of that start up process.
| | 07:36 | Now, I could write code in my
AppDelegate to instantiate it, but really the
| | 07:40 | easiest way is to jump into my
MainMenu.xib file and then from my Utilities
| | 07:45 | Panel, I am going to just select
from the Objects & Controllers section,
| | 07:50 | find the blue box, the generic object, drag it
into the Dock, and then set its identity here.
| | 07:58 | I am going to click on the third button
in the inspectors, and change its class
| | 08:03 | from the generic NSObject to MyTableViewHelper.
| | 08:08 | This is almost a shortcut
for doing an alloc and init.
| | 08:13 | It simply means there will be an instance of this
class instantiated when this interface is loaded.
| | 08:19 | And seeing as this is loaded and lasts
for the lifetime of the application, it's
| | 08:23 | a very convenient place to put this.
| | 08:25 | So it's instantiated, so what?
| | 08:27 | Well, we need the last piece of the
picture, because right now there is no
| | 08:31 | connection between this object, the Table
view Helper object and the Table view itself.
| | 08:37 | So I need to select the
Table view and hook it up.
| | 08:40 | Here's something to be aware of, when
I drag on a Table view--and this is the
| | 08:44 | same for the other controls, too--I
actually don't just get a Table view, I get a
| | 08:49 | Table view inside what's called a Scroll view.
| | 08:52 | And if you notice from deselecting that
and then just clicking it to select, up
| | 08:57 | here if I look at the class identity, it says
no, this isn't a Table view, it's a Scroll view.
| | 09:01 | That's because the Table view is inside it.
| | 09:04 | Table view could have a thousand entries,
and it takes care of showing the rows
| | 09:08 | and columns, but the Scroll view is
what supports us scrolling up and down and
| | 09:12 | controlling what part of
the Table view is visible.
| | 09:14 | Now, I could click in there again, and
I am likely to find the Table view here,
| | 09:20 | I can see that in my Identity
Inspector, or of course I could use the Dock,
| | 09:24 | which is a very useful way
to do it, the expanded view.
| | 09:27 | I can see I have got a Scroll view, which
contains a Table view, and inside that
| | 09:31 | is the first column and the second column.
| | 09:34 | Table Views by default, I am going to
select the Table view itself and take a
| | 09:39 | look at its Identity Inspector.
They do begin with two columns.
| | 09:42 | You can add more, you
can take it back down to 1.
| | 09:45 | You have checkboxes for whether it
has headers or not. That's up to you.
| | 09:50 | You have the option of selecting
alternate rows of color for every individual row.
| | 09:54 | So there's a few visual
options here that you can select.
| | 09:57 | But what I am most interested in--and
this is making sure that the Table view
| | 10:02 | itself is selected, not the Scroll view,
not the table column--is I am going to
| | 10:06 | go over into my Connections Inspector
and find the Outlet for the data source.
| | 10:10 | This is where we have hooked up
things like the delegate before.
| | 10:13 | I want the dataSource Outlet, which
for me is the second one, grab that, and
| | 10:18 | point it to the instance
of My Table view Helper.
| | 10:22 | Now the Table view knows which
object to talk to. Save that, run it.
| | 10:27 | And okay, it might not be the most
impressive thing in the world, but we're
| | 10:31 | getting data here, and it's scrollable as
well, because we're inside that Scroll view.
| | 10:35 | Automatically that's what happens.
But why is it being duplicated?
| | 10:38 | Well, that's simply because I dragged on
the Table view and set it to having 2 columns.
| | 10:44 | As part of the start up process, the
Table view asked the Helper Object how many
| | 10:48 | rows do I have, and that returned
with 40 or 50, however many it was.
| | 10:52 | And then the Table view called the
Helper Object once for every cell of every
| | 10:58 | row, for the first cell of the first row,
for the second cell of the first row,
| | 11:02 | for the first of the second row, for
the second of the second row, and so on.
| | 11:06 | So if I jump back over into my Helper
Code here, and if I wasn't doing anything
| | 11:11 | to actually detect what column we're in,
we're just returning the same contents
| | 11:16 | for each row, for two cells.
| | 11:19 | So I could do a couple of
different things here to take care of this.
| | 11:22 | I could just edit this Table view and
in the Attributes Inspector take it down
| | 11:26 | to having simply 1 column, or I could
put different data in different columns.
| | 11:32 | Well, let's try that one.
| | 11:34 | Here is the issue, over here in
MyTableView implementation file, this method
| | 11:40 | here that begins on Line 23 will be
called for every column of every row, and it
| | 11:45 | the passes in three pieces of information.
| | 11:47 | First, the actual TableView parameter, because we
could have multiple Table Views on the same window.
| | 11:52 | We only have one, so I don't care about this.
We have the rowIndex, what row is it.
| | 11:58 | That's fine, we have been using that one already.
And then we have an argument. That's the column.
| | 12:02 | Now, that is not a column index, it's not 0 or 1,
it's actually an NSTableColumn object.
| | 12:10 | So I can't just say, well, if
it's the first column, do this,
| | 12:12 | if it's the second column, do that.
| | 12:14 | They're not column 0 and column 1,
that's because a Table view could
| | 12:19 | theoretically have its
columns rearranged by the user.
| | 12:22 | We don't necessarily know
they're in a particular order.
| | 12:26 | The best way to identify the
columns is to give them an identifier.
| | 12:30 | Now, how do we do that?
| | 12:32 | Jumping back into the XIB file, I am
going to open up my Utilities Panel here.
| | 12:37 | I want to use the Dock to select not
now the Table view, but expand it and make
| | 12:42 | sure I can see the individual table columns.
| | 12:45 | So I can see that I can
select one, then the other.
| | 12:47 | I will go for the first table column.
| | 12:49 | What I am interested in here is not
the usual Attributes Inspector, I am
| | 12:54 | interested in the Identity Inspector,
because we have an identifier here.
| | 12:59 | It says Automatic, but it's
actually useful for me to give this a name.
| | 13:03 | Well, what I am going to do is say that
this first column is going to have the
| | 13:07 | code of the language, so EN, or JA or FR.
So I'll just give it an identifier of code.
| | 13:15 | Then I am going to select the second
column and give it an identifier of name.
| | 13:20 | And it's up to you, these are your names,
you just want to be able to remember them.
| | 13:25 | So it's code lowercase, name lowercase.
| | 13:27 | I can actually even see that in the
Dock it's changed the title of them so
| | 13:31 | they're recognizable that way.
Now, what do we do?
| | 13:33 | Well, jumping back into my helper object, I am
just going to give myself a bit more space here.
| | 13:38 | And inside this method, I am going
to ask the question, if the parameter
| | 13:43 | aTableColumn has an identifier that is
equal to the string code, then I'll do
| | 13:53 | what I did a moment ago, which
is just return the language code.
| | 13:56 | Let me put in a few spaces
here just to bring that code up.
| | 13:59 | So I will copy this line and paste it in there.
| | 14:03 | If it wasn't that column, I
am going to do something else.
| | 14:06 | I'd like to return the name of the language.
| | 14:09 | Well, how do I do that?
| | 14:11 | I am going to use the NSLocale
object again, and it has a method
| | 14:17 | called displayNameForKey.
| | 14:21 | What we're interested in is something
called the NSLocaleIdentifier, and the
| | 14:26 | value, and how we get that is by
passing in the actual code that we have already
| | 14:31 | retrieved, the EN, FR, JA, and so on.
| | 14:34 | Let me just split this up a little bit so
it's a bit more readable. That should do it.
| | 14:41 | The name of the array, it's languages
objectAtIndex, and we can get rid of
| | 14:46 | that last return here. Save that, Run it.
| | 14:51 | And we have alternate rows, we have
multiple kinds of data being passed in, we
| | 14:55 | have the Scroll view that will
automatically allow us to move up and down with
| | 14:59 | whatever amount we have chosen to
see on the screen at this one time.
| | 15:03 | And this is the basic procedure for
loading information into an NSTableView by code.
| | 15:09 | We need to connect the Table view
to a Data Source object, in this case
| | 15:14 | MyTableViewHelper, and then
provide the necessary methods for that.
| | Collapse this transcript |
| Using Key-value coding| 00:00 | I'm going to jump now into a concept
in Cocoa known as Key Value Coding, and
| | 00:04 | its flipside, Key-Value Observing.
| | 00:07 | And the reason why is the next
feature I want to explore, Bindings, relies
| | 00:11 | heavily on these, and
bindings is worth the trip.
| | 00:13 | Now Key-Value Coding can sound
complex at first but really isn't.
| | 00:18 | Although I will admit that I don't
think Apple do the best job of making
| | 00:21 | it accessible. Their introduction is rather
wordy and short on the immediate benefits.
| | 00:27 | So let me jump into this.
| | 00:28 | I have got a simple project that I have
created here, and I'll go through what I have done.
| | 00:33 | I have got a very straightforward new
Objective-C class called Book, two strings
| | 00:38 | and an integer, author, title and
pageCount, about as basic as it possibly gets.
| | 00:43 | And I am using Objective-C properties
here, because I'm using Xcode 4.4, the
| | 00:48 | getters and setters for these
properties will synthesize automatically.
| | 00:51 | I don't even have anything
in the implementation file.
| | 00:54 | So I am going to instantiate a couple
of objects of this class and then on
| | 00:59 | this interface I have one button that
will just write an NSLog message out,
| | 01:03 | very, very simple, because I want a setup
to allow us to do some Key-Value Coding here.
| | 01:08 | So if I look at my AppDelegate class,
all I have got here I am creating a
| | 01:13 | NSMutableArray that can hold several
of these book objects, and I have got
| | 01:17 | a listBooks method that as we'll see is
going to just write out some NSLog messages.
| | 01:23 | So here's what it's doing.
| | 01:26 | In the applicationDidFinishLaunching method,
I'm instantiating the NSMutableArray.
| | 01:30 | Then on line 18, instantiating the
firstBook object, setting its properties
| | 01:36 | using the standard Objective-C methods,
set author or setTitle, setPageCount.
| | 01:40 | Then on line 24, I'll add that to the
allBooks MutableArray, line 26 I create
| | 01:47 | another book object, and I'm using the
Objective-C .syntax to set its properties
| | 01:53 | just to show that we could use either
way, it would have no effect whatsoever.
| | 01:58 | I just wanted something
here to compare and contrast.
| | 02:00 | Then on line 32, we add
that secondBook to the array.
| | 02:04 | What I am going to do now
is do some Key-Value Coding.
| | 02:13 | First, instantiate a new book called
thirdBook, nothing special about that.
| | 02:18 | What I am going to do next is call a
method on this thirdBook object. The method
| | 02:25 | I am going to call is called setValue forKey.
| | 02:30 | First I will pass it a value of,
I'll say "Jan Hanberg" forKey:@"author".
| | 02:41 | This is Key Value Coding.
| | 02:43 | We are using a string as the key to get
to the property called author and then
| | 02:48 | setting the value of that.
| | 02:50 | This line 36 has exactly the same impact
as using the method on line 20 of setAuthor:
| | 02:57 | or as the method on line 28, .author equals.
| | 03:02 | We have just got a
slightly different format on that.
| | 03:07 | Do it again now, I am
going to do it for the title.
| | 03:16 | And I could go ahead and try and do this
for the pageCount, which is an integer,
| | 03:20 | let's say I wanted to make
this 250 for the Key pageCount.
| | 03:27 | And this is the only one I'm
going to have a problem with.
| | 03:30 | If we want to use Key-Value Coding,
the value always has to be an object.
| | 03:35 | So what I need to do here, because
it's complaining about this is instead of
| | 03:39 | passing directly in an integer,
I'm going to pass it an NSNumber that
| | 03:43 | contains an integer.
We are just wrapping that integer up.
| | 03:51 | And finally, I am just going
to add that to my mutable array.
| | 04:00 | So line 36 to 38 is Key-Value Coding.
| | 04:04 | Let's run this and make sure it's
behaving just like the other additions.
| | 04:07 | I click List books.
| | 04:09 | And we got the message coming
out exactly how I would expect.
| | 04:12 | Now if I quit back into the
application, I am going to take a look at this
| | 04:17 | ListBooks method that's
actually writing out the contents.
| | 04:20 | What it's doing is having this
format string here, and it's using .syntax
| | 04:24 | currentBook.title, currentBook.author.
| | 04:27 | We could of course use the space format inside
the square brackets, or we can use KVC as well.
| | 04:33 | We can use Key-Value Coding here.
| | 04:35 | So for the title, what I would write is
currentBook, and I will use the method
| | 04:41 | valueForKey, again, treating the
name of that title property as a string.
| | 04:51 | We could do the same thing with the
second currentBook space valueForKey:@"author".
| | 04:54 | And the last one here, what I am
going to do is currentBook valueForKey.
| | 05:04 | I'm still using the name of
that pageCount as a string here.
| | 05:09 | Although I do know that this will
return an object, Key-Value Coding
| | 05:13 | always works with objects.
| | 05:15 | And what is complaining out right now is
it was expecting a direct integer, so I
| | 05:19 | am going to change that that will format
specifier here from %i, to %@, save it
| | 05:25 | and run it, and we should have
exactly the same behavior. That's correct.
| | 05:30 | But we are using now Key-Value Coding,
both on the way in and on the way out.
| | 05:35 | To set value with KVC, it's setValue forKey.
To get it, it's valueForKey.
| | 05:42 | These methods are already in NSObject,
which means this works everywhere.
| | 05:46 | In every object you can use this approach.
| | 05:48 | Now we are using standard
generated properties in this book class.
| | 05:53 | And that's what Key-Value Coding expects,
the typical getter and setter accessor methods.
| | 05:58 | Now you can still create your own
accessor methods with different behavior, just
| | 06:02 | be careful with naming them.
| | 06:03 | If you use nonstandard getter and
setter names, if you do that at all, you
| | 06:07 | can run into problems.
| | 06:08 | Now the reaction from most people when
they first see this is this doesn't look
| | 06:13 | like it's anything special, it's
just some odd Objective-C syntax.
| | 06:17 | But as we will see, it can be extremely helpful.
| | 06:19 | Now there are a few advanced usage you can do,
because when we are using valueForKey or setValue: forKey,
| | 06:26 | we can often not just use a single word,
the single name of a property,
| | 06:31 | but we can actually use .syntax in the
string to drill down into an object
| | 06:36 | inside an object inside an object.
But we don't need that right now.
| | 06:40 | We just need to understand this idea that the
key is a string that represents a property name.
| | 06:47 | And we need the basics, because KVC,
using that string for a property, let's us
| | 06:52 | do something called Key Value Observing,
which means we use the same idea of a
| | 06:56 | key, the name of a property is a string,
and we can say we want to register as
| | 07:00 | being an observer for that key, and we will
automatically be notified if the value of it changes.
| | 07:06 | That might sound a little abstract.
So let's see an example of what it can do.
| | Collapse this transcript |
| Binding an object to a user interface| 00:00 | A great feature that's available to us
in Cocoa that isn't available in other
| | 00:04 | areas of Apple development
like iOS is the idea of bindings.
| | 00:08 | Binding refers to be able to connect,
to bind a user interface element directly
| | 00:14 | to a controller class without
writing code, doing it all in the interface
| | 00:18 | builder part of Xcode.
| | 00:21 | So I have a Cocoa application here I'm
going to use, and I have added a very
| | 00:25 | simple class to it, a Book class that
just exists here as a data structure.
| | 00:29 | I have two NSStrings for author and title,
one NSDate for the publishedDate, and
| | 00:34 | an integer for pageCount.
| | 00:35 | There is nothing in the implementation of
this Book class, it's just to hold some data.
| | 00:39 | Now, in my AppDelegate, all I am
declaring here in line 16 is a property that
| | 00:44 | can hold a single instance of a book object.
| | 00:47 | And in my implementation of
AppDelegate, that's all I'm doing when the
| | 00:51 | application launches is I'm instantiating
that book on line 16 and setting its
| | 00:56 | values on the next four lines.
That's the entire setup of this.
| | 00:59 | What I want to do is get the details
of that object onto the interface which
| | 01:03 | has nothing right now, no buttons,
no fields, no secret connections.
| | 01:07 | Without bindings, what we
need to do is several steps.
| | 01:10 | First, we'd drag on all the
user interface elements we wanted.
| | 01:14 | Then we'd have to take care to connect
them correctly to our chosen controller
| | 01:18 | class as IBOutlets, giving them names,
making sure they had the right type.
| | 01:23 | And then in our controller code, we have to
write code to set the values of all those outlets.
| | 01:29 | If the class is complex, you often have
to write quite a lot of what's referred
| | 01:34 | to as glue code, or the unexciting code
that purely exists to get object data
| | 01:39 | into user interface elements.
| | 01:41 | Well, we are going to do
something a little different here.
| | 01:44 | I do need to drag on the user
interface elements that I want.
| | 01:47 | I am going to drag on a few labels here.
| | 01:50 | Just drag this wider and
give it a placeholder name.
| | 01:53 | This will be the Title, drag
another underneath it as Author.
| | 02:04 | Technically, I don't actually need
to change the values of this label.
| | 02:08 | We're going to change them
as soon as the program loads.
| | 02:10 | And just to give us a bit of visual
interest, I am selecting the first one here,
| | 02:16 | and I will just make the
font a little bit bigger,
| | 02:24 | nothing that we haven't seen before.
| | 02:26 | This will be the point where usually
I'd switch into the Assistant view and
| | 02:29 | start doing the Ctrl-drag method
to set them all up as IBOutlets.
| | 02:34 | But that's not where we are going this time.
Here is where I am going instead.
| | 02:38 | I am going to select that first label,
I am going to jump over here into the
| | 02:42 | Bindings Inspector in my Utilities Panel.
This is the second to last one.
| | 02:47 | This looks like several intertwined
elements or a simple Celtic knot of some kind.
| | 02:51 | What I'm going to do is choose to
bind the value of this label to that
| | 02:57 | class that we created.
| | 02:58 | Well, the question is well, how
do I do this, what am I binding to?
| | 03:03 | There is a lot of options that we are seeing.
| | 03:05 | Well, the question is
what class contains the data?
| | 03:07 | Well, it's in the AppDelegate.
| | 03:09 | That's what instantiates
that object and holds onto it.
| | 03:12 | So I am going to check the box to Bind to and
then from the dropdown, select AppDelegate.
| | 03:19 | But of course there is quite a lot going
on in AppDelegate, so I have got a little
| | 03:23 | exclamation mark here
highlighting that this is the important part.
| | 03:27 | We might be binding this label to the
AppDelegate, but what part of the AppDelegate?
| | 03:31 | And this is where we're using the term key.
| | 03:33 | We are using the key part of the key
value coding which is what allows us to do
| | 03:39 | a path that drills down
through multiple objects.
| | 03:42 | So, self refers to AppDelegate.
| | 03:44 | Then I put a dot, and it's actually
looking inside AppDelegate and saying, okay,
| | 03:48 | I know about two properties you have.
There is the window property and singleBook.
| | 03:52 | Well, it's inside that singleBook property.
So I will select that and hit Tab.
| | 03:57 | But that's the entire class, so
it knows it can't bind that yet.
| | 04:00 | I'm still getting the exclamation mark.
| | 04:02 | I'll hit the dot again, and it's
looking inside the singleBook object saying
| | 04:07 | these are the accessible properties,
| | 04:09 | the NSString for Author and
Title, the Date, and the pageCount.
| | 04:12 | Well, this is meant to be title.
| | 04:14 | So I'll select that, and now
the exclamation mark goes away.
| | 04:17 | There are a lot of other options underneath it.
I don't need to do any of those.
| | 04:21 | I'm going to repeat this process for Author.
| | 04:23 | I will drag that a little wider
before I do, select the label, jump into
| | 04:27 | Bindings, bind that also to App Delegate,
but in this case, it's self.singleBook.author.
| | 04:38 | And again, for date, making sure the
label is wide enough, we are binding it to
| | 04:42 | exactly the same place just a
slightly different key path for each one,
| | 04:48 | singleBook.publishedDate and finally
pageCount bound to App Delegate, and you
| | 04:54 | can see how we could bind them to
different classes and different objects here.
| | 04:59 | Save that and run it.
And these are bound user interface elements.
| | 05:06 | It looks like it's working okay.
| | 05:07 | It looks like we are running into a
couple of issues with the length of the
| | 05:11 | labels here, and it does seem that
there is a bit too much information.
| | 05:15 | I don't need the full NSDate
description that it's giving me here.
| | 05:19 | So I'll jump back in and fix a couple of things.
| | 05:21 | First, we will drag that Title label to the full
width and then Date, I don't want the full thing.
| | 05:27 | Well, this is fine.
We can use say the NSDate formatter.
| | 05:31 | So, with that selected, I'm going to
find the NSDate formatter which is down
| | 05:35 | here a little bit, drag that on top
of the Date label, and with the date
| | 05:41 | formatter selected in the Jump bar, I
will just go to my Attributes Inspector
| | 05:45 | and change it to--I'll change it to
a Full Date Style but No Time Style.
| | 05:51 | Run it again, and that's more
like what we're looking for.
| | 05:56 | Very easy to set up, no
code that we have written at all.
| | 05:59 | But we need to take it a step further,
because right now this just seems like a
| | 06:03 | nice way of getting data out onto the interface.
| | 06:06 | But binding is not just for output, it's not
just for labels, it works the other way too.
| | 06:11 | So, quit out of this.
| | 06:13 | What I am going to do is go back into
Xcode and instead of a label, this time I
| | 06:19 | will drag on a slider.
| | 06:20 | I will just put this over here on the
right-hand side and drag it to the full
| | 06:24 | length of the current window, because
I'm going to bind this to pageCount just
| | 06:29 | to show that we can.
| | 06:31 | With the slider selected, go to the Bindings
Inspector, and again I want to bind its value.
| | 06:36 | So, select to bind that to AppDelegate,
and the Key Path, self, referring to
| | 06:42 | App Delegate, .singleBook which is inside property
of AppDelegate and then inside that, pageCount.
| | 06:49 | Running that, the slider has
immediately jumped up to the top, because it's
| | 06:53 | been set to the same value as the
pageCount which is 315 for this object, and
| | 06:58 | by default, the slider only goes from 0 to
100, so it's as high as it could possibly be.
| | 07:03 | What I will do is I will jump back
into Xcode and just set the attributes of
| | 07:07 | the slider so it has, say, a maximum value of 500.
| | 07:11 | In interface builder, it's currently
set to 50, but that doesn't matter because
| | 07:14 | as soon as this application loads, we'll
actually get it jumping to the point it should be at.
| | 07:19 | I am going to change one more
thing here which is of the slider.
| | 07:23 | I am going to select to make it continuous.
Run this once more.
| | 07:26 | It does appear as if the
slider is currently stuck at 100.
| | 07:30 | Let's just go back and make
sure that took effect here.
| | 07:37 | That looks better now.
It just didn't have the proper impact.
| | 07:40 | There we go, 315 which on a 0 to
500 slider would be about there.
| | 07:44 | But if you notice, as I move this up
and down, any control that we have bound to
| | 07:49 | that value is being updated.
| | 07:52 | This would also work if I say dragged on a
text field and typed into the text field.
| | 07:57 | They're all connecting, they
are all talking to each other.
| | 08:00 | And be aware that right now, I'm not
just changing the value of the user
| | 08:03 | interface, I am changing the object's
value here, and this is the flip side of
| | 08:08 | key value coding is key value observing.
| | 08:11 | These controls change the object, and
the other controls that are linked to
| | 08:15 | it, in this case the label, is observing that
same key and being notified when the value changes.
| | 08:21 | And that's the power of binding.
| | 08:23 | If the object changes, the user
interface changes, if the user interface
| | 08:28 | changes, the object changes,
they are bound together.
| | 08:31 | And there is no code in this
application that deals with tying that object to
| | 08:36 | this user interface.
| | 08:37 | We have no delegation, no target action,
no IBActions, no IBOutlets, no event
| | 08:43 | handling, just binding, and this is what
makes it such a powerful technique, even
| | 08:48 | with this example, which is very simple.
| | 08:50 | And while this is still good,
binding gets even better.
| | 08:53 | So next, we'll talk about binding our
Data view controls like the Table view.
| | Collapse this transcript |
| Binding more complex controls| 00:00 | For simple binding examples, we can
bind directly to an object declared in the
| | 00:04 | app delegate, as we just did.
| | 00:06 | But as we get more advanced,
that won't be good enough.
| | 00:09 | Now first realize the role
that I'm talking about here.
| | 00:12 | We are still doing Model-view controller.
We have go the user interface view
| | 00:16 | object, something even
as simple as a text field.
| | 00:18 | We have go to model, the actual data, and
with the bindings, we can minimize a lot
| | 00:24 | of the glue code in the middle and the
controller, but we can't, and we don't
| | 00:28 | want to remove it from the
picture, it's still a vital part.
| | 00:31 | So in that previous simple example, we
still went through the AppDelegate as the
| | 00:35 | Controller to act as a middleman between
the user interface view Objects and the
| | 00:40 | Model Object, in this case, one Book
object, and again, there was nothing in the
| | 00:44 | Book object that knew anything
about a user interface element.
| | 00:48 | So it's this bit in the middle I'm
talking about here, the Controller.
| | 00:52 | We have already seen earlier in
the course that yes, we can use the
| | 00:55 | AppDelegate as a controller.
| | 00:57 | We can create a regular Objective-C
class to act in the role of controller.
| | 01:02 | But there are several classes built
into Cocoa to help us in the role of
| | 01:06 | controller when we're using bindings.
| | 01:09 | In a more complex situation where we
have complex view objects like table views
| | 01:14 | that we want to use, and complex model
objects, arrays, dictionaries, objects
| | 01:20 | that contain other objects.
| | 01:22 | We need to ask a few more
questions about what's in the middle.
| | 01:25 | And the key question we need when
choosing between the options is first, what
| | 01:29 | kind of data do you have? What is your model?
Is your model object a single object?
| | 01:34 | Is it a collection, like an array or
dictionary? Is it a complex tree of
| | 01:38 | objects with parents and children?
| | 01:41 | Because we have some choices about what we can
put in the middle, in the controller role.
| | 01:46 | For single objects, we have
something built into Cocoa called the Object
| | 01:50 | Controller, NSObjectController class.
| | 01:54 | If you have an array, we
have an Array Controller,
| | 01:56 | we have a Dictionary Controller, and even a
Tree Controller for complex trees of objects.
| | 02:03 | And using these in the controller role can
make binding these complex controls much easier.
| | 02:09 | What they do is stand between the user
interface view object and our model, our
| | 02:13 | data, helping us not just blind,
but sort and add and edit and delete.
| | 02:18 | But how do you use these?
| | 02:20 | One easy way is that they
are already there in Xcode.
| | 02:23 | If I go into my Object Library, into
the Objects and Controller section, I will
| | 02:28 | find them listed here.
| | 02:30 | Notice the description here,
Object Controller is a Cocoa bindings
| | 02:34 | compatible controller class.
| | 02:36 | Bindings Compatible Controller class,
Bindings Compatible Controller class for
| | 02:40 | the Object, Array,
Dictionary and Tree Controllers.
| | 02:42 | There's even a User Defaults
Controller to allow us to bind to the user
| | 02:47 | defaults in OS X. Now these on non-
visual Objects, but we can drag them on to
| | 02:53 | the Dock, like dragging on the blue object box
that we have done a couple of times earlier.
| | 02:58 | In this way connect them between on model
objects and our user interface view objects.
| | 03:02 | Now there's a common misconception I
sometimes hear, and I want to clear up.
| | 03:07 | Is that some people come in to this thinking
| | 03:09 | you can only have one controller object per window
that you must choose what is the controller object.
| | 03:15 | And that's not true, you
can have as many as you need.
| | 03:18 | Now I occasionally hear this from
people who are used to working with MVC where
| | 03:22 | it's formalized a certain way, even in
iOS, where it's very common to have one
| | 03:27 | controller per view, one controller
object dealing with all the user interface
| | 03:31 | elements on a particular screen.
| | 03:33 | And that method can work very well, but
MVC does not force you to do it that way.
| | 03:38 | Think about it this way, you can have
way more than one view object on this window.
| | 03:42 | We know that. We can have text
boxes and buttons and text views.
| | 03:46 | In fact, the window itself is a view object.
| | 03:49 | A menu is, a menu item is, and we know
they we can have more than one model object.
| | 03:55 | We could have an array of books, an
array of authors, complex classes being
| | 03:59 | used on this one screen.
| | 04:00 | In the same way we could have
more than one controller if it helps.
| | 04:04 | If we had, for example, two arrays of
different objects, we might drag on two
| | 04:09 | different array controllers into our
Dock and use those as the middleman, in
| | 04:14 | between the user interface
elements and the data itself.
| | 04:17 | Now it still sounds a little
abstract, so next step, let's see a demo.
| | Collapse this transcript |
| Using NSArrayController with table views| 00:00 | Now let's see how to connect more complex
objects to more complex user interface elements.
| | 00:05 | I have a simple project that I have
created to get us ready to get started here.
| | 00:09 | Just to explain what I have, it's that
Book class again about as simple as it
| | 00:14 | gets, two NSStrings and an Integer.
| | 00:16 | This Book class has no implementation
we're speaking of, although I have added
| | 00:20 | an init method just to begin with an
author and title that have some basic
| | 00:25 | information in those strings,
I'll show you why in just a moment.
| | 00:28 | There's not much else going on. In the
AppDelegate, I have an NSMutableArray
| | 00:33 | called allBooks that can hold
multiple book objects, and I have created one
| | 00:38 | listBooks IBAction method that's going
to have just some simple code that will
| | 00:43 | NSLog the contents of the array out so
that we can see any difference between
| | 00:47 | what we're seeing in the user interface
and what's actually stored in the array.
| | 00:51 | And the last little piece of code worth
exploring is in the implementation of AppDelegate.
| | 00:55 | I have added an init method, and as soon
as this class is being initialized, I'm
| | 01:01 | creating this mutable array, and then
I'm creating two instances of the Book
| | 01:06 | class and adding them to the array.
We have seen almost all of this code before.
| | 01:11 | All I have currently on the interface file
is one button that says List Book Objects.
| | 01:16 | If I go ahead and run this, click
that button, there will be no surprises.
| | 01:20 | I just simply write out a very
straightforward NSLog message for each object.
| | 01:29 | So I am going to stop that application.
| | 01:31 | So at no point anywhere here is there
any code that deals with user interface
| | 01:36 | elements, writing any of this
content out apart from that NSLog message.
| | 01:40 | So let's start hooking things up.
| | 01:41 | I am going to open up my Utilities Panel,
and from the Object Library drop into
| | 01:46 | Data Views where I'm
going to drag on a Table view.
| | 01:52 | This is the one that beforehand we
had to hook up, create a data source and
| | 01:57 | implement certain named methods to be
able to provide data for every single row
| | 02:01 | and every single column.
| | 02:02 | We're avoiding that whole approach
and using binding this time around.
| | 02:06 | Now here's the thing, this Table view does have
a Binding section and Inspector, but I can't just bind
| | 02:12 | it directly to that array in the AppDelegate.
| | 02:15 | I want to use a different controller
to be between this Table view object and
| | 02:20 | the NSMutableArray of books, and
here's how we're going to do it.
| | 02:23 | From the Object Library, I'm going
to select the section called Objects &
| | 02:27 | Controllers under Cocoa, and here we have
the Bindings compatible controller classes.
| | 02:33 | We have an array, so this Array
Controller will work just fine.
| | 02:37 | This is a non-visible object, so you drag it
into the Dock rather than on to the interface.
| | 02:42 | Remember, this is a controller, it's the middleman,
so there are two connections that need to be made to this.
| | 02:48 | I need to hook this controller to the
actual NSMutableArray to the data, and
| | 02:53 | then I'm going to hook the
Table view to this controller.
| | 02:57 | If both of those things are done
correctly, it should just work.
| | 03:01 | I'll expand my inspectors and make
sure that Array Controller is selected.
| | 03:05 | In the Bindings Inspector, what
I'll see is that I have a section
| | 03:09 | called Controller Content.
| | 03:11 | This is an array controller, so not
surprisingly it's looking for an array to handle.
| | 03:16 | So it's asking, where is my
Content Array, where is that?
| | 03:19 | Well, that array is the allBooks
array that's being stored right now in
| | 03:23 | the AppDelegate class.
So I am going to select to Bind to:
| | 03:26 | App Delegate, and we're using the
key idea out of key value coding.
| | 03:32 | So self refers to the AppDelegate, but
if I hit the dot, it should look into the
| | 03:36 | properties that are available which
includes the NSMutableArray of allBooks.
| | 03:39 | So our Array Controller is now
pointed to our Array Model Data.
| | 03:45 | Now, one thing I do want to do here is
switch into the Attributes Inspector here
| | 03:51 | because there are some attributes of
this Array Controller that I want to change,
| | 03:54 | too, which is I'm going to tell it
exactly what that array contains.
| | 03:59 | It starts off with this generic entry
of an NSMutableDictionary, but no, I want
| | 04:03 | that array to contain books.
I know that is all that, that array contains.
| | 04:08 | And that will make it easier
to hook it up to our Table view.
| | 04:11 | So that's one side done, the
controller is hooked to the model.
| | 04:14 | Now, the controller needs
to be hooked to the view.
| | 04:16 | So I am going to select the Table view itself.
| | 04:19 | Remember that whenever we drag on a
Table view, what we get is a Table view
| | 04:22 | inside a Scroll view.
| | 04:24 | So, I can click again to select it, but
if I want to be doubly sure, I will use
| | 04:29 | the Dock here and expand to make
sure I am selecting the actual Table view
| | 04:33 | itself, not the Scroll view -
Table view, and I'm going to bind this.
| | 04:38 | So jump over into the Bindings Inspector,
and it's asking okay, what's my content?
| | 04:43 | And the main one I'm interested in
here and Bindings is the table content.
| | 04:47 | It's asking, what am I binding to?
| | 04:49 | Well, this time it's not to the
AppDelegate, we are binding the Table view to
| | 04:53 | the Array Controller.
So that's correct here.
| | 04:56 | We're saying Bind to the Array
Controller, and that's all I actually need to do
| | 05:00 | right now because the Array
Controller contains those book objects.
| | 05:03 | Now, you might be thinking, well, does
that mean that everything works?
| | 05:07 | No, nothing would happen yet because
the objects that we have in that Array
| | 05:11 | Controller could be significantly complex.
| | 05:14 | We might not want to show
everything on this Table view.
| | 05:17 | So what we have to do next is say what
appears in each column of this table view.
| | 05:22 | Well, right now I drag this Table view
on by default, which means it's only got
| | 05:26 | two columns. I'd like it to have three.
| | 05:28 | So again making sure the Table view
itself is selected, I am going to switch
| | 05:32 | over into the Attributes
Inspector and give it three columns.
| | 05:36 | And then I want to go column by column
saying once in each one, so I will expand
| | 05:41 | the Table view itself.
| | 05:43 | Select the first column, and I need to
go to its Bindings Inspector and tell
| | 05:49 | it that its value should be coming
from Array Controller, and we're looking
| | 05:54 | for author. As I start typing it
should bring that up because it's looking
| | 05:59 | inside the Array Controller, it knows it's full
of books, so it should tell me the properties.
| | 06:04 | So, author is correct for that column.
| | 06:06 | Then I will select the second column,
bind that to title, and then I will select
| | 06:14 | the third column and bind that to page count.
| | 06:20 | Third column is hidden a little bit here,
so I am going to see if I can drag it
| | 06:25 | a bit wider, and grab hold of that.
| | 06:29 | Then I should be able to click in
and just resize that a little bit.
| | 06:32 | I am just going to go ahead
and press Command+R to run this.
| | 06:36 | We're opening up our Table view, we're
binding, we have got that Array Controller
| | 06:40 | in the middle that's
hooking everything up correctly.
| | 06:43 | Now, here's one of the great things to this.
| | 06:45 | If I'd click the button to List Book
Objects, we'll just run through that array
| | 06:49 | and pop out the idea that, yes, this
book has 315 pages, and this has 280, but
| | 06:55 | this is editable by default.
| | 06:56 | So I can double-click on this and just
type in 250, and I am not just changing
| | 07:01 | the user interface, I am
changing the actual object.
| | 07:04 | So if I press the button again, we'll
see we now have 250 pages and 280 pages.
| | 07:10 | And that's because by default, the
Table view hooked up to the Array Controller
| | 07:14 | does support editing.
| | 07:15 | You can turn that off if you
want to, but it can be very useful.
| | 07:19 | Well, let's take it a little step further.
| | 07:21 | I am going to quit out of
that and back into the interface.
| | 07:27 | I'm going to add a couple of buttons here
for adding and deleting from that array.
| | 07:32 | I will jump to my Control section,
and what I'm going to use here will be a
| | 07:38 | Gradient button, which by default has
text, but I don't want that, so I'm going
| | 07:46 | to switch that in my Attributes
Inspector and get rid of the title and then come
| | 07:51 | down to the Image section where I'm
going to select from the NSAddTemplate which
| | 07:56 | is the classic plus button here.
Doesn't quite need to be that wide.
| | 08:00 | So I will make it a bit smaller and
then do an Option-drag to copy that, change
| | 08:06 | the second button to the NSRemoveTemplate,
which is the classic minus sign. Well, now what?
| | 08:12 | Well, usually, what we think about
doing is hooking things up to code, writing
| | 08:19 | some code, calling methods.
| | 08:21 | What I can actually do is here use
IBActions, they're still very useful in this
| | 08:25 | situation, but I'm going to Ctrl-drag
from the plus button over to the Array
| | 08:32 | Controller because the Array Control
that's holding all that data is smart.
| | 08:35 | I'm going to let go and the Array
Controller has these received actions because
| | 08:41 | it's set up, it understands what an
array needs to do which is often insert or
| | 08:45 | remove or select next or select previous.
| | 08:48 | So we're going to say Add.
| | 08:51 | Then I'm going to select and Ctrl-click
from the minus button, drag over array
| | 08:56 | controller, let go, and select Remove.
| | 08:59 | Go ahead and run this. We still have
the editable idea that we can switch any
| | 09:05 | of these around if we want to, change
Under the Moonlight to 200 pages, and
| | 09:10 | yes, it has 200 pages, but I can click
the plus button, and we actually get the
| | 09:14 | new object inserted.
I could click that a couple of times.
| | 09:20 | We can double-click in there and start
adding new title and so on, and it all is
| | 09:26 | changing that I actual Mutable Array.
| | 09:29 | So if I am spitting out the output here,
I'm seeing all the different objects.
| | 09:33 | So we're truly affecting the mutable
array, not just in the user interface, all
| | 09:38 | done without code, without connecting
this Table view as a data source and then
| | 09:42 | writing multiple methods to provide
the data for each column and each row all
| | 09:46 | done through bindings,
displaying, editing, adding, removing.
| | 09:50 | We can use the Remove button and just
get rid of the two that I don't want.
| | 09:55 | Now sure, as the situation gets more
advanced, we would add code perhaps to
| | 10:00 | validate what's entered or perform
certain actions when a row is selected.
| | 10:04 | But as an example of binding a
Table view, these are the fundamentals.
| | Collapse this transcript |
|
|
7. Debugging and TroubleshootingUsing the Xcode Debugger| 00:00 | We have used a few simple
troubleshooting techniques like using NSLog to send
| | 00:04 | messages to the console, and we have
talked about diagnosing the most common
| | 00:08 | issues when hooking up your
IBActions and IBOutlets correctly.
| | 00:12 | But once you're past that, sometimes
it's not quite so clear where the problem
| | 00:16 | is, and you don't want to start writing
dozens or hundreds of NSLog messages, so
| | 00:21 | you want to be able to step through
the code line by line as it executes.
| | 00:24 | And we're going to do that
now using the Xcode Debugger.
| | 00:27 | This is just a brief introduction. If
you have already been using the Debugger in
| | 00:31 | iOS, I won't be telling you
anything you don't know already.
| | 00:34 | So I have got a simple Cocoa application
here called DebugStarter and looking at
| | 00:39 | the MainMenu.xib file, I have got a button here
conveniently titled Boom! and a blank label.
| | 00:45 | Now that button calls some very straightforward
code and a method called doSomething.
| | 00:50 | It creates a couple of integers by
calling some inner methods of this class, and
| | 00:56 | then it divides one by the other,
creates an NSString and spits that out to the
| | 01:01 | label, some fairly simple stuff there.
| | 01:03 | In fact, this code is all
syntactically correct. It will compile if I hit
| | 01:08 | Command+B, it'll go through and succeed, there
is no problem there, but it is going to crash.
| | 01:13 | So let's go ahead and run it.
I came over to the button, I click it.
| | 01:20 | Now because we ran this directly from
Xcode, we're jumping back into Xcode with
| | 01:25 | all these great Debugger options
appearing at the bottom of the screen here.
| | 01:29 | Our application is still working.
It's paused so we can view the inner
| | 01:34 | workings of what's going on.
| | 01:35 | So I have got the lower section showing up,
if it's not you should be able to get
| | 01:40 | to it from the view section here.
| | 01:42 | And there's a problem, I can see
immediately by this highlighted line, line
| | 01:45 | 39 here, EXC_ARITHMETIC, we have some
problem with Arithmetic. Okay, we'll get to that.
| | 01:52 | Now, over on the left-hand side what
Xcode has jumped us to is the fifth
| | 01:57 | navigator here which is the Debug navigator.
| | 01:59 | It's showing us a stack trace,
basically a list of where we are and how we got
| | 02:05 | here, and it's the most recent at
the top, this the main thread here.
| | 02:09 | So it's telling us we're in the
doSomething method of AppDelegate but we got
| | 02:14 | here very gradually from
NSApplication, NSApplicationMain and Start.
| | 02:19 | Now towards the bottom I have this
slider here, and if I actually start dragging
| | 02:23 | that to the right and then to the left,
what you'll actually see is different
| | 02:27 | levels of the stack trace.
| | 02:30 | And that can sometimes give you a clue
of how we got there, but right now most
| | 02:34 | of these are really internal plots.
We have the main method that called
| | 02:37 | NSApplicationMain which hopefully
remember from our lifecycle discussion, and a
| | 02:41 | lot of the rest of the stuff going on
here is basically being handled internally
| | 02:45 | by NSApplicationMain.
It's waiting for events.
| | 02:48 | It's running, it's gotten a mouseDown,
and it's kicked that mouseDown over to
| | 02:51 | our doSomething method.
| | 02:53 | So I don't need quite that level of information
on my stack trace. I'll drag it to the middle.
| | 02:58 | We just know we touch the button, it
called our code, and there's a problem.
| | 03:02 | Now in the lower section here in the
debug area I have the split between the
| | 03:07 | variables view and the console.
Console is telling me lldb here.
| | 03:12 | We're using the low-level
virtual machine debugger.
| | 03:15 | Used to use gdb, but from
Xcode 4.4 onwards we're using lldb.
| | 03:20 | On the left-hand side I can see a list
of Local Variables, and I can also use
| | 03:25 | the dropdown here to move between the
Local Variables which is what's shown
| | 03:29 | automatically and All Variables,
Registers, Globals, and Statics.
| | 03:33 | If I want to, and it's easier I can also mouse
over the code to see the different values.
| | 03:40 | Mousing over firstVal here tells me
it's 10,000, mousing over the second
| | 03:44 | one tells me it's zero.
| | 03:46 | So there's the problem. We're trying to
create an integer on line 39 by dividing
| | 03:51 | 10,000 by 0, and that's an issue you
can't do a divide by zero on a computing
| | 03:56 | system, that is a problem.
| | 03:58 | But let's imagine that it's a little bit
challenging to figure out exactly where
| | 04:02 | did these values come from.
| | 04:04 | SecondVal is zero that's a
problem, but how did I get secondVal.
| | 04:07 | So what I'm going to do is hover my
mouse over the gutter section here, the gray
| | 04:11 | bar beside the line numbers,
that's if you have line numbering on.
| | 04:15 | I'm going to click in here before
the call to calculateFirstValue.
| | 04:19 | When we set a breakpoint, we will break before
this line is executed right at the start of it.
| | 04:25 | Now because this program version isn't
working, I'm just going to hit the Stop key here.
| | 04:30 | So if I click in this gutter, I get this bright
blue icon, which means it is a working breakpoint.
| | 04:35 | If I click again, it becomes somewhat dimmer,
which means it's just not active right now.
| | 04:40 | And you can kind of flip them back on and off.
| | 04:43 | If I wanted to delete the breakpoint, I
can just drag it off to the side and let
| | 04:47 | go once I see the cloud icon.
But I want it, so I'm going to put it back.
| | 04:52 | If you actually start adding multiple
breakpoints all up and down different
| | 04:56 | parts of your code, and be aware that
you are breaking before the line that the
| | 05:01 | breakpoint is pointing to.
| | 05:03 | If I had a lot, I can actually go to
a different section of my navigators
| | 05:07 | here, the Breakpoint navigator is the
one that actually looks like the little
| | 05:10 | blue marker points here, and it
will give me another view of all the
| | 05:14 | breakpoints in this project.
What line they are on, what method they're in.
| | 05:19 | I can delete them from that view, or I
can drag them off, and you can actually
| | 05:23 | see them disappear as I do that.
| | 05:24 | So I'm going to go ahead and run this
with my one breakpoint just in the first
| | 05:28 | line of the doSomething method.
| | 05:30 | Our program is going to run normally
because we haven't hit that code yet, it
| | 05:34 | won't happen until I click the button.
So I click it, we jump into the break mode.
| | 05:39 | We're positioned before line 36.
| | 05:41 | So if I hover over this, we're not going
to get any kind of meaningful value here
| | 05:45 | because I haven't run this line yet,
this integer hasn't been initialized.
| | 05:49 | Down towards the middle section here,
I have got the Debug bar that's going to
| | 05:53 | allow me either just keep going until
the next breakpoint, to Step Over the
| | 05:58 | instruction, and that simply means
execute it, but if it was calling a method
| | 06:03 | don't go into the method, and then we
can decide to step into the instruction.
| | 06:08 | So in this case what that means is if
I'm calling calculateFirstValue, which is a
| | 06:12 | method in this current object, I'm
going to hit the Step into, and we will
| | 06:17 | actually jump into that method, and to
calculateFirstValue, I can keep going,
| | 06:22 | that returns 10,000, and that looks right.
| | 06:24 | What I should expect now when I am mousing
over there is that value is 10000, looks good.
| | 06:29 | Then I'm going to jump into the next
one, which is calculateSecondValue.
| | 06:32 | There is a bit more going on here.
I'm creating an integer called zero.
| | 06:38 | Integer b here is about to call the
calculateFirstValue method again.
| | 06:42 | I don't want to go into that, I saw it
a moment ago, so what I will do instead
| | 06:46 | is use the Step over version, which
still means we called it, we did execute
| | 06:51 | that line, but I just didn't want to
go into that method and look at it.
| | 06:54 | To prove we did execute it, I can
actually see the b down here and our variable
| | 07:00 | section is set to 10,000, or I
could mouse over and see it that way.
| | 07:04 | So stepping forward, it looks
we're in a fairly boring for loop here.
| | 07:11 | And unfortunately this is going
to go around 5000 times right now.
| | 07:14 | I don't really want to click 5000 times,
as it ticks down, so what I'm going to
| | 07:21 | do is just step ahead and put a
breakpoint before the return statement, and
| | 07:24 | click the Play button to
move ahead to that point.
| | 07:27 | And looking at this, this
appears to be the problem.
| | 07:29 | And we're going to return zero from that.
We're saying return a, and we should
| | 07:33 | really have return the variable
called b so there was actually some value.
| | 07:38 | Okay, so that was our problem.
What I'm going to do is just stop.
| | 07:41 | That was a little quick, so it thought it quit.
| | 07:45 | Ignore that, I'm going to drag of my
breakpoints and say that here I should be
| | 07:49 | returning b, and in fact I
don't need that integer a line.
| | 07:53 | Of course this was just a constructed way
of causing a problem, but you get the idea.
| | 07:59 | We go ahead and run it, and now our
code is executing correctly, that 10,000
| | 08:06 | divided by 5000 is 2.
| | 08:08 | And that's a simple
introduction to the Debugger.
| | 08:11 | However, as we'll see in the next movie,
sometimes a couple of other things you
| | 08:15 | want to tweak about that.
| | Collapse this transcript |
| Creating an exception breakpoint| 00:00 | So you just saw how to use the debugger to
analyze something like a divide by zero situation.
| | 00:05 | There is actually a problem with
using divide by zero, it's a little too
| | 00:09 | obvious, not just to us but to the
computer itself, because if you have a
| | 00:13 | divide by zero issue, you will
actually immediately break into this situation
| | 00:18 | with the EXC_ARITHMETIC, because it's a
very low level, what's called a signal
| | 00:24 | that it is sending to the computer
itself, we can't go any further than this.
| | 00:28 | But some other cases, the program will
actually try and continue on, and you
| | 00:33 | won't immediately stop on the line that
caused the problem, you actually break
| | 00:37 | when Xcode figures out you can't go any further.
| | 00:39 | Now there is a couple of different ways
that might manifest itself, but let me
| | 00:44 | show you one of them.
| | 00:45 | I'm just going to stop this running
application and go and fix that divide by
| | 00:49 | zero exception, which was just
returning the variable called b instead of the
| | 00:54 | variable called a, and then I'm
going to go ahead and run this.
| | 00:58 | I have created the project that has
another error in it that's not necessarily
| | 01:02 | quite so obvious, so I'm going to click Boom!
| | 01:06 | And instead of jumping into a specific
line with a nice green highlight, what
| | 01:10 | we are getting down here are some error
messages being sent out here to the console.
| | 01:15 | Now sometimes you can diagnose a
message from that--I'm just going to widen
| | 01:20 | this so we can see more about it.
We have got mouse downs and sand effects, it's
| | 01:24 | basically our call stack going on.
| | 01:25 | And it does appear that
we have got an index beyond bounds.
| | 01:29 | But it's not telling me
exactly what line I am looking at.
| | 01:33 | Now, I could probably figure it out
from this line here, because I've got a very
| | 01:37 | simple application, but there
is a better way of doing this.
| | 01:41 | We can tell Xcode that we want to
break immediately, as soon as any exception
| | 01:47 | happens, as soon as anything
detectable causes a problem.
| | 01:51 | This is the way we do it.
| | 01:53 | I'm going to stop the app and just clear
out my console, I don't need that right now.
| | 01:58 | I'm going to jump into the breakpoints
navigator, that's the one that looks like
| | 02:03 | breakpoint symbol itself.
| | 02:04 | Now I don't actually have any
breakpoints right now, which is why nothing is
| | 02:08 | showing up here, but I'm going to add one.
| | 02:10 | And what I'm going to add is not a
breakpoint for a particular line, but I'm
| | 02:15 | going to add what's called a General
exception breakpoint, telling Xcode I want
| | 02:20 | to break if there's ever an Objective-C exception.
| | 02:22 | I do this by coming down to the plus button
at the bottom of that breakpoint navigator.
| | 02:29 | So again, I am on the
second to last section here.
| | 02:32 | And I click Add Exception Breakpoint.
It gives me a pop-up window.
| | 02:35 | What kind of exceptions do I want to break on?
I'm going to say All of them.
| | 02:40 | I could choose to do just Objective-C or C++.
And Break as soon as the exception is Thrown.
| | 02:46 | Optionally, I can click to add an
Action, like play a sound or run a command,
| | 02:50 | but I'm just going to leave
everything as is click Done.
| | 02:54 | So I'll now break on All Exception, I'm
going to go ahead and click Run, back to
| | 03:00 | the app, click the button again.
| | 03:03 | Now we immediately break, but we are
breaking on the line that caused the problem.
| | 03:08 | What's actually happening here is
online 42 I am creating an array with three
| | 03:12 | elements in it, which would be 0, 1, and
2, and then I'm trying to access what's at
| | 03:17 | position 3, what's at index 3?
Well, there is nothing there.
| | 03:20 | So that's the actual problem here,
and we are now breaking at the line that
| | 03:24 | caused it, so it's much easier to diagnose.
| | 03:27 | I need to change that it 2 and Stop it
and Run it again, and we are looking good.
| | 03:37 | So if you're finding that when you're
running is that you're not stopping in the
| | 03:41 | most helpful place, try this technique,
go in and add an exception breakpoint in
| | 03:47 | Xcode to make sure that you are
actually stopping as soon as possible.
| | Collapse this transcript |
| Using assertions| 00:00 | One useful technique for
troubleshooting in Cocoa is using Assertions.
| | 00:04 | Assertions help you find bugs
earlier than you would otherwise.
| | 00:08 | At a particular point in your
code you can add Assertions.
| | 00:11 | You assert something, you say at this
point something should be true.
| | 00:15 | A variable should be greater than 1,000,
or a string should be a certain
| | 00:18 | value, an object should be not nil.
| | 00:21 | And if what I have asserted
is false, that's a problem.
| | 00:24 | So here I have a very simple method called
doSomething being called by a button click.
| | 00:30 | It itself is calling this
complicatedCalculation method.
| | 00:33 | Now I might imagine there's an awful a
lot going on here, but what I'm going
| | 00:38 | to do is after our for loop, I'm really
hoping that the variable foo is equal to 5000.
| | 00:43 | In fact, that's what I want to assert.
| | 00:46 | And I create assertions like
this with a single call to NSAssert.
| | 00:52 | It's a very simple line, it looks like
a function call, and you can't think of it
| | 00:56 | like that, but technically it's a macro,
and that's very useful for a reason
| | 00:59 | I'll explain in a moment.
| | 01:01 | NSAssert takes two parameters, what
are you asserting, what is the condition
| | 01:05 | you're saying is true, phrased
like a condition in an if statement.
| | 01:09 | So for me I'm going to say I expect
the variable foo to be equal exactly to
| | 01:14 | 5000, that's what I'm asserting.
Then the second argument is the string.
| | 01:19 | It's the message that should be
logged if what I'm asserting is not true.
| | 01:24 | So I'll just do this as an NSString here,
the variable foo is the wrong value.
| | 01:33 | So what happens is we're going to
execute this code, we would come through this
| | 01:36 | for statement, we'd hit line 24.
| | 01:39 | And if what we see, what we have asserted is
true, nothing happens, we simply move on.
| | 01:44 | However, if what we say what we have
asserted is false, it will raise an
| | 01:48 | exception, and it will log this message.
And we could of course do this otherwise,
| | 01:52 | fill our code with if statements, but
this is a compact readable way to do it.
| | 01:57 | So I'm going to go ahead
and run the application.
| | 02:01 | Click the button to Check Value,
the value is 5000, nothing happens.
| | 02:06 | Everything is as I said it
should be, and we just continue.
| | 02:11 | Quitting and going back into that, what
I'll do is pretend we have made a slight
| | 02:15 | change to the logic of our program.
I'll just make a quick tweak to the for
| | 02:19 | loop and run this again.
| | 02:22 | Now I click the button, and we
instantly jump into the problem.
| | 02:25 | I don't know if you saw here, but
we're getting the messages being logged out
| | 02:29 | here to the console, including that
the variable foo is the wrong value.
| | 02:33 | And this is important to understand,
bear in mind when we use NSAsserts, this is
| | 02:37 | not casual informational
messages like you might do with NSLog.
| | 02:42 | If an assertion fails, it throws an exception.
It's a real problem.
| | 02:46 | What you're saying is true, it should
always be true, this should never fail,
| | 02:50 | and it will cause your app to stop.
And that's what we want here.
| | 02:53 | The reason that we do it as we're making
these bugs more significant as early on
| | 02:57 | as possible, and it's a
great technique for developers.
| | 03:00 | If we're going to fail,
fail as soon as we can.
| | 03:02 | Let us know about the problem early,
so I can fix it, rather than return this
| | 03:07 | value and pass it perhaps 10 levels
deeper before we fail later on.
| | 03:11 | Now, for example, I wanted to find
out what the value of it was, we can
| | 03:15 | actually call multiple different
versions of Assert, there's NSAssert1,
| | 03:18 | NSAssert2, and so on, just taking a
different amount of format specifiers and
| | 03:25 | parameters after the fact.
| | 03:26 | So if I wanted one parameter, I would
use NSAssert1 and just change my string
| | 03:32 | here so the variable
foo is %i and pass that in.
| | 03:39 | This time around when I run it, the
message should just say: The variable foo is
| | 03:44 | 4999, so very easy to add a very
compact succinct way to do this.
| | 03:52 | And one of the great things about this
is that because NSAssert is technically a
| | 03:57 | macro, here is one of the great things
about it over, say, a function like NSLog.
| | 04:01 | We can pepper our code with these
assertions, we can put them anywhere we think
| | 04:06 | is useful, and while we're developing,
they come in very handy, but it's pretty
| | 04:10 | easy for us to add a small
parameter to our Build Settings in Xcode.
| | 04:15 | I haven't talked much about Build Settings yet,
but we'll be doing that in the next section.
| | Collapse this transcript |
|
|
8. Distributing an ApplicationArchiving an application for distribution| 00:00 | So how do you get your Cocoa
Application to somebody else?
| | 00:04 | Let's say there are two
situations here, first, the informal idea.
| | 00:07 | You have created an app, even a simple one,
and you just want to run it on another
| | 00:11 | machine or even email it
to a friend or colleague.
| | 00:14 | And then there is the formal idea,
you have worked for months on your application,
| | 00:18 | and now you want to prepare it for
distribution, either free or selling it
| | 00:22 | yourself or of course, on the Mac App Store.
| | 00:25 | Now we begin all of this the same way,
by taking our project and archiving
| | 00:30 | it, and when we're in our project in Xcode, we
find the Archive option from the Product menu.
| | 00:36 | Now archiving might sound
like an odd thing to do.
| | 00:38 | If you think of archiving, it's
something you do to put some old files in
| | 00:42 | backup and forget about them.
| | 00:44 | But what we're trying to do is formally
bundle our application up at a point in time.
| | 00:50 | An application archive for us is
the application at a certain date in a
| | 00:54 | certain state, so we may end up
creating multiple archives at multiple times,
| | 00:59 | but each time we intend to distribute an app
formally or informally, we create an archive.
| | 01:04 | So I'm going to select the Archive
option from the Product menu. It creates an
| | 01:08 | application archive and by default
we'll open the Archive's Organizer.
| | 01:12 | This is actually not a new Window;
| | 01:14 | it's the same organizer window you
would use for Documentation or for
| | 01:18 | source code repositories.
| | 01:20 | And every time we archive the
application, we'll have a new entry show up here.
| | 01:25 | The application at a particular date and time.
| | 01:27 | There is not much you can do on this
window apart from add a Comment, perhaps I
| | 01:32 | am creating a First try one for testing here.
| | 01:35 | I can also choose to right-
click this and Delete the Archive.
| | 01:38 | If I choose to Show in the Finder,
I'll see this Xcode archive file. This is
| | 01:43 | actually a compressed file, we don't
need to go into it, but you can find it
| | 01:46 | there in the Finder.
| | 01:47 | Here is the two things I'm interested
in are the buttons at the right-hand
| | 01:52 | side to Validate and Distribute our
application. What we should first do is Validate it.
| | 01:57 | When we do this we have two choices:
| | 01:59 | Validate for the Mac App Store,
or for Direct Distribution.
| | 02:03 | Now Validation doesn't do a tremendous
amount, it's not validating your code
| | 02:08 | just mainly doing some
basic checks on the application.
| | 02:12 | If you Validate for the Mac App Store,
you're going to need to give it your Mac
| | 02:16 | app credentials, and you need to have
created an entry in iTunes Connect for
| | 02:20 | this application, which means you have
already got your Mac Dev account, you have
| | 02:24 | gone through all the contracts
arrangement setting up a company name and so on.
| | 02:28 | That's not necessary for us here, so
what I'm going to do instead is Validate
| | 02:32 | for Direct Distribution.
| | 02:33 | This will perform a few simple checks.
It's telling me that the archived
| | 02:38 | application doesn't contain an icon.
I haven't got a custom icon for this app yet.
| | 02:43 | Well, I'm going to do that in a little
while, so let's skip that for now just
| | 02:47 | say Finish, and we'll see in the Status
field here that we have Failed Validation.
| | 02:52 | Doesn't really matter because I can
choose to go ahead and distribute it
| | 02:55 | anyway using the default application icon.
| | 02:59 | So I'll click Distribute, and again,
we get a few different choices, do you
| | 03:03 | want to Distribute for the Mac App Store,
Export it with a Developer ID-signed
| | 03:07 | or some other option?
| | 03:10 | Now these options do often change in
wording and in arrangement, they have changed
| | 03:14 | between Xcode 4.2 and 4.3 and 4.4, so
I don't guarantee that what you'll see
| | 03:19 | will be exactly the same as what I'm seeing.
| | 03:22 | Well, I'm going to go as informal as
I can, and in this dropdown I have the
| | 03:27 | option to Export as an Xcode Archive.
| | 03:30 | That's not what I want. I want
to Export this as an Application.
| | 03:34 | I don't need a Mac Installer Package.
| | 03:36 | That's not necessary, and it's
not necessary for most applications.
| | 03:39 | Well, I do need to be aware that with
the release of Mountain Lion in 2012 with
| | 03:45 | the security features called
Gatekeeper, if I don't sign this app with a
| | 03:49 | Developer ID, anyone with Gatekeeper
set to require a Developer ID won't to be
| | 03:54 | able to run this unless they change
their settings, we'll talk more about
| | 03:58 | Developer ID in just a moment.
| | 04:00 | So, I'm doing this at the most
informal level, say I just wanted to send this
| | 04:04 | app to a colleague on the same team,
we both know what's going on, I could
| | 04:08 | even choose not to sign it at all, so I'm
going to click Next, and select to Don't Re-sign.
| | 04:13 | Depending on the level of development
you have done your particular machine, you
| | 04:17 | may have multiple signing identities
available in the dropdown box based on what
| | 04:21 | you have created from your Mac Dev
account or your iOS Dev account.
| | 04:26 | But I'll choose to not to re-sign it,
click Next, and so it's going to ask,
| | 04:30 | where do I want to save this?
| | 04:32 | I'll put it on my Desktop and click
Save. Just go now and minimize that and all
| | 04:38 | we have is the application.
| | 04:40 | The reason I have got a folder called
Metronome is that's just where I had the
| | 04:43 | project that I had opened.
| | 04:45 | This is our app with its
default application icon.
| | 04:50 | Archived, Validated, set up for
Distribution. I could email this to someone, put
| | 04:54 | it to on a share drive, put it on a web site, allow
people to download and run it, it's ready to go.
| | Collapse this transcript |
| Working with debug and release builds| 00:00 | So we need to archive our applications
during the process of distributing them,
| | 00:05 | but technically we could do a little
more informally. You may have noticed that
| | 00:10 | with something like a simple
"Hello, World!" level application,
| | 00:14 | when you build the application,
it is already built as a Cocoa App.
| | 00:17 | If you expand the Products folder in
your project navigator, you'll actually
| | 00:21 | find the application itself. I could
right-click and choose to Show this in the
| | 00:26 | Finder, and you could take this file
just double-click it to run it, whether
| | 00:30 | Xcode is open or not, or even copy it
to another machine and run it there, but
| | 00:35 | this really isn't the way to do it.
| | 00:37 | Because when we build, when we choose to
run our application or hit Command+R to
| | 00:42 | do that, what we're doing is running
in debug mode, using a Debug Build.
| | 00:48 | Your project has been compiled and linked
together with symbolic debug information
| | 00:53 | that's useful to us as developers but
not to the end user. Might have things
| | 00:56 | like the state of the
breakpoints in the application.
| | 01:00 | Now when we instead choose to Archive
our application, we're using a Release
| | 01:05 | Build instead of a Debug Build, and that
does not include all the hooks into our
| | 01:09 | code that the debugger needs.
| | 01:11 | Now it still does have some
symbolic information which might help us
| | 01:15 | diagnose crashes in a Released app,
but it compiles and builds with a
| | 01:19 | different set of options.
| | 01:21 | So these Debug and release
Builds are already set up in Xcode.
| | 01:25 | They are already configured
for a typical application.
| | 01:29 | If I want to change anything about them,
I can go to the Project settings and
| | 01:34 | find the Build Settings for this just
by clicking the top level icon with the
| | 01:38 | project name in the Project Navigator.
In this section we have Build Settings.
| | 01:43 | Now you'll actually find Build Settings
under the both the Project selection and
| | 01:48 | in the Target selection.
| | 01:50 | A common question I get is
what is the difference between the two?
| | 01:53 | They both have Build Settings.
| | 01:55 | Now for an example like this in a new
Cocoa Application project, not really any
| | 02:00 | difference at all. We have one project,
this entire project, this application
| | 02:04 | that we're building that creates one
target, the actual compiled application.
| | 02:10 | In a more complicated project, you
might have multiple targets, and each
| | 02:15 | target could have slightly different build
settings from the default project build settings.
| | 02:20 | Now particularly early on in your Cocoa
career, you can leave everything here as is.
| | 02:27 | If I decide to scroll through the
Build Settings, and I can choose either the
| | 02:30 | basic ones or click the All button here to
see all of them, there are a lot of options.
| | 02:36 | Again, most of them you don't really care about.
| | 02:39 | What you'll find is that with a few,
not many, there are different options for
| | 02:44 | the Debug and Release.
| | 02:48 | Coming down, for example, into the
Preprocessing section, I have different
| | 02:51 | Preprocess or Macros for Debug and
Release, and one of the few things I might
| | 02:56 | change, which I mentioned earlier on
in the course is in the Preprocessor
| | 03:00 | Directive section, and you can either
scroll through this, you can also use
| | 03:04 | the search filter button at the top here to
filter down to anything that matches those words.
| | 03:11 | If I'm using Assertions, that I'm
using that NSAssert call in my code, what I
| | 03:16 | can do is make an entry here by double-
clicking the Release section, click that
| | 03:21 | plus button, and I will add in
the NS_Block_Assertions entry.
| | 03:31 | This written in uppercase with this
particular format will strip out any of the
| | 03:37 | NSAssert calls in my Release build. But
one of the questions might be, how do I
| | 03:42 | know what I'm using, how do I know if
I'm using a Debug Build or a Release
| | 03:45 | Build, where is that option?
| | 03:47 | Well, that's already set up in Xcode 2,
and it's in what's called a Scheme,
| | 03:52 | a collection of settings for the
different things you want to do with this project.
| | 03:56 | Now just to show where those are, if I
come to my Product menu, we have got some
| | 04:02 | Edit Scheme, New Scheme, and Manage Schemes,
we already have a scheme for this application.
| | 04:06 | You can either get it
from this menu or you can get it from the
| | 04:09 | schemes dropdown box. By clicking on this,
it'll allow me to see that I have got a
| | 04:14 | scheme for this application called
Metronome running on 64-bit, I can actually
| | 04:19 | jump in to edit it, so either from the
dropdown box or from the Product menu.
| | 04:24 | And what this scheme is showing me
is that I have multiple configuration
| | 04:28 | settings for what happens when we
Build, what happens when we Run, what
| | 04:33 | happens when we Test, what happens
when we Profile or Analyze, and what
| | 04:37 | happens when we Archive.
| | 04:38 | Now in this course we don't really
get into the whole idea of testing or
| | 04:42 | profiling, those options are also
available from either your Product menus or by
| | 04:48 | holding and clicking on the Run button.
| | 04:50 | I'm interested here in the difference
between Run, because when we Run, what
| | 04:54 | we're doing is we're using a Debug Build.
I can also change here that I'm using
| | 04:58 | the LLDB Debugger, I could choose to use the
GDB Debugger instead. I'll leave it as default.
| | 05:04 | There is a couple of options
here, like does the program Launch
| | 05:07 | automatically when we're running it,
or do we Wait for the app to Launch if
| | 05:11 | you're manually launching it?
| | 05:13 | But the important part here is that
we're using the Debug Build Configuration,
| | 05:18 | but when we Archive, when we select
that option, we'll automatically be using
| | 05:22 | the Release Build Configuration, and
there is not many options available for us
| | 05:27 | in Archive other than do I want to
Rename that archive from the default project
| | 05:31 | name, and when I archive, do I
immediately want to Organizer a window to appear
| | 05:36 | with that recent Archive in it?
| | 05:38 | And early on you don't really have
to change anything about this, but
| | 05:41 | understand that we always have a
scheme that allows us to choose what the
| | 05:46 | settings we're using between
Release and Debug Builds, and that will
| | 05:49 | automatically be what's called when you select
to Archive from the Xcode project menu.
| | Collapse this transcript |
| Sandboxing an application| 00:00 | Sandboxing is a technique Apple have
introduced to help with security.
| | 00:05 | Say you download a calculator app or
buy one from the Mac Apps Store.
| | 00:09 | Well, think about this, do you want
that app to immediately have complete and
| | 00:13 | total access to your file system, to the
network, to your microphone and webcam,
| | 00:17 | to the devices attached on your USB ports?
| | 00:20 | Well, of course you don't, but by
default that is the way that applications have
| | 00:25 | worked in the past, they run with the
privileges of the user who's running them.
| | 00:30 | Sandboxing gets us away from this situation.
| | 00:33 | When we add Sandboxing, simply put,
it means that applications are put in
| | 00:37 | containers by the
operating system, by OS X itself.
| | 00:41 | Sandboxing limits what the application
can do down to only what it needs to do,
| | 00:46 | and it makes you as a developer say
up front exactly what it is your app needs to do.
| | 00:52 | And if attempts to do something else,
that would be blocked and Sandboxing
| | 00:56 | is important, this is now required, if you
want to put your app in the Mac App Store.
| | 01:02 | You have to say exactly where your
application needs, there is a set of options,
| | 01:06 | does it need the webcam?
Does it need the microphone? Does it need
| | 01:10 | access to the network? And you say
exactly whether your app should be entitled
| | 01:15 | to do any of these things,
they're referred to as entitlements.
| | 01:19 | Now in this course we haven't really
done anything that would require special
| | 01:22 | permission, special entitlements,
we're not using the webcam or reading and
| | 01:26 | writing to the file system or using USB.
| | 01:29 | Now I do have a very simple
project that I have created here.
| | 01:32 | What I have done is drag on a
control called the web view.
| | 01:35 | We haven't used this before, but in
essence it's a very simple control.
| | 01:40 | It really is a little embedded browser
control, and all I have done in my AppDelegate
| | 01:45 | header file is I set up my WebView as
an outlet, and then in the awakeFromNib,
| | 01:51 | what I'm doing here is simply creating
a request to lynda.com and loading that
| | 01:56 | request into that WebView control.
| | 01:59 | So if I go ahead and run this,
we'll see the impact of that.
| | 02:02 | Not terrifically impressive, we're
simply loading in a web page inside that, so
| | 02:07 | we're actually making a
call out there to the network.
| | 02:10 | I'm going to quit out of that and go back
into Xcode. And let's see how to turn on Sandboxing.
| | 02:15 | Turning on Sandboxing is very simple,
and it's very simple even if you do
| | 02:20 | require certain entitlements.
| | 02:22 | So I'm going to jump over in my project
navigator into the first section here,
| | 02:27 | and what I'm looking for is the
settings for my Target, so I'm in the Summary
| | 02:31 | section of my Target.
| | 02:32 | Here is where you turn on Entitlements.
I check this box, and what I'll instantly
| | 02:38 | get over here in the navigator
is a simple property list file.
| | 02:42 | In this case it has one value in
here that Sandboxing is turned on.
| | 02:47 | If you don't see that value, then I'll
click back into the Summary section of my
| | 02:51 | Targets, and underneath it I'm going to
have Enable App Sandboxing turned on.
| | 02:57 | This is where you will affect the Entitlements.
| | 03:00 | You're going to say explicitly should we
allow Camera Access, Microphone, Printing.
| | 03:04 | Access to the Address Book, access to
say the movies file, and just Read Access
| | 03:10 | or Read/Write Access,
access to the Downloads Folder.
| | 03:14 | So I have turned on Sandboxing, and
right now I'm saying I'm not requiring any
| | 03:18 | of these Entitlements.
| | 03:20 | I'm going to click the button here to
Validate Settings, project settings are
| | 03:23 | valid, and I'm going to go
ahead and build the application.
| | 03:27 | Now I'm building this, now one
restriction is as soon as you turn on Sandboxing
| | 03:31 | your app does need to be signed of
the process of building it, and if you
| | 03:37 | haven't already set yourself up with
the proper certificates to sign that,
| | 03:41 | you're going to need to spend a little
time in the Mac Dev Center making sure
| | 03:45 | that you get your own certificates
generated for development and then installing
| | 03:49 | them into your Xcode.
| | 03:51 | I'm going to just say Always Allow, to
make sure that it's using my certificates
| | 03:54 | to sign this application now.
| | 03:57 | So, we have compiled correctly, that's it,
Sandboxing is turned on. I'm going to
| | 04:01 | go ahead and Run the application, which
should immediately bring back that web
| | 04:06 | page, but it isn't going to do that.
| | 04:09 | However, do notice that we didn't
crash, typically speaking. Blocked access
| | 04:13 | won't cause the program to
crash, it just won't work.
| | 04:16 | The reason is we don't want the user
being bombarded with problems, so there's
| | 04:20 | not really a lot telling us why this
web view isn't working. But I know I
| | 04:25 | turned on Sandboxing, so let's go and
figure out how we can diagnose this.
| | 04:31 | I'm going to quit out of that, and
then I'm going to open up the console.
| | 04:34 | When I say console, I don't mean the Xcode
console, I don't just mean the debug area.
| | 04:40 | What I'm going to do is go into Console,
I'll just use Spotlight to get there,
| | 04:45 | and you'll actually find
that Console is available here.
| | 04:48 | I'll click that and open it up.
| | 04:50 | This is giving me all the console
messages for OS X itself, for this operating
| | 04:54 | system, this computer.
| | 04:56 | Now what I'm going to do is make sure
that all messages are selected by the
| | 05:00 | system log and then over here in the
String Matching section, I'm going to type
| | 05:04 | in the word Sandbox, and to filter even
down, you can put sandbox with the D at
| | 05:09 | the end, and what I'm actually seeing
here is some messages that these are
| | 05:13 | Sandboxing messages for this
particular program, in my case, it's called
| | 05:17 | SandboxExample is the name of my application.
| | 05:20 | And what's happening is we're getting
this denied network-outbound call, we're
| | 05:25 | not being allowed to call out to
the network, we're being shut down.
| | 05:29 | So, I need to go and fix that. I'm
going to quit the Console, go back into my
| | 05:33 | Project and in the settings here, I'm
going to say yes, I want the Sandboxing
| | 05:38 | on, but I need to allow outgoing
network connections and the difference here
| | 05:42 | between outgoing and incoming, it
doesn't mean that we can't reach out to the
| | 05:47 | network and bring back some contents
from say web page, but I do mean that my
| | 05:51 | app is not responding to incoming
network connections. It doesn't need to do
| | 05:54 | that, so I don't want to support that.
| | 05:57 | So we do that check box and then go
ahead and run this again, and now we are
| | 06:04 | able to call out to the network
and retrieve some contents there.
| | 06:08 | So Sandboxing is as of now--June 1st,
2012--is required for all new submissions
| | 06:14 | to the Mac App Store, and it is
highly recommended for every application.
| | 06:18 | This is the basics of how to turn it on,
how to diagnose any problems with it.
| | 06:23 | If you do need to know more, take a
look at the application Sandboxing details
| | 06:27 | on the Mac Dev Center.
| | Collapse this transcript |
| Using Apple's Developer ID| 00:00 | I have mentioned Developer ID a couple of
times in this course, particularly when
| | 00:04 | talking about archiving and creating
a distributable version of our app.
| | 00:08 | Developer ID became important in 2012,
along with Sandboxing, and the reason
| | 00:13 | that it's important is that in Mountain Lion
there is a security feature called Gatekeeper.
| | 00:19 | For most users Gatekeeper just becomes obvious
as part of system preferences in Mountain Lion.
| | 00:24 | There is an option to allow the user
to choose and install software only from
| | 00:28 | the Mac App Store and identify developers.
| | 00:31 | If this option is selected and your
app is not signed with the Developer ID
| | 00:36 | certificate issued by Apple, it will not launch.
| | 00:39 | Now let's be clear here, if you're
planning to sell your app in the Mac App
| | 00:44 | Store, you do not need to worry about
Developer ID, because all the signing that
| | 00:48 | you already do to get inside
the Mac App Store is good enough.
| | 00:51 | Developer ID is for the case where
you want to sell it or distribute it to
| | 00:56 | Mountain Lion users outside of the Mac
App Store, but of course, you may need a
| | 01:00 | Developer ID if you want to do both, but
becoming an identified developer is not
| | 01:05 | complex, there's just a
few things to be aware of.
| | 01:09 | To get a Developer ID certificate, you
do need to be a paid up member of the Mac
| | 01:13 | Developer Program, not just
a registered Apple Developer.
| | 01:16 | Now if you're already in the Mac
Developer Program, you may find that you have
| | 01:20 | the Developer ID certificates already.
| | 01:23 | You could either use the Mac Dev Center
or you may even find them in Xcode.
| | 01:27 | If you go into your Organizer window and
look at the Devices section under Teams,
| | 01:32 | you may find a couple of certificates
for Developer ID for Applications and
| | 01:36 | Developer ID for creating Installers.
| | 01:38 | If you haven't gone through the
process of setting up your developer device,
| | 01:42 | then take a look at your account
details in the Mac Developer Center.
| | 01:46 | There is an area of this called the
Developer Certificate Utility, and if I go
| | 01:53 | into this area then click on Certificates.
It'll tell me the ones that I already have.
| | 01:57 | If we see a couple for Developer ID,
we're good, if not, you can ask for one by
| | 02:02 | clicking the Create Certificate button
and one of the options you'll find is the
| | 02:07 | Developer ID Certificate.
| | 02:09 | There are two kinds as we can see here,
and the difference just depends on how
| | 02:13 | you're planning to distribute your app.
| | 02:15 | There is one certificate for regular applications
and one for creating installer packages.
| | 02:21 | Now I'm not covering Creating Installer
Packages in the course. We are working
| | 02:25 | with the idea of a standard application,
so let's see how complex it is to sign
| | 02:29 | an application with a Developer ID.
| | 02:31 | I'm going to jump into Xcode where I
have a StandardCocoaApplication that I have
| | 02:36 | just created. It doesn't have any
functionality in it, I haven't done anything
| | 02:39 | with Entitlement or Sandboxing, I just
want to share the process of signing this app.
| | 02:44 | Like Sandboxing, it does require that
my certificates are all in order first,
| | 02:48 | but it will tell me if they aren't.
| | 02:49 | So to do this what I want to do is go
into my Project settings and selecting the
| | 02:56 | settings for the entire project go into
Build Settings, and what I'm looking for
| | 03:01 | is the Code Signing section.
| | 03:04 | Rather than scroll up and down, it's
just easy enough to filter on, say, the word
| | 03:08 | signing, and what we should find is
this one called Code Signing Identity.
| | 03:13 | Right now it's set Don't Code Sign this. I
need to associate that Developer ID Certificate.
| | 03:19 | So as long as they have been downloaded
and configured already, I can select from
| | 03:22 | the dropdown box, find my Developer ID
Application, and either just directly run
| | 03:28 | this, come up to Product, and tell it to Build.
| | 03:31 | Depending on if I have allowed Xcode
access to my certificates, I may need to
| | 03:35 | allow this once or twice. It's actually
a lot easier to just say Always Allow if
| | 03:39 | you're planning on doing this a lot.
| | 03:41 | So that's how to sign an application
with a Developer ID. And then when we go to
| | 03:46 | the steps of archiving this. It will
be signing our Release Build with that,
| | 03:50 | and when I choose to Distribute it, I can
export it as a developer ID signed application.
| | 03:57 | It's detecting that I really just have one
Developer ID here, click Next, and we're done.
| | 04:05 | That's the entire process.
| | 04:07 | Very simple, and again, not needed if
your intention is to Distribute purely in
| | 04:12 | the App Store, but highly recommended
otherwise and very simple to do.
| | Collapse this transcript |
|
|
9. Finishing TouchesCreating full-screen apps| 00:00 | In OS 10.7 Lion, Apple introduced a
standardized Full Screen mode for OS X, so
| | 00:06 | apps can shift into
taking over the entire screen.
| | 00:09 | If I'm in Safari I just need to click
this Full Screen icon at the top right
| | 00:14 | of the Title Bar, and will take over the
entire screen, even including the Apple menu.
| | 00:18 | If I move my mouse up to the top I can
make it comeback, so I can shift out of
| | 00:23 | Full Screen mode, and I can still get
to the Dock in most cases, but it allows
| | 00:27 | us just to take over that space, Safari
has it, Mail has it, even Xcode has the
| | 00:31 | Full Screen option, so any
app can choose to do this.
| | 00:35 | The first question of course
is does it actually makes sense?
| | 00:39 | There is two main reasons why you would want it.
| | 00:41 | First will be creating a distraction-
free reading or writing environment.
| | 00:46 | For example, if I'm in Preview and
reading a document, I can go full screen just
| | 00:50 | to focus on the actual document that
I'm taking a look at, and you'll find a
| | 00:55 | quit a few writing tools also take over
the full screen, even if they don't use
| | 01:00 | the entire space to help you focus
without being distracted by other applications
| | 01:04 | And of course the other reason
for it is when you have limited
| | 01:08 | screen real estate and a lot
going on in the application.
| | 01:12 | Say you're using Xcode on an 11-inch
MacBook Air, being able to make that menu
| | 01:17 | disappear and use every last available
piece of screen can be very helpful, but
| | 01:21 | on the other hand an application
that you want to jump in and out of very
| | 01:26 | quickly, like System Preferences, this
would be a very poor choice for supporting
| | 01:30 | full screen, and it doesn't support it.
| | 01:33 | So it's not required, and it's not
expected of everything, but it is very easy
| | 01:37 | to implement if you
choose to. Let's take a look.
| | 01:40 | I have got a brand-new Cocoa application just
to show that there is nothing that's been added here.
| | 01:45 | Now I do want something that we can
see on screen, because otherwise when I
| | 01:49 | implement it will just have a lot of
gray, so I want something on screen.
| | 01:54 | Now it'd be a poor choice here to have
just say a button or two, so I'm going
| | 02:00 | to grab a couple of the larger
controls just to give us something to look at,
| | 02:04 | I'll jump into my Data Views section
here, drag on a Table view and an Outline
| | 02:13 | view and just vaguely line them up. I'm
going to embed them together into a Split view.
| | 02:18 | So just select both of those and then from
the Editor menu decide to Embed In > Split view.
| | 02:25 | Now there is nothing that I'm doing
here as anything to do with actually making
| | 02:29 | something full screen, I just
want to give it something to look at.
| | 02:31 | So I'm just going to take care and
drag these and connect these to the edge
| | 02:36 | of the page so we can see the effect that
going full screen will have. That will do.
| | 02:44 | So now let's do the full screen part.
| | 02:45 | In our app I'm going to go to the
Window making sure the Window is selected,
| | 02:50 | jump into my Attributes Inspector,
and what I want to do is come down to a
| | 02:55 | dropdown box that says Full Screen,
which by default is Unsupported. I'm going
| | 03:00 | to select it to support the Primary
Window, and that's actually automatically
| | 03:05 | added the standard Full Screen icon
to the top right of the Title Bar.
| | 03:10 | I'm going to hit Command+R to run this
application, and we have the app fairly
| | 03:16 | simple split view going on here, but I
have this Full Screen icon. I'm going to
| | 03:21 | click it, and we immediately shift into full
screen, we have taken over the entire screen.
| | 03:26 | If I do move up to the top move
my mouse here, I do have the option
| | 03:29 | automatically popping up here to go
back to the regular size. It works.
| | 03:34 | However, we also need a touch more,
because if I look at the menu for the
| | 03:40 | application, I do have the regular
view menu which has Show Toolbar and
| | 03:43 | Customize Toolbar there. They are grayed out right
now simply because no behavior is happening there.
| | 03:48 | But if I click back into Xcode, I
have that Full Screen button, but what I
| | 03:53 | usually expect to see is under the
view menu I have got an Enter Full Screen
| | 03:57 | option with the shortcut that is Command+Ctrl+F,
and that is the standard way it should look.
| | 04:03 | In Safari it's in the view menu, Enter
Full Screen, Command+Ctrl+F, and what
| | 04:08 | happens is if I select this we'll go
into entering full screen, but if I move
| | 04:13 | back up to the menu and look at the
view menu for Safari again it's changed to
| | 04:17 | Exit Full Screen, it's
just toggling between the two.
| | 04:19 | So we have got a standard
menu option, standard wording.
| | 04:23 | The last option in the view menu where
that shortcut key, and we should support
| | 04:27 | it in our application as well, so let's do that.
| | 04:30 | Well, editing this Window I can
actually jump up here into the menu itself and
| | 04:35 | see that in my view menu I do have just
the two standard options, Show Toolbar
| | 04:39 | and Customize Toolbar.
| | 04:41 | We have a couple of choices here. We
could add a manual menu item from the
| | 04:46 | Windows & Menus section, drag that on
and start configuring it, hook up the IB
| | 04:54 | actions and so on, or we can do it the
easy way, which is if I scroll down all
| | 05:00 | the way to the bottom, I actually have
a Full Screen Menu Item. I'm going to
| | 05:05 | simply drag on that to the open view
menu and put it at the bottom here.
| | 05:11 | Now usually what I'd actually want is
this is at the bottom, but there is a
| | 05:15 | separator above it, a horizontal line,
so I'm going to find the separator from
| | 05:19 | the Window menu section. There it is,
Separator Menu Item, and drag that above
| | 05:23 | Enter Full Screen just to
give us the proper look.
| | 05:27 | Usually when we're working with menu
items we would then select them, and we
| | 05:30 | would look at our Connections
Inspector and see if they're hooked up to
| | 05:34 | anything, but we don't need to do any
of that. It's actually already working.
| | 05:37 | Dragged on, if I highlight this and
select my Attributes Inspector I can even see
| | 05:42 | that I have got the shortcut key entered in.
| | 05:46 | If I go to the Connections Inspector, it
is actually passing the toggleFullScreen
| | 05:50 | menu to the First Responder, which
will get passed itself to the application.
| | 05:54 | So all I really need to do is go ahead and run it.
Currently have the other one running. I'll hit Stop.
| | 06:00 | The application launches, I come up
to my view menu, I have the Enter Full
| | 06:04 | Screen option, I select it, we shift
into Full Screen mode, I go back up to the
| | 06:09 | view menu, and it's changed to Exit
Full Screen. Not only that, but we can
| | 06:14 | check to see that the shortcut keys
work. I hit Ctrl+Command+F, and we Shift
| | 06:18 | back into the regular mode.
| | 06:21 | So very easy to implement just with a
couple of quick changes in the Attributes
| | 06:26 | Inspector and a drag and drop onto the menu.
| | 06:28 | The most work you're going have to do
in supporting full screen is actually
| | 06:32 | testing your layout on a variety of
different sizes and becoming familiar
| | 06:36 | with how auto layout is going to attempt to reformat
your user interface elements, and that's it.
| | Collapse this transcript |
| Creating icons for OS X applications| 00:00 | So far we have just been letting Xcode
use the default application icon for our
| | 00:04 | Cocoa Apps, that's the one that looks like this.
| | 00:07 | You might see it in Xcode itself, but
this icon is actually attached to the
| | 00:11 | application itself, and unless we say
otherwise, it's the one we are going to be using.
| | 00:16 | Now creating icons for a Mac
application is really two issues.
| | 00:19 | There is the technical side, what
do we need to do to make this work?
| | 00:23 | And of course the creative side, what
are all the things we could do with the
| | 00:28 | icon design, things like color,
perspective, should we use text and so on?
| | 00:32 | Now for the creative side of things,
I am going to point you mainly to the
| | 00:36 | terrific section in the OS X Human Interface
Guidelines, particularly the chapter on Icon Design.
| | 00:41 | There is a lot of great content here on
using perspective and color and shadow
| | 00:47 | and on other aspects many developers
don't really think about, such as the
| | 00:50 | different genres of icon that, in fact,
Apple designs their icons differently based
| | 00:55 | on the kind of application it is.
Whether it's utility or a consumer app will
| | 01:00 | drive different decisions
regarding color and image.
| | 01:03 | But we are going to focus
here on the technical side.
| | 01:06 | Let's say we have a custom icon.
| | 01:08 | We want to make how do we make it
work, and here's what we have to do.
| | 01:11 | First know that an icon is not just one image.
| | 01:15 | We are expected to provide multiple
image files, multiple sizes of artwork for
| | 01:19 | an icon, and that's because on the Mac
there are many situations in which an
| | 01:24 | application icon is used.
| | 01:25 | From the most basic idea of using the
icons in the Dock, then if we switch to
| | 01:30 | the Applications folder, we see
them here at a different size.
| | 01:34 | In the Finder Cover Flow window where
the icons can be shown very large and
| | 01:38 | support a lot of visual detail, or on
the flipside over to somewhere like
| | 01:43 | Spotlight, where the icons will show up
but can be shown very small. So how do
| | 01:48 | we drive these decisions?
| | 01:50 | You take your preferred graphics
application--Photoshop, Fireworks, whatever you
| | 01:54 | like--and we are supposed to provide
icons at five different sizes and OS X will
| | 01:59 | choose the right size at the right time.
| | 02:02 | Size 1 is 512x512 pixels,
we have got 256, 128, 32, and 16.
| | 02:10 | We need to create images for our icons
at all of these sizes, and now you can
| | 02:15 | just provide one large image
and expect OS X to scale it.
| | 02:18 | You are supposed to support the
idea that larger icons can support more
| | 02:22 | detail than smaller ones.
| | 02:24 | What looks good at 512x512 is going to
look messy if you just scale it right
| | 02:29 | down to 16x16, so it should
be redesigned for that size.
| | 02:33 | But one more thing, it's not just
five images, it's actually ten that are
| | 02:38 | required because we must also
provide duplicates of these at double
| | 02:42 | resolution for a Retina display.
| | 02:45 | So with the 512x512 icon, we also need
that at 1024x1024 and so on, and Mac OS X
| | 02:53 | will pick the right set of
images for the correct device.
| | 02:57 | And it's very important what you name
these ten files because that's how OS X
| | 03:01 | will pick the right
image in the right situation.
| | 03:04 | And this is the format, the 512x512
pixel images should be icon_512x512.png.
| | 03:14 | We have icon_256x256.png and so on.
| | 03:19 | However, we can't just use this same
format for the Retina display version
| | 03:23 | because we'd actually end up with
two icons of 512x512, so all the Retina
| | 03:28 | display icons end in @2x. But
although the actual Retina icon might be
| | 03:35 | 1024x1024, we would call it 512x512@2x.png,
and this is the format that Apple use
| | 03:45 | for the Retina artwork with
the iPhone and iPad as well.
| | 03:48 | So these are the ten images that we
need to create and the names of those
| | 03:52 | images, and with those together we can start
the process of getting them into our project.
| | 03:58 | So in my Exercise Files folder, I actually
have some icons that were created earlier.
| | 04:04 | Just selecting them, I am going to use
the spacebar to look a little bit at them.
| | 04:08 | Here's the 16x16, same one at
twice the resolution, they may go to 32, to
| | 04:15 | 128, to 256, and to 512.
| | 04:17 | Now I have created them slightly differently
for each size, and you'll see why in a minute.
| | 04:23 | So here is what to do.
| | 04:24 | Once you have got these images, you don't just
drop them into Xcode. That would be too easy.
| | 04:29 | In fact, the first step
doesn't involve Xcode at all.
| | 04:32 | First create a folder, and this folder
can be anywhere. I am just going to put
| | 04:37 | it on my Desktop, make a new folder here,
and I will call it icon.iconset, and
| | 04:43 | the name is important here.
| | 04:44 | Now this is a stepping stone to creating a single
file that will bundle all our images together.
| | 04:50 | I have called that iconset. I am
getting little confirmation message here, do I
| | 04:53 | want to add the
extension to the end of the name?
| | 04:55 | Yes I do, so I will add that, and I am
going to grab my ten images and just
| | 05:02 | drag them into that iconset folder, and
you might think, well what does that do?
| | 05:08 | Well, this .iconset name Finder treats
a little differently, so I am going to
| | 05:13 | select that folder and then just hit the
spacebar because what will happen is it
| | 05:17 | gives us a quick look preview here that
involves this little slider Bar at the
| | 05:21 | bottom, and as I drag it smaller, we
can actually see the different images
| | 05:25 | appear at different sizes. That's why I
try to make it a bit more obvious what's
| | 05:30 | happening as we change the image, that
we are actually picking the different files.
| | 05:33 | We are not just scaling it down,
we are using a different image.
| | 05:37 | But the next step is we need to take
our .iconset folder and package all these
| | 05:42 | images together into a single
file which is called a .icns file.
| | 05:47 | And Apple used to provide a separate
program called icon composer to do this, but
| | 05:53 | in Xcode 4.4 it was removed, and
we use a command line tool instead.
| | 05:57 | So I am going to launch a terminal
window. I will just do it by typing in
| | 06:02 | terminal in spotlight, launching it
this way. Going to change directories to
| | 06:07 | my Desktop, which is where my iconset
folder is and the command I am going to
| | 06:12 | run is iconutil, all one word, so we
say iconutil space -c for convert, because
| | 06:19 | we are converting an iconset into an
icns, so what I am converting to?
| | 06:25 | I am converting to icns, and then I give it
the path to the iconset folder which I
| | 06:30 | just called icon.iconset.
| | 06:35 | Hit Return, it thinks about it for a
second, and what actually happened is it's
| | 06:39 | created that here, I have got icon.icns
in the same folder--in my case the
| | 06:44 | Desktop--that your iconset was in.
| | 06:47 | Now at this point if you are missing
images, you'd have an error message here,
| | 06:50 | you'll only get this to work if
you have got all the images you need.
| | 06:55 | This .icns file is the icon that Xcode
wants, so I am going to go into Xcode
| | 07:02 | where I just have a very
straightforward Cocoa application, haven't done
| | 07:05 | anything with this yet apart from created,
and I am going to just shrink it so I
| | 07:09 | can see my Desktop here.
| | 07:11 | I am going to jump over into my Project
Settings. So selecting the top icon over
| | 07:15 | here in the File Navigator, I am going
to choose the Target section and select
| | 07:20 | the app, and we have a droppable area
for our application icon. So I am going to
| | 07:25 | grab that .icns file, drag it
over here, let go, that's it.
| | 07:30 | Now we have an Application icon.
Well, let's prove it.
| | 07:34 | I am going to go ahead and run this.
| | 07:37 | Build Succeeded, again,
it's a very simple Cocoa app.
| | 07:39 | There is nothing in this, no functionality yet.
| | 07:42 | I have my Demo up here. If I hit Command+Tab,
I can see that I have a proper icon
| | 07:47 | being selected at that size.
| | 07:49 | I can even see in Xcode, the actual
target itself is using the smallest,
| | 07:53 | the 16x16 version of the icon, so it's
using the correct size for the correct context.
| | 08:01 | If I come down to my Products section
and right-click my Demo app and say to
| | 08:05 | Show in Finder so we can actually see
that application on the File system, I am
| | 08:10 | going to switch to the cover flow version,
and this will give us one of the best
| | 08:15 | ways that we can see this icon
changing to different sizes as I drag it to
| | 08:19 | larger and then to smaller
and then to smaller still.
| | 08:23 | OS X will take care of scaling this
and showing the right set of icons if you
| | 08:28 | have a Mac with a Retina display,
but this is how you bundle your icons
| | 08:31 | together and get them into your project.
| | Collapse this transcript |
|
|
ConclusionFinal thoughts| 00:00 | So we're reaching the end of this
Cocoa Essential Training course.
| | 00:03 | What I wanted to do this course was as
quickly as possible take you through the
| | 00:07 | things you'll always need
in every Cocoa application.
| | 00:10 | Layouts and Controls, Target and
Action, Delegation and MVC, application
| | 00:15 | lifecycle, data sources, key-value coding,
and bindings and sandboxing, but of course, it gets deeper.
| | 00:22 | And while we may have covered the
things you'll need in every Cocoa app, we may
| | 00:26 | not have covered the things you need
in the one you want to build right now.
| | 00:30 | You might need Core Data or iCloud or
more on graphics and animation or working
| | 00:35 | with audio and network communications.
So the question is, well, what now?
| | 00:39 | Now you got the basics,
where do you go from here?
| | 00:42 | And I think it's a great time to re-
inspect the Mac Developer Center and the
| | 00:45 | amount of content that is available
here, because it's very easy to think of
| | 00:50 | this as just reference, as your class
reference libraries, but it's a lot more than that.
| | 00:56 | And particularly the documentation and the
guides and the sample code are very usual.
| | 01:00 | Of the two documents I think is
essential for every new Cocoa developer to
| | 01:04 | keep on hand the Mac Application Programming Guide
and the OS X Human Interface Guidelines.
| | 01:10 | Now, sometimes these can be a little
tough to find, but if I go into the
| | 01:14 | Developer Library section and select
the Guides, we're going to find several
| | 01:19 | hundred here. There's about 336 of them
right now, but they can be grouped by topic.
| | 01:24 | So if I click this to group them
together, I'll find first--or at least pretty
| | 01:28 | shortly--the general guides which
includes things like Concepts in Objective-C,
| | 01:33 | but also includes the Mac App
Programming Guide. This is a great single document
| | 01:38 | for detailing expected
behavior of every OS X application.
| | 01:42 | Now it's a good one to keep on hand.
| | 01:45 | These guides are provided both with HTML,
and they also typically have a PDF link
| | 01:50 | as well, if you want to download a copy.
| | 01:52 | Now you can, of course, get to this
documentation from within Xcode itself if you
| | 01:56 | have the Organizer window open. Or if it's not, you can
just get to from the Help > Documentation > API Reference.
| | 02:04 | And then in the left-hand section,
drill into the particular library for what
| | 02:08 | you're working on, whether that's OS 10.7,
or if you have OS 10.8 or even later.
| | 02:14 | Those themselves are split into the
different categories. I could jump into
| | 02:17 | the General section, and in here is where I
should find the Mac App Programming Guide.
| | 02:24 | What I can do here is right-click and
add a Bookmark, that gives me the little
| | 02:28 | bookmark section which can give me the
favorite documentation that I have at the moment.
| | 02:32 | So doing that, I am going to jump back
in and then close down General, go into
| | 02:37 | the User Experience section, and this
is where we will find the Mac OS X Human
| | 02:42 | Interface Guidelines, another really
good one to always have bookmarked.
| | 02:46 | But whether you are using the Xcode
Organizer or you're using the web site,
| | 02:50 | you'll also find a selection of Sample Code.
You can get that in the Developer
| | 02:54 | Library, there is an entire Sample Code section.
| | 02:58 | Do be aware that though there might be
hundreds of sample projects, some of them
| | 03:02 | are fairly old. In fact, the
earliest ones go back to 2003, which doesn't
| | 03:08 | necessarily mean they are all that
useful for you in the current version of
| | 03:11 | Xcode with current best practices
and the current APIs and libraries.
| | 03:16 | I tend to prefer the ones that are
from the last couple of years, so you can
| | 03:20 | either drill through them on the web site,
or you can get to them in the Xcode Organizer.
| | 03:24 | You'll find this icon tends
to represent some sample code here, so I
| | 03:30 | might find say NSAlertTest. It allows
me just to open the project, I can see
| | 03:34 | that this last revision was
in 2011, which isn't too bad.
| | 03:39 | Directly open that from within the
Organizer itself, and then I can take a
| | 03:43 | look at some of the code that Apple would provide
to illustrate certain concepts and ideas.
| | 03:50 | These won't always be exactly what
you're expecting, but they are certainly
| | 03:55 | worthwhile to take a look at.
| | 03:57 | And finally, of course, take a look
at some of our other courses here at
| | 04:01 | lynda.com on different
aspects of Apple development.
| | 04:04 | We have more coming all the time, and also let
us know if there is anything you want to see.
| | 04:08 | See you next time!
| | Collapse this transcript |
|
|