WWDC2001 Session 122

Transcript

Kind: captions
Language: en
well good afternoon okay so this is the
using cocoa Talk
my name is a loser I'm the manager of
the cocoa frameworks group okay so the
the title of the talk is a bit vague
what are we going to do today let me
just cover that quickly we are going to
cover some cocoa programming topics
which is good we are also going to be
discussing some api's and we're actually
going to write some code using those
api's we're actually also going to try
to compile and run those apps on stage
so keep your fingers crossed
and probably the overall goal is to
demonstrate that cocoa is powerful and
easy you've heard this on Monday you saw
some demos and we want to show you with
more stuff that that's indeed the case
now note that this doesn't mean that if
you're a new newcomer to cocoa that
within two weeks you've written the
world's greatest app and you're shipping
it there's still a significant learning
curve you still have to learn all of the
functionality available of the classes
and so on but again cocoa is got a
consistent set of API some nice small
number of conventions and paradigms it
uses and as you become familiar with
those names you see those you're going
to become an expert in hopefully a short
period of time and overcome that
learning curve and today we're going to
cover some of the representative topics
that you might encounter in your cocoa
programming so before I dive into api's
and and some code I want to give you a
quick overview of objective-c very quick
just so that those of you who are not
familiar with Objective C aren't lost in
the code examples we're gonna be showing
you I should also note that lot of the
examples I show you do have one-to-one
correspondence in Java it's actually
pretty straightforward to use them from
Java if you're programming in Java so
objective-c is a small superset of C and
it's ANSI C so everything you love about
NECC and everything you hate about nsec
there's probably some is present in
Objective C there is some additional
syntax and there's a few additional
types and Objective C and we'll cover
them very soon objective-c also has a
dynamic object runtime I I mean two main
things by that one it's that messages
are bound to objects that is when you
call functions or when you call methods
and Objective C the binding doesn't
happen until runtime which gives you a
lot of flexible
see secondly objects are able to ask
questions about other objects about what
messages they respond to that basically
Objective C has these facilities that
allows you to ask at one time what
messages do I respond to what messages
do you respond to you know Who am I why
am I here
etc those kinds of questions and that
dynamism actually adds a lot of power
it's responsible for a lot of the power
and flexibility of cocoa as you'll see
so just very quickly cover some of the
syntax in Objective C here's how you
define in it that this is probably the
weirdest syntax it's this is just like a
C or Java function except that the
header line looks a bit different to you
you'll see that it's set with : height :
again it's a void return and two
floating-point arguments except the name
of the method is broken up into two
pieces because you can use keywords in
front of the various parameters to
identify them more easily the rest of
the body is you know sir like C or
Objective C mixture of those two now to
use this in a method here's what the the
line looks like you use brackets to
indicate that you're making a message
send or a method call my rect is the
receiving object and they say set with :
height : with the parameters appearing
in the appropriate places now note that
when you this key words that appear in
front of parameters really allows you to
make the code a lot more readable
especially when you have multiple
arguments which all are identified by
the keywords now one other interesting
thing in Objective C is this ability to
refer to these methods as I said
Objective C is fairly dynamic and one
reason for that is this selector type
the SEL or the cell type allows you to
reference methods and then use them so
for instance the reference this method
set with height you can say at selector
and then put the method name in there
and then this variable myself can be
used in a variety of contexts for
instance you can apply to an object it's
store like a function pointer but a lot
more dynamic because depending on object
you're sending to will actually execute
a different body of code depending on
how that object is implemented this
method will see a use of this later on
to refer to object here's how you
declare it rectangle Stars says that
this object my rect is
you know instance of a rectangle or
subclass again that's the C syntax it's
a pointer to rectangle ID is the generic
term for an object which means this some
other object is actually an object of
any type so these are how you would
refer to objects referring to this
object meaning the object in the context
of a message send the receiving object
is self this is very much like this in
Java or this in C++ and finally this
feature of constant strings this is not
strictly speaking this is not a feature
of objective-c but something we've added
fairly early on the compiler using this
app quote business you can create
constant strings which are instances of
the in a string class and in a string
class is a object that's used very
heavily in Cocoa API so this allows you
to get instances of those very
efficiently because they're at compile
time okay so so much for objective-c now
hopefully now you're armed with just
enough to understand some of the stuff
we're talking about so how's today's
talk format we thought you would ask
questions and we would answer them and
just to make sure it's all clean and not
so messy we thought up the questions you
want to ask okay so let's just start
diving question number one I wrote a
small app for my school project but for
full credit I need to support undo the
app is so simple I don't know if I can
help me okay there's a great question
now typically when you think of undo you
think of a large app and if you were
here for the cocoa overview session you
heard Chuck say that undo is easy to add
to applications that are designed using
Model View controller paradigm and which
implies you know well-designed large
application not necessarily a small
application that's somewhere in
Kindergarten road so let's see how we
can do this so now the reason you can
add undo to any kind of application is
Model View controller is actually fairly
easy to achieve at least at a
superficial level and that's sometimes
enough in addition the undo is really
not all that hard so you can actually
try to squeeze into any kind of
application the main object you use to
do undo is the NS undo manager so let me
just show you a slide with the api's and
then I'll jump right into a demo and
that's undo manager is the main class
you use there's usually one perv
or one per document typically you would
have one per undo context you want a
sport so if you want to have undo that
applies to the whole application means
undo stack applies to the whole app you
would have one instance of this instead
of one per window the way you use this
is whenever the user does an undoable
action you know they type some text they
do something you register a callback in
the callback is the callback you want
invoked to undo that action the way you
register this callback is to call this
method so note that this is again those
of you on these equal objectives this is
a method with three arguments this
method you provide first of all the
callback target who's gonna be called an
S selector basically the method that
will be called there's the use of that
SEL type and finally the single argument
into which you can shove anything you
want so this is basically what you do
okay
so this is pretty much all the API I
need to show you at this point so let's
go and do a little demo
okay so for demo I'm going to be using
the dot view application those of you
who were at last year's cocoa overview
probably know that dot view application
was born there on stage then it made its
way into the examples folder on your ten
machine it also made a makes an
appearance in the cocoa learning cocoa
book by O'Reilly so this program has
gotten around and here it is again once
again for us to fiddle with okay so the
program is very simple it's got one
subclass of view let me just run it so
there this you you probably have seen
this in one of those contexts you can
make the dot larger you can click
anywhere you want you can also click on
this color well object which brings up
the standard color panel and you can
change the color so if you go look at
the Edit menu which is standard in cocoa
apps you notice that nothing is enable
you can't cut copy paste you also cannot
do undo or redo so our goal is to try to
enable those okay so let me quit this
right now so this this app only has one
object it's the dot view object it's a
subclass of nsv you as you know in this
view is the main object used for drawing
so I'm not going to go through all this
implementation there's actually only
about 25 lines of stuff here you in it
did you do like it this is the way you
use draw themselves and the interesting
methods are Mouse up this is what moves
the dot set radius which is what changes
the radius and set color which is what
changes the color
okay so first let's concentrate on
making the color undoable now let's look
at this method here it takes an ID
sender this is that a typical target
action method if you remember from
Monday or from some of the other talks
target action is how cocoa UI objects
communicate with the backend objects so
in this case whenever I fiddle with the
color well I mean the color panel the
color well ends up sending me a message
and argument here is the color well and
here I get rid of my old color dot color
is the current color and I hang on to
the new color by asking the sender what
its color is and hanging on to it and I
tell myself I need to display so that's
all nice and good but this is not really
an MVC this is not a very good MVC
method it mixes the model the view and
controller all into one so
see if we can make it a little better
now I'm tired of typing so for the rest
of this session I'm gonna use this magic
typing assistant and I might explain to
you how it works later on so now you'll
see how it works I'm just gonna go like
this and it's gonna type for me okay
okay so let's get started first I'm
gonna add this method this assistant is
really very good okay okay so I've just
added this method which is very much
like this method except instead of
taking a sender it takes an NS color and
instead of obviously asking the sender
for the color just retains that color so
this is more of a model method you know
it sets the instance variable directly
that means somebody else can call it to
set the color that's nice let's go ahead
and rewrite set color to work in terms
of set color value and that's fairly
obvious as well hopefully it's fairly
obvious that this old method is
equivalent to this and this so this
method just calls set color value with
the color right you're convinced that's
about the same thing so let's get rid of
this so the beauty of doing this is now
we have a method here which we can use
for our undo purposes okay so the first
thing I'm gonna do here is to get a hand
and create an undo manager now it turns
out that every window by default has an
undo manager so if you don't do anything
undos work within the context of a
window and that's why don't we take
advantage of that right now so I'm gonna
ask my window for its undo manager by
default it's not created it will be
created lazily and returned to you and
that's what we're taking advantage of
here and now we're going to use make use
of that code I showed earlier okay so
just to make sure you understand this
I'm telling the undo manager to register
undo a target self self being this
object selector is the set color value
selector an object is the old color so
what happens is whenever I change the
color
I tell the undo manager to call myself
with the old color if it needs to undo
this okay so
this is pretty much all that's needed
and let me show you that that's indeed
the case
I'm gonna save I'm gonna build
and run okay let's hide others okay so
the Edit menu is disabled
I can click around it's still disabled
but I can bring up a color well I can
change the color let me actually make
this bigger change the color and undo is
enabled and I can undo there you go now
notice that one more magical thing we do
is also enabled so what's happening here
is any time and undo is being done any
time we do something the undo methods
are recorded now when the user doesn't
undo that same method is called
when that methods being executed it also
registers undo so any undo that are
registered as a part of processing and
undo are recorded as redo actions for
that undo so it turns out that one line
actually is enough to do both the undo
and redo another magical thing if I
actually change this around so I'm
changing the color all the way when I
undo it doesn't go back to the
incremental color it just goes back to
the last color when I started clicking
that's because undo managers not smart
enough to know which event mode were
looking at and ignore all the events not
actually ignore them but call us all the
events that happen when we're actually
in tracking mode this helps you get rid
of methods that happen like this or when
a slider is moving and so on that's the
right thing to do and again you can
override this behavior but typically it
is the right thing to do okay so let me
quit this and next thing I'm going to
show you is let's also make the dot
moving undoable
okay so here's mouse up here we look at
the event location we convert it to the
current coordinates converted to store
in a variable called center and then we
set needs display well now you know how
to fix this we want to go ahead and add
a method that does a set Center for us
okay
okay so hopefully this is a pretty
obvious method to set the center pretty
straightforward
it also means I can now get rid of these
two lines and replace them by this so
self-set Center with that mumbo-jumbo we
had earlier so that ends up calling this
method okay so let's go ahead and make
it undoable just like the other one okay
suddenly though you notice one thing
that mechanism I showed you takes is an
object takes as an argument an object
however the set center method takes as
NS point and as points are not objects
they're structs they're passed by
structs so they're not they can't we
can't use that method we showed you
because it is really geared towards
passing objects around so what's the
solution to this well it turns out there
are two solutions
one is you can go ahead and wrap the
point or wrap any structure any C type
any data structure you want in this
magical thing called NS value and then
it becomes an object however note that
this is really not very pleasant because
suddenly have a set center method which
takes this NS value as opposed to taking
a point and that's not very natural you
really want to take a point because
that's the argument so we're gonna not
use this method and we're gonna use some
other method let me just show you the
slides for it can we go back to the
slides
so for sophisticated call backs and undo
you would use this method prepare with
invocation target suddenly you're all
going what's that mean this name doesn't
make much sense the word register
doesn't appear there so turns out this
is this quite sophisticated way of doing
this and the name will make a little
sense maybe when I explain it but
basically this call makes the undo
manager go into a state where it then
you can make a call into it and it frees
drives that call you made okay and then
you can layer on add water and execute
that call this is a great way to
basically freeze dry any call no matter
how complicated can have five arguments
it can have an argument with a huge data
structure it remembers at all and I'm
gonna show you exactly how this works so
it makes more sense the reason the word
invocation appears here is because we
use a thing called an S invocation a
class called an S invocation to
implement this and of course most of
this owes a great deal to objective-c
dynamic nature
able to do all this packaging so let me
show you how this works here's the call
you make first you call say undo manager
prepare with invocation target self
again we want this object to be called
when this happens and then we actually
make the call set center Center that's
it you make the call and it just
remembers the call instead of executing
it it wraps it up and puts it away so
I'm going to save on the build and run
come back
I want to hide others ok so again let's
make the dot bigger
that's not undoable but if I click here
click there click there bring up the
color panel change the color around
here's green click there click there I
can undo it moves undo I can redo undo
undo and as you can see the color
changes and the movement changes are all
stored in the same stack so it all works
ok ok well enough for undo let's go to
the next question how do I add a toolbar
to my application I don't see that
interface builder ah that's a good
question
toolbar as you know is a new object we
added it there recently in 10-point oh
and most people when they're doing cocoa
programming are used to just going to
interface builder and dragging their
objects off well toolbar doesn't make an
appearance in interface builder yet
because it's brand-new and we haven't
added facilities for a toolbar to
properly be archived in interface
builder and so it's not there in
addition toolbars new so it's not very
well documented either so you might be
getting confused about how to do it so
let's just show you a simple example of
how to do this now the toolbars I said
is new in Tendo and there are two
classes that implement the toolbar the
toolbar item class in the toolbar class
toolbar item is the class that
represents the individual items on the
toolbar so the various buttons you see
each one is a toolbar item the
attributes you can assign to these tool
our items include stuff like what the
images what the label is what the help
tag is what the menu is so when you
click on the menu drops you can assign
that menu in addition of course very
important when you assign a target and
an action as you know target action is
how UI elements do their thing so you're
assigned to a tooltip I'm sorry to the
toolbar item and that does its thing
note that toolbar items can also be
custom by they have a custom view which
means if you have some sophisticated
view you want to put up there not just a
button like thing you would use that
mechanism for instance the mail search
field which has a pop-up a search field
some text over it is implemented using
this you can do all sorts of crazy
things like this you can put a clock up
there a CPU meter stock ticker you can
sell ad space on
Toolbar so it's all very useful now
toolbar items each one has a unique
identifier which is an NS string this
unique identifier is used to reference
the items so it typically the toolbar
talks in terms of identifier z' not
toolbars and when i say unique here i
don't mean a globally a unique you know
credit card number like thing it's just
a string that's unique within the
context of a toolbar and we also provide
some built-in identifiers from Coco's so
you can use the standard items in your
application the toolbar is the class
that represents the whole toolbar again
it has attributes and these include
stuff like whether it's visible whether
it's customizable whether it's display
mode is and so on in toolbar also has an
identifier and this identifier is used
to one save the state of the toolbar
because remember you can customize those
toolbars and when you customize a
toolbar in app and you quit the app and
your we start if you want the same state
in addition this identifier is used to
keep the toolbar synchronized with other
toolbars so if you're in your app you
have seven document windows and you
change the toolbar on one of them you
want all the other toolbars to change
however if you have two kinds of
documents for instance in mail there's a
compose window and there's a mailbox
window you would assign two different
identifiers so that when you change the
compose windows toolbar the mailbox will
remains distinct so that's what the
identifier is used for now interesting
thing about the toolbar is it's quite a
lazy little class it relies and still
get to do most of the work so and this
is a paradigm we use another place in
cocoa for instance a table view would
ask its data source for the data and not
really store the data itself this allows
it to be lazy it doesn't store the data
it can create it later you know it's all
that's a pretty good paradigm and that's
what tool bar does given that's in the
case let's just look at the three of the
delegate methods these are important
delegate methods because these need to
be implemented so the first one is how a
toolbar finds out what items can be
placed on the toolbar now note that this
is sent to the delegate so the delegate
gets a reference to the toolbar so if
the same delegate is being used for
multiple toolbars it can make different
decisions
yeah that's so that that's always the
case of delegate methods and this
returns an array of identifiers
indicating here are all the items that
can appear in this toolbar the next
method is similar except it returns the
initial set of ein items meaning when
the user first time brings up that
toolbar what today's see and finally
there's a method to create the toolbar
item because remember all of these
methods are working in terms of
identifiers eventually somebody has to
create a toolbar item from a tool but
the item item identifier and that that's
when you call this method passing in the
toolbar the identifier and a flag
indicating whether it's being added to
the toolbar or it's being created for
some other reason and that would
determine whether the thing should be
live or not for instance so again these
are sent by the toolbar to its delegate
okay again demo but for this I'm gonna
use the TextEdit application most of you
probably know about to take that
application it is the app that ships in
the Applications folder the source is
also available on your developer CD in
the examples directory so you can take a
look at it yourself so TextEdit is not a
document it's not an NS document based
application it's a custom document based
application it was done before in this
document so it influenced its own
document functionality and it turns out
the most convenient place to create a
toolbar is right after we create the
window for a document because a toolbar
goes hand-in-hand with the window so you
basically want to create that toolbar
when you create the window and where
that happens is in the init method I'm
not gonna explain all this code here
there's a lot of code but here's the
init method which initialize the
document that also goes in and creates
the window and all that now this is not
a super great example of MVC so don't
look at text edit for MVC hints but
anyway it's it works so at the bottom of
in it we're just gonna go create our
toolbar here if we look up here a little
bit we create the window and so on so
ignore all that mess but here let's
create our toolbar okay I'm gonna open a
brace now one thing people get confused
about an objective-c is they think they
can declare variables anywhere like in
C++ well that's not the case yet because
the c standard did not allow it but it's
the season 99 and we might actually see
this an objective-c someday but for now
to create new variables in the middle of
your stream in the middle of your code
you have to open a new brace again I
could have done this at the top but that
would be messy so we have a tool bar
instance we create the instance note
that this is the class a lock in it is
what you normally use to clear create
instances so here I'm creating a toolbar
myself by hand because I can't do it in
IV so this is you know work that I
wouldn't have to do sometime in the
future hopefully and I give an
identifier again it can be anything
texted a tool bar sounds good now let's
go set a few attributes on this we make
the delegate to be self we tell it that
it allows user customization meaning the
user can change it we say that it can
save its configuration and we also tell
our window let me scroll this up we tell
our window that the tool bar I just
created is the windows tool bar okay set
toolbar when NS window has a method
called set tool bar now finally because
I gave this tool bar off to the window I
don't no longer need it so I release it
you know this is the memory management
stuff in Cocoa where you create it you
hand it off to somebody you don't need
anymore you get rid of it okay that's it
so that creates the toolbar now remember
step two here is the create to implement
those delegate methods let's find some
empty space here and let's do our
delegate methods so the first one was
allowed item identifiers here we were
supposed to return an array containing
the items the item identifiers so let's
go whole hog and do this you're going
whoa what's that these are all the items
that Coco gives you out of the box you
know the color dialog the font dialog
the print dialog the separate item etc
and the customized item so we create an
array and we return that okay next we
implement the second delegate method
default item identifiers and let me
finish implementing this here we return
an array of just one item this is the
default toolbar it doesn't matter what
it has the user will customize it
hopefully let's just put the customize
item in there okay and finally we have
to implement our third delegate method
remember
was to create the items in this case
because we were using all the built-in
items that method actually doesn't have
to do any work but it turns out it has
to be implemented so we just go ahead
and implement it okay note it's got
three arguments we implement it and we
just return nil I mean we don't do
anything in this case because this
method will never be called it just
happens to be implement it turns out
most of the time when you implement a
toolbar this method will be implemented
I'll show you that in a few seconds okay
that's it we implemented our three
delegate methods and we wrote a few
lines of code to create the toolbar
itself so let's say and let's run this
thing
okay let me hide others well and there
you go there's a toolbar and it has a
customized item and it does all the
things toolbar does appear disappear
that's good note that the content area
down here doesn't know anything about
the toolbar because that's part of the
frame now I can do the magic stuff bring
it down now I'm customizing it I can put
the colors panel I can put fonts panel
let's put this customized item away put
a flexible space okay and there we are
so that's a toolbar that I can live with
if I create a new document thank you
again creating a new document also gives
me the same toolbar because I told it
that it has an identifier and so on so
again this is interesting but you really
want to create your own toolbar items I
mean you're not going to be content with
just those items so let's just do that
one extra step and show how we would do
this to allow that in the allowed item
identifiers method we want to return a
new identifier again according this
identifier is you just pick it out of
thin air you don't have to do anything
magical let's call that fine dialog
because let's say we want to add a
button that brings up the find dialog
turns out that's one of the ones that's
not standard in cocoa so we're changing
our allowed item identifiers the default
item item fires we don't need to touch
we can add it there but we don't need to
and finally we have to change this code
here the toolbar the creation method
because now we are creating a custom
item this method will be called with
that fine dialog here so let's see how
we do that first get rid of this return
nil and type away so again we declare a
toolbar item let me put some space there
so you can see we declare our toolbar
item and we created again a lock in it
the same thing we're passing the item
identifier that we got now we're going
to set some attributes if it is equal to
define dialog because as I add more dial
more identifiers I will get called with
other ones too so I'll just make some
conditional code so if it is equal to
the find dialog I will go ahead and set
the label label the string that appears
under it I want the label to be set to
find typically we would say set label
find but that would be a non localizable
program and that wouldn't be very good
you want to sell in Japan or other
countries so why not May localizable by
calling this function which allows this
string to be localizable you can also
set the palet label that is the string
that appears in the customization window
it can be different than the string that
appears in the toolbar I'm also going to
set the target turns out to bring up a
fine panel you contact this object
called text finder this is in TextEdit
and we set the action turns out the
action to bring up the fine panel is
this thing or the front fine panel so
again we're setting action and target
typically you know when you make
connections an interface builder you're
implicitly doing this here you're seeing
how to do it by hand again because we're
diving a little deeper and I'm going to
set the image this is the image that
appears on the toolbar now to set the
image I asked an S image for an image
and now I just said that to be my image
now here I put a question mark because I
don't have an image yet let me go ahead
and find an image by going to finder go
into my documents directory I'll choose
one of these images this one okay it
turns out this is a picture of my cat
turns out the reason for that is because
my cats always finding things under the
couch behind the refrigerator
inappropriate things but he's a good
finder so let's just use the cat so to
use that image and this is pretty
typical whenever you want to use an
image in your application and you want
to make it part of your applications
resources you drag the image into
project builder under resources project
builder asks me what to do with it one
of the important things you might want
to do is copy it into your sources and
add it to my target so now that the cat
is part of my resources along with all
these other resources down here I can
actually use this call and s image image
named put the word cat here so that
method image named will find any image
out of your applications resource
package if it's the correct we localized
I'll find a localized version so instead
of having you know an Egyptian cat you
want to have a Norwegian cat that's okay
so you can do that then we didn't
localize it here but that's what you get
that yeah okay and then we finished this
because we're done and we return the
item okay and turns out that's all we
need to do now you might be asking
what's this order release business again
that's got to do with Coco's
memory management because we created the
item and because we're returning an item
that the clients gonna take ownership of
we auto release it which means release
it later it's sort of like smart garbage
collection and you will see this a lot
and it's standard particle programming
up not gonna go into it anymore so
that's it and note that if you had other
items you'd basically write code like
this or someday maybe use interface
folder and not have to do this at all so
I'm gonna save I'm gonna run
okay hide others okay there note that
when we ran it it remember the old
toolbar so that seems to be working
bring down customize there is the fine
dialogue there's the cat let's say done
and let's see if the cat can find things
there's the fine panel so there you go
okay
so you know we could play with the
toolbar all day long but that's okay
let's go back to our next question
question how can I get a better
framerate out of my animating game oh
it's a performance question that's great
and you've been hearing that performance
all along so let's see how whether we
can do this Oh demo again okay okay
let's see about this animating game now
let's see what what it does what it
looks like conveniently it's on our dock
oh it's a worm game okay so this games
been around for a while I think since
the 60s and it even makes appearance on
your cell phones you know you probably
have seen this game let's run it just to
show you what it's about I'm gonna start
there you go
now typically this worm game doesn't run
this fast in fact I can make it run
slower by clicking on here there you go
what you do is you make the worm go eat
the target oh yeah
and when he eats it he grows by one dot
so as he gets longer and longer he
becomes harder to manage it and
eventually it hits itself and dies and
obviously the more you eat the more you
get
and typically the worm when it hits the
edges would die but we simplify the game
here for demo purposes because I don't
want spend too much time playing the
game so this slider here allows us to
change the framerate and I'm setting the
framerate to a really high number and
you can see I'm getting 38 frames a
second okay that seems good enough for
this game well I mean you know this
person is quite worried about
performance but it's actually good to be
worried about performance even if your
framerate is good
trying to speed it up means that there's
more processor power in the machine for
other things and you can be doing other
things in the back so let's see whether
we can help this person out now one
thing you'll notice here is that this
whole area seems to be white and we
don't see any of the window background
typically when you subclass a view
you either draw everything in your
bounds or you draw less than everything
now if you draw everything one thing you
can do is tell the view subsystem that
you really don't want anything behind
you to be drawn whenever you're being
drawn and the way to do that is to
implement one method in view now
whenever you're doing a drawing a
subclass of view a drawing application
this is the first thing you should look
for and that's to implement this method
called is opaque to tell the system that
your opaque that's the first thing we're
going to do let's see if that will help
us now we go to our subclass of view in
this case room view and it's some fairly
involved overview class there's also a
controller class to control the UI and
the worm guts which controls the logic
of the game let me close this up so this
is again a standard view you know in it
with frame there's a dialog there's a
method to set the string and get the
string oh yeah if you notice the worms
body was made up of a string that seems
odd but you know there's a reason for
that later in the demo there's a method
that performs each frame of the
animation and finally there is the draw
rect method draw rect again is the
method you override to do drawing now if
we bring up our fine panel and search
for is opaque we see that it's not
implemented
so let's first thing we should do is go
implement that okay it's implemented
just like this is flipped method it's so
easy I don't need my typing assistant is
opaque so we implemented and we returned
yes because the default implementation
returns no and this basically says that
when this view is being drawn don't
worry about drawing anything that's
behind it because this view will take
care of every pixel within its bounds so
let's run this little puppy well look at
that 44 frames a second so just that one
little line got us you know up from 37
to 43 42 so that's that's pretty good
but you know I have a feeling this is
not gonna be enough let's hide the
project builder so next thing you might
want to do is run quartz debug which you
saw earlier in the week I hope quartz
debug shows you which areas are being
drawn let's kick it on okay so again
obvious you know this might have been a
rigged demo but it's obvious that the
worm is drawing the whole view every
time
okay the yellow area shows the area
that's being updated well you really
want to worm to only to draw the area
that's being updated so that's next
optimization we can do so let's quit the
worm let's hide quartz debug and let's
go back to our worm application okay now
there are two pieces to drawing less
than your whole view one is to make sure
that when you tell the view it needs to
be updated you tell it what region or
what rectangle needs to be updated and
the second thing is in your drawing
method pay attention to that rectangle
so we'll do both of these right now so
the first one happens here in the
perform animation method we say self set
needs display yes that just says I'm
dirty we draw me and it gets drawn later
on whenever appropriate so instead of
doing that we have to compute a smaller
a tighter rect and let's see how we
might do that now some of the stuff here
has to do with the worms logic but
basically what wanna do let me push
these lines down a bit I want to start
with I wrecked and I'm gonna remember
the old target position and I wanna for
the length of the worm I want to look at
every position every body position of
the worm I'm gonna figure out what the
rectangle is I want a union into my
rectangle so as a result of this
operation I end up getting a rectangle
which tightly covers the worm okay so
again you know that little method there
returns the worms body and so on so this
allows us to create the tight body
around the worm okay then we update the
gamestate meaning we move the worm now
it turns out we know that the worm only
moves one block per frame so after the
game has updated the frame we can go
ahead and Union the new head position
okay
again the worms head moves so we also
want to bring that rectangle into the
whole rectangle so our rectangle grows
of it there's one more thing we need to
do to compute the tight rectangle and
that is to see if the target changed
position meaning if the worm ate the
target it moved so let's also Union that
end if the old position is not equal to
the new position we go ahead and union
in the target position okay so I hope
this makes sense now we have a rect that
includes the target in the worm
it only includes a target if the target
moved which is rare enough so that
that's okay
and the final thing we have to do is
instead of Sidney's display we call sit
needs display in rect and pass that rect
so now that tells the view machinery
just draw the smaller rect
so what's safe the next thing we want to
do is modify our draw rect know that
note that draw rect is taking a rect
argument but nowhere in here it's really
being paid attention to again sloppy
programming first thing you want to do
is this is the background drawing and we
do a rect fill of the whole balanced
self bounds means my whole bounds here
itself is the view so instead of self
bounds we really want to pass in correct
okay so that's straightforward we just
draw a smaller rect the next thing I
want to do is note that here we take we
run the length of the worm take the
rectangle and we draw the character the
substring that makes up that part of the
worms body and we do it character by
character so instead of doing it all the
time
unconditionally let's do it if they're
rect intersects the rectangle that was
passed it okay does that make sense
again we only draw it if the worm is in
that region again pretty straightforward
this will intersect the two records and
return to you yes or no finally the same
thing with the target if the target rect
happens to be in that wreck we passed in
we'll just go ahead
we'll only do it if the target rect is
also in that box okay so I'm gonna save
I'm gonna run
okay here's the moment of truth okay so
there's 85 I think that's fast enough do
you think so you agree okay good so
there you go we've now made the game
quite unplayable but it's also very fast
so I think I think this this person
should be pretty satisfied with this
performance okay so let's go let's go
back to the slides please okay so what
we learned from here is that you want to
draw as little as possible one thing
that means is you should fine-tune the
drawing area the update area and you
should also pay attention to that you
should also use is opaque to prevent
super views from drawing needles see
those are probably two most obvious
things you can do to speed up drawing
and also use quartz drawing to see
what's drawing sometimes you might find
something very surprising like some text
field is being updated every so often
and you don't even know about it
or as Robert Schroder on Monday even
when paused his application the kissflow
kept on drawing now there are things
like that that courts the debug will
tell you next question hmm but still not
good enough for my boss can I make it
draw even faster
okay so that's interesting we'll see if
we can make it draw a little faster I
think the thing to do at this point is
to see whether we can see what the
problem is so let's go back to a demo
again and will now use another
performance tool quickly let's run it
and let's launch sampler again I think
you heard enough about sampler I'm not
gonna go into details with sampler you
can attach to a running program I'm
gonna do that and I'm gonna choose worm
and I'm gonna say okay is you've seen
sampler so I'm not talking too much
about it but what its gonna do is it's
gonna sample the target app every so
often every 20 milliseconds and capture
the stack and that's gonna give us an
idea where the application is spending
its time so let's put this down here
let's say start there you go let's say
start sampling being sort of paced back
and forth a bit get some coffee its
sampling the worm and you can say stop
okay and let's stop the worm here okay
so this is now the biggest stack now you
can actually go down this tree here and
look at all the things that are
happening but this turns out to be the
biggest stack let's go back and if you'd
look down here its main its application
run these are the standard objective-c
things I'm savanna cocoa things which
are powers of frameworks and here the
worm timer callback this is your code
and here we're displaying the view and
it turns out the biggest thing we're
doing and displaying and you would
expect the displaying to be taking the
longest time the question is what is the
displaying so slow turns out the biggest
thing here is nsstring string drawing
draw in rect so the most time in fact of
all the drawing that's happening 90
something percent of the time is spent
in drawing that string okay so maybe
that's something we can look at okay so
let's go take a look at that slide
squeeze
okay to do to draw strings to draw short
little strings here and there you would
use this API NS string draw interact
with attributes its the rectangle and
attributes include stuff like the font
the color you know everything else a
style text would need to know this math
is very convenient and you should use it
if you need to draw strings here and
there but it does do a lot of work on
their covers one of the things you need
to do when you're drawing true Unicode
text is that you need to you need to
take the unicode string you need to
convert it into what's called glyphs and
then you need to lay those grooves out
and you need to send them to the screen
so it's not just a simple matter of
taking the Unicode characters out of the
string and blasting to the screen the
reason for this is Unicode text is
fairly complicated and you basically
need to convert those unicode's into
elements in the font which are called
glyphs and sometimes like a three
character unicode string might
correspond to five glyphs or it might
correspond to one glyph because there
might be a special glyph some languages
are actually even more complicated so
that's why the text layout machinery is
actually does a lot of work in addition
there's a lot of work that needs to set
up just to start that operation and end
it so the string drawing is convenient
but because it's called with no context
it does a lot of work repeatedly so here
we can try using the text system for
some performance gain and to do that
let's look at the tech system
architecture rather quickly some of you
might have seen this before the cocoa
text system is a network of objects
typically when you're using it an
interface builder you're making you're
copying that you're taking an instance
of NS text you drop it into your
application and it creates everything
else for you and then you're fiddling
with that but these other objects are
also available for it to use directly
oops text storage is the model object it
stores the characters and their
attributes layout manager computes and
stores the glyphs in their locations so
the layout manager sir like the
controller in this picture text
container provides text area information
so in fact in the spec
you can imagine a layout manager with
multiple text containers if you are
doing a multi-column text editing
application for instance in the text
view the final piece the piece you see
in interface builder the divisible piece
is the piece that handles a display and
editing now note that again
this allows us to do fairly
sophisticated things for so you can have
one text storage you can have three
layout managers what this means is you
can have a same text document but it has
three different views on it so one could
be you know a wide view one could be a
short view one could be a view without
fonts and so on similarly multiple text
containers as I said allow you to have
multiple pages multiple columns so on so
turns out that here the interesting
piece when they use is the layout
manager it gets the text contents from
text storage as I said it converts these
characters into glyphs and it computes
the glyph locations and what we really
want in this case is we only use the
glyphs in the Gulf locations and we
don't want this real eye out to happen
over and over and then finally you would
get at layout managers to draw these
glyphs by calling this method draw
glyphs for glyph range and that's
usually called by the textview layer so
let's see how we can make use of layout
manager in our application first thing
we want to do let's get rid of this is
we want to go into our room view the dot
H which is our at the header file which
declares the object and want to create
three when I declare three new instance
variables text storage layout manager
and text container so those are the
three objects we talked about so instead
of using text view we don't need text
view we're just gonna use those three
level lock three objects at the bottom
so we create them let's save our header
file and let's switch back now in the
init method where we create various
stuff we now want to go ahead and create
those three objects and it turns out
it's fairly easy to create them text
storage a lock in it layout manager a
lock in it text container a lock in it
we don't want to provide any
sophisticated at you know attributes you
can do that you can provide size as you
can provide various other properties we
don't need to deal with us right now and
then we want to add to the layout
manager the text container and add to
the storage delay our manager again the
API says
and not set because you can have
multiple layout managers you can have
multiple containers okay so this is all
at me all we need to create a subset of
the text system again note that when you
create a text view programmatically or
through interface builder all this is
done for you magically because that is
really the you know the most common use
of the text system okay now because we
created those three objects we should
remember to release them so whenever
object goes away we release the three
things we created that's fairly
straightforward now comes the tricky
part
set string is where a new string is
provided for the worm note that this
happens very rarely because the string
is not really changing okay so what one
to do is whenever we need get a new
string in addition to remembering that
string we actually want to pour it into
this text system that mini text object
we created and to do that I would tell
the worm storage object that its string
is the new erm string that I have in
addition I would tell the worm storage
what the attributes are now this worm
text attributes comes from up here and
again I said it's the style information
in this case it just stores the fact
that the font is loosely round of 16 I'm
not going to go into that so anytime a
new string comes in we reinitialize our
text system with the new string and the
new attributes that's it that's all we
need to do there okay so that takes care
of that piece and finally in the drawing
instead of doing this string drawing rec
which we know is not fast enough we want
to use a layout manager to draw okay so
instead of doing this character stuff
let's open up some space here let's push
this to the top I'm gonna work in terms
of glyphs I'm gonna ask the glyph
location and I'm gonna do draw and
glyphs not ignore this code here you
know I can explain it but it's really
pretty straightforward what's happening
here is instead of drawing the character
instead of drawing each character one by
one as we would do down here we're now
drawing each glyph one by one and pour
that we're going to the layout manager
and I can get rid of this code so the
old code and the new code are very
similar it's just that one is a slightly
lower level talk talking to the layout
manager and turns out this is all we
really need to do and again I'm saying
all we need to need to do but this is
actually fairly sophisticated stuff
because you have to dig down you know
in there into the text system and it
could get messy but let's see if it
gives us the performance we want
let's build and run
okay oh look at that
so I think that's good enough for this
person right now okay at this point I'm
getting really sick of the worm
hey that's sweet
okay add some pizzazz to the app oh and
we're shipping this afternoon so
something quick please oh I see it's
still a worm question okay so we need to
add disaster this app and we need to do
quickly okay so well what can we do the
app looks pretty boring let's go back to
it quickly there's this big white area
that's quite boring right so we can add
some color to it now if we go back to
our draw rect which is here one thing
you notice is that we do an S color
white color set that makes the
background white well obviously we can
add pizzazz and then very quickly by
making this red or yellow or anything
you want but that wouldn't be enough
pizzazz I don't think for this person so
let's do something fancier instead of
color but we might want to use an image
or a pattern one good place to find
images or pad well there's a cat but
other than that if you go into the
desktop pictures folder on your disc
there's a bunch of nice pictures here's
one there's another one so on now one
that I like that will work probably in
this case is one of these ripple
patterns now I know if you can see it
there it's a nice little pattern with a
little thing and so instead of using an
image let's use a pattern and let's see
how how easy or hard that is now as I
showed earlier we want to drag this
image into our let's get this back we
want to drag this into our application
like we did earlier let's copy it in
those resources we want to copy it we're
gonna say add so now again this image
ripples Maus dot jpg is part of my
application now okay and now let's go
ahead and use it turns out to use a
pattern where you can use NS colors so
therefore this logic here of setting a
color and drawing with it doesn't really
need to change very much let's go back
to our view and let's add an instance
very
for the color okay
so now we have an additional instance
variable on top of everything else we
did called color now back in our view
implementation where we create all this
other stuff let's go ahead and create
that color and that requires one
somewhat long line but there it is what
we're doing here is like we did before
we do in the image named ripples mas
which takes that image that corresponds
to that thing and when we call make this
call to NS color saying color with
pattern image that says create a color
using this image as the pattern and then
we retain it because we're gonna hold on
to it and that becomes this new color
instance variable we created now again
being a good citizen you wanna release
that when you go away and finally down
in our draw rect instead of this red
color which wasn't too creative
we'll use color okay let me save
ah look at that and if we let's also set
the speed down to something nice and
let's run actually you can set the speed
to something high and you see that the
frame rate actually isn't really
suffering because of this maybe just a
bit but it's the whole pattern and note
that this is a pattern and it's being
drawn continuously so if I make the
window larger you actually see the
pattern again working there so just by
using an image for the pattern just with
one extra line of code you're able to
use patterns and sort of colors in your
application so that's fairly
straightforward Killick okay let me say
some words about NS color in s color
therefore it not only represents colors
but represents meta colors catalog
colors patterns etc and to paint with
any one of those you just do NS color
set and here are some of the interesting
methods we just show color we just shows
saw color with pattern image another one
which we saw is white color that just
gives you the white color you have red
color orange color blue color whatever
you can create a color with your own RGB
values obviously that's color with
calibrated red so on RGB alpha that's
what you're used to and finally we have
meta colors like window background color
this is the color that presents the
background color of a window and turns
out that actually returns to you the
Aqua pattern if you need to use it so
again a patter use of pattern in colors
okay question let's see how much more
time we have for questions so how does
the magic typing assistants work go
ahead you ask okay the answer is
services okay and some of you might have
guessed that if you are seeing a little
mini flash services allow applications
to provide their functionality to other
applications in this magic code we were
using is actually a modified version of
the TextEdit application all we did is
we implement this service where every
time you invoke it it takes the next
line from the currently open document
and texted it and paste it into the
current location I'm at now I'm not
going to go into detail and services
here because the next talk actually has
a little more technical discussion of
services so I'm going to leave it there
but let me just show you what I mean
here by this low feature
okay I'm gonna quit the worm so here we
are in project builder again if I click
here in text if I go to the services
menu you'll see that there's the
standard services you're used to seeing
and then there's this text edit + item
which is the app I wrote the modified
version of text edit in addition to the
standard text set items there's a get
next line move down the line and move up
a line and it's been assigned key
equivalents again through services
that's fairly easy to do so every time I
go ahead and invoke this service get
next line it gets me the next line see
that's the line I was supposed to type
but I did by hand
again I can do it and you can I can move
up by hitting that thing and it does the
same line again and again you know you
can get very fast and you can see that
you can do anything you want and some
services work by actually taking the
current text selection and working on
than returning a new thing and so on and
again I'll leave a discussion off to the
next talk okay
slides please okay so let's talk about
what we did today I think we're pretty
much out of time we added undo to an
unsuspecting app we added a customizable
toolbar to texted it we made a game draw
much much faster that was like 8x that's
pretty good and we also learned how to
use patterns to spiff you up any app and
we saw how useful services can be so
again a bunch of topics and a
representative set of topics that apply
to actually a lot of applications so
what we really saw is you know how to
enhance apps with just a few lines of
code and again use your visible way and
did you know you can apply this to any
application and you also saw how to do
fairly sophisticated things with a
little bit more of code I mean that ten
lines of code you saw where we're using
the text system and deaf that's actually
code you wouldn't normally use but again
just by diving in a bit learning a few
more classes and again you know there's
a learning curve but learning those few
classes you're able to do a lot more
than you can and again those text system
objects for instance can be plugged in
and very creative ways to create fairly
interesting text editors not just texted
it we have a saying in Cocoa where we've
been you know saying this for many years
and I think it's full true we like to
make simple things simple and complex
things possible so again just with a few
lines of code you can come on stage and
make a demo but by writing bunch more
code you can actually feel
magical things that allows you to create
a fairly large very you know
full-featured application okay as far as
a roadmap for other talks now if you
miss these first two talks I think they
would be very useful if you're new to
cocoa and this is the first cocoa talk
you went to I would definitely recommend
seeing at least those two and maybe some
of the project builder talks on on video
there they're quite handy interface
builders very we don't see interface
builder today but it's very integral to
cocoa development and the cocoa overview
gives you a good overview of the things
cocoa provides advanced cocoa topics is
right after this one and that's going to
be somewhat more substantial talked in
this where we're gonna go into some of
the advanced features in cocoa file
wrapper etc drag-and-drop printing you
know how to dive into those features are
cool performance tools if you're more
interested in learning more about
sampler etc is also at the same time or
you can catch that one on video it's in
room a2 and finally we have a feedback
forum if you can't get your question
answer today or you have something to
say it's tomorrow afternoon at 5:00 and
Heather Hickman the art is our
technology manager and the cocoa
feedback and the cocoa development
mailing lists are available for your use
you