WWDC2004 Session 411

Transcript

Kind: captions
Language: en
good afternoon everybody welcome to
session 4 11 cocoa tips and tricks so
let's just jump right in
I can get this worked there you go okay
so today we're going to be showing you
well they say we're going to have a
bunch of Engineers from the cocoa
frameworks team up on stage answering
the sort of questions you might have and
showing you how to put some cool
features and some useful things into
your applications we're going to show
lots of source and lots of demos and
just like everything else at the
conference it's going to be available
for download download on the ADC website
all of the sakoda that you see today
okay last year we showed you lots of
cool features lots of useful things I
hope we had a lot of fun and this year
we've got even more things to show you
and you can see there's a lot so let's
just jump right in my name is Chuck
vassula I'm an engineer on the cocoa
frameworks team and let's take a look at
the first question I have a table view
and it doesn't know how to start though
I'd like to add sorting can you tell me
how hard that is well it turns out it's
really pretty easy to do and what we
need to do is two things we need to
define which table columns are sortable
how those table columns are sortable and
then we need to provide the code that
actually does sorting but at a table
view is going to take care of everything
else for us it's going to handle the UI
handle clicks and in fact it's going to
tell us when we need to sort now if you
want to be you know even lazier nut and
doing less glue code and less work you
can just switch the bindings and this
would all just work okay so how do we do
our first job which is defining the sort
ability of cable columns well what we
need to do is provide a sort descriptor
prototype for each column that we want
to be sortable and in the search
scripter prototype we're going to
provide three bits of information we're
going to say what the key is that we're
sorting on what the initial sorting
Direction is and what the selector is to
use when comparing two objects during
the sort now like many other things we
can also set this an interface builder
by inspecting the table column and
setting the three attributes okay so our
second job is to actually do the sorting
as I said table view is kind enough to
tell us when we need to update our sort
ordering it's going to send us the table
view colon short
scriptures did change colon and the
second parameter is going to be the old
list of sort descriptors in case we know
that we can do something more efficient
by being given the old sort scriptures
if we want the current sort descriptors
we just turn around the table view and
ask it for the sort descriptors now for
some reason if you want to manage all
the sorting yourself table you provide a
routine to set the current list of sort
descriptors and another interesting note
is that the sort descriptors are
persisted along with other information
about table columns that are persisted
so across reload a clock using across
running of your application table do
remember what the last or targeting was
that the user using okay so now that we
know when to sort we need to do the
sorting and we're going to use some
conveniences provided by NS array and
its array knows how to take an array of
sort descriptors which again we get from
the table view and knows how to sort
using the information in the sort
descriptors one of the things is the key
which is going to do the sorting out and
finally you'll see at the bottom an
example of how we might sort an array of
things using a sort descriptor we're
going to sort things in this array based
on the first name value of each object
okay before we go into this demo I
wanted to do just a quick overview of
what we're going to be looking at since
what we're really going to be doing is
an extending is extending an example
that exists on the system already that
example lives in developer examples apt
it's called drag and drop outline view
and what it does is display some
hierarchical data and the data that it's
managing is sort of a simple tree
structure with nodes and each node has a
pointer to some data so at this point I
believe I want to go to the demos
okay let's take a look at the
application running and see what we're
going to get in the end okay what you'd
expect i click on a table column of
sorts this actually in the existing demo
it already knows how to sort based on
the name column and in a second we'll
see that it really was a hack and we're
going to do it a better way and we're
going to do it in a completely generic
way now we're able to sort on each
column okay so let's first take a look
at our first job which is to set the
sort ability of the table column we did
this in interface builder and the first
column is going to sort each object
based on its name key and it's going to
use compare colon to do its comparison
and it's going to sort its initial
direction as offending and we could have
actually left compare colon off because
that's the default if you specified null
or nothing and then we'll see that we
specified some values for the other
columns the key will be is expandable to
the second column and is a group for the
last column okay for this example
actually i'm going to show you the code
a little bit of a different way than
you've probably seen into all of the
sessions i'm actually going to bring up
file merge since as i said this is a
demo on the system what i want to show
you is what we've added to it so it
lives in the original lives in developer
examples app kit drag and drop outline
view and we're going to compare it to
this
set of code okay and let's see what
we've added so change the app
application controller which is the data
source of the outline view and there's
one difference we've added the sort
descriptors did change colon delegate
method and what we're going to do is
tell her our data to sort our tree data
we're going to add a sort using
descriptors method and then since we
probably change the order of things
we're going to tell the tale of you to
reload the data and display it in its
new order so let's take a look at simple
tree node next which is a subclass of
tree node and really all i want to show
you here is that we removed our hack
from before we used to sort things by
forcing it to compare using the name key
okay so that before we're sorting only
in that column and it really was a hack
it wasn't a good way to do things so
let's do things a little cleaner more
appropriate we're actually going to make
it very generic we're going to put the
sorting ability in our base class we've
added a sort using descriptors routine
to the tree node and take a look at the
implementation so first we go and we
tell our node children which is is an
array we tell it to sort itself to
reorder itself based on the sort
descriptors and then we recurse and
finally since we want to sort on keys in
the data and we have a pointer to our
data but we don't actually respond to
all the methods in the data we're going
to do a little trick and we're going to
override value for undefined key so when
we're trying to compare based on a key
in the node which it doesn't respond to
like the nodes don't respond to name
it's going to go off to the data object
and ask it for the value for name and so
by doing this we're going to be able to
sort based on keys in the data object
and using those you know a small set of
changes not many changes there were able
to get sorting
in our table view or our outline view in
this case okay so if we could go back to
slides please okay well that's great but
you know your parents out there just
going sorting is not boring I'm never
going to sort anything no fun we make it
a little more fun so could I add
something like animation to the sorting
so it's a little more Lizzie a little
more fun to do a little bit more you
know Mac os10 kind of sliding around fun
style and certainly we can do that what
we're going to do is make a subclass
identify outline view the notes how it
knows how to do all of this and what
it's going to need to do is first take a
snapshot of the location of all the
items in the outline view before you do
the reload and that's so that we can map
index items from their old location to
their new location so then the animation
we're going to slide things from the old
place to the new place so before we load
will make a snapshot and after the data
sorted by the data source what we're
going to do is reload in a way such that
we create an index mapping which shows
where things went from and to and then
we're going to do some custom drawing
because well we're not drawing things at
fixed locations and finally we're going
to use NS animation to help us manage
our timer and get the nice smooth curve
values so we get a nice you know fun
smooth animation ok so as I said we're
going to make a subclass it's going to
be called animating outline view and
first we're going to add a method to it
called well I like long lesson names for
those you who know me it's called
prepare for reload movement animation
and this method is supposed to be called
by the data source before it reads the
data and this is a chance for the
animating outline view to take a
snapshot to take the snapshot location
of where things currently live then
after it sorts of data is going to call
a new method that is on the bottom
called reloaddata with movement
animation and this is basically a new
kind of reload that we're going to make
which knows how to make the index
mapping start up a timer which
and is going to control and run our
animation and of course it's also going
to reload the data okay as I said we
don't draw rose that fixed locations
anymore and we're going to override draw
row in clip wreck and what we're going
to do is over time smoothly animate the
rows at new locations and we're actually
going to use a nice little trick by
drawing these rows instead of into the
table you're going to draw the rows into
an image and then we're going to blit
the images onto screen because we're
going to be doing this lots and lots and
lots of times very rapidly this means we
only have to draw the roll one time and
after that we can always use these
images that we've cached away and we can
get better performance okay so we're not
drawing rose into a table view we're
going to do a little trick and we're
going to draw rose into an image so to
do this we're going to create an image
we're going to lock focus on it and then
we're going to call tell-tale view go
ahead and draw Rose like you normally
did but se rule 3 where does it draw it
probably draws it a coordinate of like
and why of 51 and our image we don't
want to make every single image for
every single rose big is the table we
just want to make it the height of a row
so what we're going to do is trick the
table view into drawing everything
during animation at a y-coordinate of 20
and by doing this we're going to be able
to draw into the it into the image and
later on we're going to use it we're
just going to blitz screen over and over
and over okay so if we can go to the
demo machine please now just so we see
what we're going to get let's take a
look at this one again before we start
and well we've got sort it's not very
fun yet let's cook the fun button and
let's make some more data so it's a
little more interesting
and we've got some nice fun little
animation going on all right so let's
take a look at the code for this
first thing on a do take a look at is
the not that class is the animating
outline view our new class it's a
subclass of NS outline view it has some
instance variables that help it manage
the animation now this this example is a
little more complex has a little bit
more code than some of the other demos
so I'm going to kind of breeze through
it because you can get to look at it on
your own and for the most part this is
all some little lots of little details
that need to be taken care of it's
nothing too difficult and we've added an
interface that our data source gets to
use okay let's take a look at the actual
code and jump down to prepare for reload
animation and only if animation is
enabled we're going to do a couple
things first if we're animating before
we happen to have some of the old stuff
lying around we're going to throw it out
start over and what we're going to do is
sorry I guess want to jump down here
we're going to create a dictionary which
we're going to keep it as an instance
variable it's something that's going to
be used by the next reload and it's
going to be the snapshot of the current
order of all the items now if you have a
very very very large outline view you
can imagine this performance might not
be great so I'm going to leave it as an
exercise up to you guys to figure out
more efficient way to do that kind of a
trick and we mark some other information
which is the current row selection so we
can fix it up later okay so jumping
ahead we have our reload data with
movement animation and as I said it's a
new kind of reload data it's going to do
reloaddata and a couple of other things
the first thing we want to do is compute
our index mapping I'll let you guys take
a look at how that's done offline if
we're currently animating we finished
the current animation we just bail and
start over
and then once we have an index mapping
first we want to fix up the selection
because things have moved to new
locations so we're going to select the
curt make sure the selection match event
we're done with the data that we marked
before so let's free it clear it out and
finally jump ahead a little bit we
retain our index mapping so that we can
use it throughout the animation then we
create a progress animation I'll go to
that code in just a little bit that's a
subclass of NS animation and what it
basically will do is help us manage the
timer and it's going to help us get the
nice smooth curve value so that we don't
have to know what function generates the
nice smooth ramping and curve values and
we're going to get those smooth values
by specifying and its animation
ease-in-out so it's going to ramp up and
wrap down nicely we're going to use a
non blocking mode we're going to create
a place that we can store the images
that we're going to use to draw during
the animation and then we start the
animation and it turns out that our our
subclass of NS animation is going to
tell us whenever we need to update and
it's going to tell us by sending us this
message progress animation current
progress did change and when we get this
while we're either at a point where
we're done with the animation so we'll
finish it or we're full will force a
redisplay and when we redisplay i'm
going to jump ahead a little we
eventually end up getting into draw row
and again what draw row is going to do
is draw using an image so first thing
it's going to do is figure out well
where do I need to draw it's going to
get the nice smooth curve values a
little bit of math in this this routine
that I have and it's going to figure out
where the row should be at this point
then we're going to find out well if
it's not actually on screen let's just
bail we don't want to draw if we haven't
generated an image cache yet let's
generate an image by the code I showed
you in the slides we're going to create
a name
edge draw into it and then cash it away
and finally we're going to just split
the image onto the screen and again you
hear you see in wrecked of Roe here's
our trick to get the drawing to draw at
a y origin of zero and the rest of the
code I'm going to let you guys take a
look at online these are just our help
routines compute the index mapping
figure out where we want to draw things
and so on now let's take quick look at
our animation subclass to subclass of
ennis animation we add a new and knit
method because we want to be able to
specify something special which it
doesn't normally have and that's a
delegate and the delegate is the one
that's going to get this message
whenever the animation updates now if we
take a look at the code for this it's
really simple we have a cover for a net
statue of the delegate and basically all
it does so whenever the progress changes
it tells the delegate that it needs to
update the animation and that's it and
it's nice because this class picture of
all the little dirty details of managing
a timer creating it getting its fire and
it hides the details of how it computes
the ease and ease out values and things
like that alright and again once we have
all that we've got our nice smooth
animation
and you'll see when you look at the code
there's some other neat little tricks in
there like we we try and make sure that
we never you know if the table we had
10,000 things you don't want to animate
something from 10,000 rows away you sort
of want to clamp it to two times the
visible height so that it's never too
far away from visible so if you man away
from really far away it wouldn't be on
screen very long drink animation so
there's some neat little tricks and I
like that that I'll let you guys take a
look at offline all right if we go back
to the slides please okay well we've got
some really cool fun animations but you
know I'm sure this never happened anyone
out there but the last minute we're bout
ready to ship and H is they've changed
their mind they want something they want
to be in table view now not in an
outline view so what are you going to do
you're going to change everything to be
a table view and you can change the data
sources to use different data source AP
is well here's a little trick what we're
going to do is make an assault line view
display looking more like a table view
we're going to trick NS outline view to
draw like a flat list and one advance to
this is that you only have to deal with
one delegate and data source you don't
have to change anything in your nib and
for those of you who want a unique
identifier outlined views require unique
identifiers per item per row but of
course for some people that's a drawback
so those are things you'll have to think
about if you want to try this trick okay
so we're going to trick NS outline view
and what we're going to do is tell it
set your indentation level to something
like 0 don't draw with a big indent
because that's one difference between
outline view in table view and if it
turns out that for some reason you're
drawing a flat list but you have some
hierarchical data well it would try and
draw those turn down indicators and we
don't want to draw those what we're
going to do is over ID will display
outline cell delegate message and when
we get that we're going to effectively
force the outline felt to be hidden and
that's what you see down at the bottom
if we could go back to the demo machine
please I got a little overzealous and
close things behind myself
bring it up again now I'm actually not
going to show the code for this because
you just saw all of it on the slides
other than some little helper things
I've added and you'll see if you compare
this to what already exists on the
system for dragons are following views
you compare it I've added the ability to
change the data file that's being
displayed and what it's going to do if
it detects that there's no hierarchical
data it's going to switch to using a
flat list type display using the code
that you saw on the slide and so all we
do I know data file one happens to be a
flat list i click that and it looks more
like a table view and I didn't have to
change anything in my nib and I didn't
have to add any more code than what you
just saw on the slide okay so if we go
back to the slide please slide please
thank you okay at this point I'd like to
invite up on stage another one the cocoa
frameworks engineers Tina Wong Tina
[Applause]
thank you very much Chuck once again my
name is Tina pong and I work with Chuck
on the app case so have you ever noticed
that applications such as Xcode provide
easy access to commonly used functions
such as opening a file or creating a new
project and they do this by having a
menu in the dock well how can you add a
dog menu to your application well the
very easy way and basically no code
method is at an ID to do this the drag
menu out into your nib file and connect
it to your applications doc menu outlet
but there are times where in your dock
menu you want the contents to very
dynamically depending on the current
state of your application and so to do
this you have to actually create the
dock menu in code and all you have to do
is implement in your application
delegate the application doc menu method
and have that return your doc menus so
to illustrate this I have a quick demo
for you if I can go to demo to please so
we're going to take a look at this first
notice that when I well first of all I
like to imagine that dot view is another
application that you can get in your
application developer applicate examples
and if you went to the cocoa
introduction talk i think all we showed
you basically how you can create stop
you but here we have in the doc menu red
blue and green so we basically are
allowing you to change the color of the
dot in the menu however to illustrate a
dynamic menu is kind of seemed silly to
have read in your menu when your dog is
currently Reds than just meaningless so
we're going to change it so that if the
dot is one of the current colors then
take it out of the menu so say I select
blue and now that's how the menu but if
I were to change the color to something
like maroon now I have all three options
available so to take a look at the code
and real quickly i'm going to change the
indentation here so it looks a little
better okay so taking a look at the code
we've implemented the application doc
menu method the first thing we do is we
create a new menu and we're going to say
the default colors here are red blue and
green once we have that we're going to
take a look at what the current color of
the dot is and basically if it's red
take read out the menu and the same
thing goes for a blue and green and then
for each one of the colors that remains
we create a an NS menu item out of that
color and set a note milky equivalent
add the item to the menu and at the end
return the menu we've just created and
that's it if I can go back to slide
please so that's great we can now change
color easily in our dots using the menus
but let's say in addition we want to
have the ability to change the dot size
as well now we could just add on top of
red blue green the small medium and
large size controls but then we're going
to have a really cluttered doc menu so
what we really want to do is have the
ability so that when you hit the option
key that red blue and green which is too
small medium and large well again you
can create alternate menu items in ID
now ultimate many items are not unique
to doc menus they apply to any ns menu
you have but new and tiger is ultimate
many items are also available for the
doc
so I'm sorry back to that previous slide
the two general rule you have with dark
alternate menu items is that the key
equivalents have to be the same and the
team modifiers have to be different so
looking at how we would set this up an
ID remember that you always want to work
in pairs of menu items so in this case
red is going to have the ultra menu
items small and to do this I have on my
on your left should be the red the
inspector for the red menu item and on
your right should be the small menu item
we're going to first take a look at the
key equivalents and notice here that
they are indeed the same and having an
empty string for a key equivalent counts
then we take a look at the key modifiers
and notice here that they are not unique
so let's say for the small we're going
to have the option key checked once you
do that notice that the enable g as an
alternate many items checkbox becomes
enabled and all you have to do is check
that and now small is the alternate menu
item for rest and again you can do all
of this in code by setting the key
equivalent and the key modifier Mask
using NS menu item ap is as well
studying the alternate flag and I have a
quick demo for you here as well so first
taking a look at the running application
we have to your red blue and green when
I hit the option key I have small medium
and large so when I hit here turns green
with option Oh notice here that if there
are only two colors available we remove
the middle size always because it would
be weird to have like small and medium
so that's what we're trying to
accomplish looking at the code
and by the way when you look at your
sample disk image all these are the same
file they're just slightly reordered for
demonstration purposes on stage so
notice that in addition to creating the
standard red blue and green colors for
the alternates I have the available
sizes small medium and large right here
I have the code that basically says if
I'm only displaying two color options
remove that middle size and here's the
interesting part so for every color I
add and notice that once again the key
equivalent is no I also create a menu
item for the size with the same key
equivalent and then i set the key
equivalent modifier mass to be something
different than the color and then I said
to alternate flag and that's it then go
back to slides please so that's fun but
changing the color of the dots pretty
boring and you know Chuck said OS 10 is
all about fun with the animations so
let's animate the dot color so that
fades into the new color well again new
in Tiger is NSU animation which is the
only current public subclass of NS
animation to create an NS view animation
it takes an array of dictionaries with
various properties set the important
properties that we are going to focus on
for this demonstration is the target key
which should be the view or the window
that you're trying to animate and did
proper effect and in this case we're
going to use a fade in effect once you
set up your view animation all that's
left to do is to run it so this is a
very easy way for you to create
animations in your app and I'll show you
the demo of that
so now rather than just having the color
change when I took a different color it
does one of those fun animations and the
code for this is remarkably simple so we
have the original dot view which is the
color that we're actually changing but
we want the color to actually have the
original dot behind the dating in color
so what we're going to do the trick it
to do that is create a temporary dot
view that has the same color origin and
radius as the actual dot view and then
we add it to our view hierarchy
positioned above the actual dot next
thing we do is create view animation
with the temporary dot right here as the
target and once again we're going to use
the NSU animation fade in effect for the
effect ii we create a view animation
with with just that dictionary in it and
then we're going to set the duration to
one second just to make it last a little
bit longer where's Chuck knew the
non-blocking animation for the table
view sorting we are going to run it in
blocking mode so that the actual dots
color doesn't change until the animation
is complete and then we call start
animation notice that by the time we
reach this point here since we are
running in blocking mode the animation
is done and so it's okay for us to
release animation and remove the
temporary dot from the super view and
that's it if i can go backslide
fanimation is fun but what I really want
is to be able to drag my view into a
thought into into a file in a place that
the finder but when I start that drag
that location is unknown so how do i
create the file well there are few
possible solutions we could put the data
onto the pasteboard as an NS PDF pase
por types however that's going to leave
a response the responsibility to the
destination to actually write that to a
file or we can create the file at some
temporary location and once that drag is
complete move that to the drop location
or ideally we're going to delay the file
creation until the drop occurs and to do
this we use something called HFS file
promises in NFU we have a method that
allows you to drag promise file from
racks etc and basically what you hand it
here is an array of file types that you
promise to create one to drop occurs
once the drop occurs we get a call to
name a promise files drop that
destination here you're handed a URL
containing the drop location and you'll
easily create the file and that's all
and to illustrate this
so let's say I want I want to be able to
drag this and have a dot in a PDF
available in on my desktop and notice
now that I open in preview and look I
have my dot so you can send Christmas
cards to all your friends with lots of
dots you create and so looking at the
code here in the mouse drag method
here's where we promised the file type
PDF and then once the drop occurs we
implement the names of promise files dot
the destination and again the drop to
this nation is handed to you as a URL we
have some clever code here that
basically computes the file name so that
if we don't overwrite a current existing
file for those of you who've never seen
this method this is an NS view method
that basically allows you to create
create a PDF out of any view so we
create the data with that and notice
here that I create the file URL and I
route that file name to the drop
destination and a right to that file
what I return them this method is an
array of the file names i have written
and so that's great but let's let's say
i have the Finder window and I traverse
this whole hierarchy for where I want to
place a file but notice that as soon as
I click to drag I've now covered my
Finder window and I no longer know where
to drag to so what you really want is to
delay that when they're ordering so that
once I start a drag operation the
application is not ordered front but if
I click on the mouse up the window
orders front so that way just really
easy if I have my Finder window I can
drag and not block that Finder window if
I can go back to slides here
so how do i prevent my application from
blocking other windows during a drag
operation and this is very simple in
ennis window design a few method that
you can override should delay window
ordering for event and he returned yes
the event the window will not be ordered
until your mouth off event and now at
this point i'd like to invite up the
next presenter handsome soup Thank You
Tina hi my name is handsome suit and I'm
an engineering the cocoa group and for
the next ten minutes I'd like to show
you how you can use child windows and
over the windows in your applications so
let's say I have an application and I
have a main application window and I
want to create a secondary window
actually go back to slides please well
actually I'll just show you it's
[Applause]
yeah so I have a main window here and
here's my auxiliary window and this is
kind of useful for say I have a utility
window or a tool palette that I want to
be stuck to my main application window
such that if i move the main window
everything moves along with it so how do
i do that back to slide please great
thank you so we're going to do this by
using something called a child linda
we're going to make our auxiliary window
a child window of our main window so we
do this by very simply by calling a
method on NS window called surprisingly
addchild window ordered and we're going
to give it one of two ordering modes
above or below and so we can make our
kai window either ordered above or below
the main window and that's pretty much
it that's all we need to do so now let's
take a look at this in our actual code
back to demolition ones
so here we are we're going to start with
the dot view application again that we
all know and love and we have added a
new controller class to our view and
we're going to set up our child window
in a wake from nib so we could have
created our child window either in
interface builder but today we're going
to do it in code just to show you what
it looks like and here we're going to
set up the frame rectangle of our child
window and then we're going to
instantiate our child window here next
we're going to tell the main window to
add our child window and we're going to
order it above the main limit now next
after that we're going to order it above
the main window again that seems a
little redundant the reason why we're
going to order it relative to the main
window again is to work around a bug
that I found when I was writing this
demo involving I wasn't receiving mouse
clicks correctly so what what turns out
is we need to make this call in order to
tell the app kit to properly register
itself for event so without doing this
the window doesn't the athlete doesn't
know that the windows actually there so
we're going to do that next we're going
to draw a dot a dot view in our child
window so we're going to create a new
dot view and we're going to set the
content view of our child winner to the
dot view so as you can see going back to
our groups
going back to our you may have recompile
it
going back to our demo here that we can
move the dot around and we can move the
dot around the main window and I can
move this child window anywhere I want
so I can move over here and everything
just works correctly it will always stay
in the same relative position to the
main window great so now I've got I
don't know I've got two dots one in each
window so given them my brain sometimes
thinks like a three-year-old I want you
connected us go back slide please so
like any three-year-old who plays
connect the dots I'm probably going to
draw outside the line and in this case I
have to draw outside lines because I'm
going to be drawing a guideline in
between the two windows from the dot in
my main window to the dot in my travel
una so I have to draw outside the bounds
of my windows how the heck do I do that
well the answer is you don't I'm going
to I'm gonna have to fake it so I'm
going to thank it by creating a new
window a third window and I'm going to
make that window invisible and this
window is called an overlay window now a
number of things to remember about over
the windows an overlay window number one
and most importantly is just another
child Linda so it's exactly the same as
my previous child window except for one
thing well several things actually too
we're going to overlay it above its
parent window and three we're going to
make its background transparent this is
probably the most important thing we
want we want it to both appear
transparent invisible to the user and we
want it to be transparent to events so
that if you click anywhere on on the
overlay window mouse clicks pass through
to whatever is below it and lastly we
want
make the overly window borderless so
that means we can't create an IV we have
to do it in code so let's go back to the
demo and take a look
so we bring up our controller again and
everything over here is the same code as
before setting up our child window now
we're going to set up a new window
called an overlay window we're going to
call it over the window now since an
overly when it was just another child
window if you take a close look the code
is almost exactly the same as what we
did when we set up our child window some
differences one we we want to draw on
top of both our previous two windows so
we want the size of our overly window to
be the union of the other two windows
and next we're going to programmatically
instantiate this and note we're going to
give it a mask of NS window borderless
borderless window mask then we're going
to add it as a child window on top of
our main window and here most
importantly where these few lines were
going to make the window chance the
window background transparent so first
we're going to set it a set opaque know
so that events will pass through the
window background and then we're going
to set its background color to clear now
we need to draw our guideline into some
view in our overly window so what I've
done is I've created a custom subclass
the Venice view that I'm going to draw
into and I'm not going to show that code
to you now you can see that on the disk
but we're going to instantiate that view
and we're going to set it as a content
view of our overlay window so if we run
this let's see voila we have a line
drawn in between our two windows and you
can clearly see here that the whatevers
will blow it is clearly showing through
and I can move this around over here I
can move the dot around everything to
subspace correct everything they're just
updates correctly so another thing i can
do is i can resize this window and
everything will update now a couple of
things need to be done in order for this
to work so one thing is if we move the
child window where we want to tell the
overlay view to redraw itself and if we
resize the main window we wanted to we
want to do the same thing another thing
we need to do is we need to remember
that since the overlay windows size is
the union of these other two windows
since its dependent on these other two
winners so if I move this around or if I
resize either these two windows I'm
going to need also to tell the overlay
window to update its size so we're going
to do that in our controller again and
we're going to implement to win to
delegate methods on NS window window did
move and window did resize we're going
to listen to these notifications and if
the if the windows the main window or
the child window moves or resizes we're
going to do want two are going to do two
things we're going to tell the over
label you to update itself and we're
going to tell the overlay window to
resize itself of course there's one
little extra detail is when we only want
to do this if the child window moves we
don't want to do is the parent window
moves and the reason for that is because
when we move the power window the child
window always moves along with it so
we'd be doing it twice so we don't want
to do that so here we're going to check
explicitly to see if the window that's
being moved is the child window so great
everything just works we can move
this around and can resize it at will
and we've got our look nice little guide
line drawn between these two dots
alright that's slices so there's a
number of other things that we can do
now that we know how to use overly
windows for instance we can draw
controls and overlay windows this allows
us to do interesting things such as draw
controls on top of NS movie views and s
opengl views as you know neither these
two views can normally you can or you
can't use normally embed controlled in
them so this allows you to make it look
like you've got buttons sitting on top
of your movies or or on top of your 3d
content so that about wraps up wraps it
up for tribe windows and overly windows
next I'd like to introduce Doug Davidson
our resident text expert
alright thank you handsome now let's go
to the next question so this question
here is about text completion now if you
want the sort of completion behavior
where the user is typing along your
application and hits a key and is
presented with a list of completions
taken from the standard system
dictionary then you have to do
absolutely nothing that behavior is
built into the text system but there is
a reasonable chance that your
application has a somewhat better idea
than that of what the user might be
trying to type so in that case you can
customize this behavior and how can you
do that well first and most obviously if
you have a subclass of ennis textview
then you have complete control over all
aspects of the completion behavior if
any of you were here last year in the
text talk I % an example of this some of
the methods you can use you can replace
the completion behavior entirely by
implementing your own version of
complete or you are allowed to control
the range and text of the user is
presumed to be completed by implementing
range for you to completion or you can
supply a custom list of completions by
overriding completions for partial word
range etc and you can provide custom
behavior when the completion is inserted
back into the text by overriding insert
completion for partial word range etc
etc but that's not really what I want to
talk about here today what I want to
talk about today is what you can do if
you're not a subclass of ennis text view
but just a delegate of an NS text view
and really you can do quite a lot there
first and most obviously the delegate of
the text view is given the opportunity
to control and alter and change and
completely control the list of
completions that is presented to the
user also the text views delegate is
notified and given the opportunity
well any time the user changes the test
and the text views delegate is notified
and given the opportunity to control
whenever the user changes the selection
in the text and if you put these
together you can combine them to produce
the number of interesting effects and if
we can go over to demo number two I want
to present a simple little example of
that so let's just pull on it make this
a little bigger now what a happier this
application is what i like to call my
Macintosh writers companion so when
you're writing about the Macintosh
you're always saying Maxis and mass that
so when you're writing in this
application let me make this a little
bigger whenever you type Mac after a
brief pause it helpfully an
automatically offers to complete it to
one of these standard forms macintosh
mac OS michaelis 10 let me type mac wait
there it is
so how did we do that let's take a look
at the code
so the primary thing that we have here
is a little timer and it's the timer
that handles this brief pause and when
the time requires it calls its method to
completion and really all that does is
to call complete on our text view where
upon the completion behavior happens and
we also have some methods here to start
and stop the timer so when are we
starting and stopping this timer well
we're implementing those three text view
delegate methods here that I told you
about first of all one user makes any
change to the text we take a look that
change and we notice when they were
typing that sea and on that case we
start the timer it's pretty cute crew
juristic but it works very well in this
case there are plenty of more
sophisticated things that you could do
and have to make any other change we
stopped the timer because we don't want
to present the completion also if they
make a change in the selection then we
are going to stop the timer also but
only if it is not the change in
selection that occurs after the user
inserts a piece of text because we
already handled that case of above so we
keep track of that and make sure we
don't do it in that case and then when
that timer fires after the brief pause
and complete is called then the text
view delegate gets called again to
determine the list of completions to be
presented and so we implement a delegate
method for that and and there we just
notice we check to see whether the
string that we're being asked to
complete is actually Mac and if it is
then we offer to complete it with in
this case Justice 6 list of macintosh
mac OS mac OS 10 and that's all there is
to it so let's go back to the slides
and we can take a look at the next
question so next question here has to do
with mixing images and text and
ourselves now when we think about a text
cell normally what we think of is just
plain text but what may not be entirely
obvious is that you have the full power
of the cocoa text system available to
you whenever you use it so if you can
display it and text edit you can display
it in a cell or using string drawn and
of course one of the things that you can
do in TextEdit is to drag in images and
have them displayed in line and the text
so that's fine and texted it but how can
you do that programmatically well
programmatically images are a case of
what a call attached file and the way
that attached files of represented in a
distributed string is as a special
character the attachment character which
has on it a special attribute the
attachment attribute and the value of
that attachment attribute is an instance
of the class and it's text attachment
and as text attachment models the
contents of the attached file to do that
it uses an NS file rapper but that's
optional you don't absolutely have to
have that if you don't need it and the
other thing that it has to do is that it
has to provide some visual
representation to be displayed in line
in the text and to do this naturally
uses a cell and as text attachment cell
and by default and it's text attachment
will automatically generate an
appropriate text attachment self but you
don't have to let it do that if you know
what you want the visual representation
to be you can supply it you can use a
completely custom and a technique statue
itself subclass if you want to see an
example of that come to the cocoa text
talk on Friday section 437 I'll give an
example that but what I'm going to talk
about now is that you can use a
text attachment cell and just set an
arbitrary image on it to be displayed in
line in the text and here are some of
the relevant api's that sells and
controls and so forth can have an
attributive string value not just a
plain string value you can create an
interview directly from an attachment as
a convenience method if you don't have
to deal with the attachment character
and attributes aboard you create a new
text attachment with the foil wrapper if
you have one you can query it for its
attachment so you can set it the tasman
cell and you can create this attachment
cell with an image of your choosing if
you like so if we can go back to demo to
let me give a little example of that
[Music]
so that's right now what we have here
very simple is nothing more than a list
of colors in each color has a name and a
little color swatch to show you what it
is and perfectly ordinary except it what
we have over here is just a stock one
column table view no custom cell no
custom anything is right directly out of
interface builder the only code is
written here is in the data source now
let's take a look at that code I made
this really simple all I have to provide
the data is one array of colors and the
parallel array of color name so I set up
the beginning just fixed and static and
so the number of rows in table view is
always fix does that count as those
arrays the really interesting code here
is all in the table view object value
column row so what I'm going to do here
is create an appropriate attributed
string that has in it both an image and
the text so I get my color and the name
of the color and I'm going to create an
attachment I don't need a file robber
here so i'll just use meal now i'll
create a text attachment sell blank one
and i'm going to create an image that
why we use to be an image for my color
swatch and then i'm going to create a
mutable attributed string now when i
created start off with i'll just have
the color name string at this content
that's not very interesting then what i
want to do is to take on my text
attachment and to insert it into the
beginning of that string that tributed
string so i'll replace the beginning of
that attributed string with an attribute
string created from my attachment very
simple and then oh yeah
somebody was actually asking about this
on whatever mailing it's just today I
wanted to shift the image down a little
with respect to the text so they line up
nicely and to do that I set that
baseline offset on the character
representing the attachment simple
little shift moves it down so we line up
nice and neatly now I need to make this
image so i lock focus on my image that
my color fill it up and get a color
swatch then all I have to do is attach
the image to the cell that's and find
the cell for the attachment now
everything is held on to by the
attributed string so I can release the
image still on the attachment return my
attributed string and we're done that is
it so that's our example we can go back
to the slide and you can download this
tonight use tomorrow and now i'm going
to advise Chuck back up to wrap things
hi again everybody so I hope you've
enjoyed everything so far but we saved
the best most exciting thing to last
hopefully just blow you out of the water
with this I'm going to show you some
debugging tips well it's not very
exciting maybe but it's something that
everybody here has to deal with and our
goal with this here is to show you some
tips specific to cocoa which can help
you in your daily work ok so what are we
going to talk about for debugging wise
we're going to show you some debug
settings that you can set up that'll
help you some gdb tips and we've got
some ideas for helping you debug crashes
alright so first what do I mean by debug
default most of you probably know but
I'm just going to review you can set
defaults that apply either to
specifically to an application or to the
entire system and I have an example here
which shows how to set the end of food
default to some value and I've done in
the command line using defaults right so
this is a way to persistently set a
default that will live forever until you
get rid of it or if you want to just set
it for particular run of the application
there's two ways you can do it you can
launch the application from the command
line is specify dash and espoo default
and give the value or you could do it in
Xcode by finding the appropriate pain
and setting the value ok and so what are
some interesting defaults that might
help you during debugging now the first
thing I want to mention with all of
these things these defaults these
different tips we have maybe some
methods we're going to suggest these are
all meant strictly for debugging they're
not strictly supported they may be
documented somewhere maybe but the idea
is that these are to help you for
debugging only and help to you know save
you some time but they should never be
in a shipping application ok so and a
show all views with that said sorry NSU
all views can be set to yes or no and
when you set it to yes it's going to
show you something really ugly but the
really ugly thing might actually end up
being pretty useful for you what it's
going to do is show you where everything
in the view hierarchy loads it's going
to outline everything with a different
color and it might help you to discover
that oh I've got a blank view covering
my other view and that's why it's not
why I don't see my view or you know
they're not lining up right because
other views are lined up in such a way
it's useful thing I find the next thing
I talk about is Anna show all drawing
when you set that to yes it will sort of
act like quartz debug now one those who
use corpse debug one disadvantage courts
debug it flashes the screen and yellow
but it flashes the the buffer area
that's being flushed to the screen and
the buffer area is normally a coalesced
area so if I just drew an area up here
and I gern an area down here you know
the whole area is going to get flushed
screen and it might you know mistakenly
convince you that you're drawing that
entire region when you're really not so
this is a little more targeted will help
you see what draw rect code is actually
being invoked and run one other note is
that this works much better on tiger it
doesn't work quite as well on Panther so
it's just using it mostly on tiger the
value can be set to yes or it can be set
to an integer which specifies how long
to delay between the flashing of yellow
so on this example in the open panel
here let's say I click on I guess media
and when I click on media it's going to
show me that Papa past the job because
it knowledge to show media what instead
of what used to and the new column
that's being loaded is going to flash
and that's what are you going to see
it's going to flash delay flash it's
going to be really slow but it's going
to help you see exactly what's being
drawn and it might help you discover
that you're over dirtying areas and
drawing things that don't need to be
drawn to other interesting defaults I
want to mention and it's less coal left
view drawing I know it's a long name but
I didn't put it in there what this will
do is revert the coalescing of dirty Rex
back to I guess pre Panther behavior and
pre Panther what happened was if you
dirty Dan area up here and your dirty an
area down here Coco just happily
coalesce them all together and told
everything in that region to draw and in
pants there a lot of hard work went in
to making sure that we didn't do that
and now we don't collect those wrecks
together but because of that you may
have been depending on that behavior and
things that used to get drawn just
to the coalescing may not be getting
drawn so this might help you discover
why your things not drawing if you're
depending on that old behavior and then
finally just a quick note about ms trace
events at the bottom if you're not
receiving Mouse events or keyboard
events like you expect you could turn on
trace vents and see what the cocoa event
processing system is doing ok so how
about some gdb tips so one thing we can
do is we can peel an object now we're
not making the object mad what we're
doing is it's shorthand for print object
I'm pretty sure print object and what
it's going to do is print to the screen
what it gets back by invoking the
description method on your object now
one thing that I don't know if this is
actually declared in a public header and
again this is strictly for debugging
debugging there's a method called debug
description I forgot to put down the
slides with lowercase debug uppercase
description you could override and
provide a custom debug only description
if you wanted to have peel print
something different than it would
normally print when you're doing like NS
log of something ok some other
interesting things are hidden parameters
to methods this can be useful to know
about there's every method has a self
parameter which is not explicitly
declared its hidden but it's there and
there's an underscore CMD parameter
which is the selector it's the name of
the method a really interesting thing
that this one of the interesting things
about this that if I'm doing an NS log I
get tired of doing NS log type up the
whole method name I can just do NS log
percent ass and I can say you know you
see if the next step there and a string
from selector so if I just want to print
when i'm in a method i can just copy and
paste lots of code and i don't have to
keep typing the method name you'll find
out in a second it's also interesting
other places so if you want to print out
the selector without doing p 0 you could
actually print care star pet to find out
it's actually i think it's a
null-terminated but it's a string ok so
some of these things become interesting
when debugging crashes obviously message
defend is the guy that tries to dispatch
message and if it was just about ready
to dispatch a method to your objects
well those hidden parameters were all
set up to be used and I didn't point out
explicitly before and the slide that was
there it said dollar r3 is the hidden
argument self dollar for is the hidden
arguments underscore CMD so if you
wanted to figure out you know I crashed
an obscene message send well it's not
objected sees runtimes fault it was it's
probably what probably was trying to
happen was that it was about to dispatch
a message to an object that was be
allocated and what you can do is print
care star of dollar are for and you can
see what it was trying to dispatch or
you can print the address of the object
that was about to receive the message
but of course if you try and pio the
object at that point it's probably dead
and it'll raise another exception but
this could be useful when you're
debugging to see what object was about
to receive the message you know which
object was dead so on and hopefully
that's helpful normally well lots of
times your crashes may be due to over
releasing an object and one useful tip
that may not be obvious that I just want
to throw out is that you can use object
a lock and turn on its retained release
recording and you could use that to
actually pair up your retains and
releasing to see if somebody's releasing
it that probably shouldn't be alright
another idea for debugging crashes is to
enable zombies all right this isn't
something out of invasion of the body
snatchers is actually useful feature
that you can turn on in the command line
and it's not a default like the other
defaults we talked about it's an
environment variable that you'll set and
what you'll do is set the environment
variable and a zombie enabled to yes and
then what happens is for the most part
the allocated objects don't go away they
just get kept around in a state just
enough that they can receive messages
and raise errors and what's going to
happen then is that when you try and
message the dead object it's going to
raise an exception like you see at the
bottom in fact it's going to be nice
enough to tell you where you could set a
breakpoint to catch this now one thing
to notice the note about this is that it
works really well for
kit level and gooey level object but it
doesn't quite work so well for
foundation object mostly for things that
our toll-free bridged alright and
another thing that I wanted to mention
for debugging that I think it's i'm
pretty sure it's new and tiger you can
probably pretty easily find this out but
it's a method called underscore subview
subtree description and again remember
these are methods for debugging only
they've meant to help you out in
debugging we don't want to have to
support these if we want to change them
for some reason to use them disclaimer
so this is very useful because it prints
information about an entire subtree into
view hierarchy so friends for example
this is a something i printed out from
one of the earlier examples the
animating outline view it's showing me
that at the top level i have a
scrollview which has a clip view of the
sub view it has an animating out vietsub
view and so on and there's a bunch of
interesting information associate with
it and don't don't worry about trying to
scramble right down saw all this
information really quick because this is
also available on the on the download
okay so the first bit of information it
shows you to the frame and the bounds
shows you the horizontal vertical resize
springs and flags and it shows you a
bunch of other flags again go ahead and
look at the dmg okay again all this
available on the dmg gotta