WWDC2004 Session 416
Transcript
Kind: captions
Language: en
cool good afternoon everyone welcome to
session for 16 this session will be all
about using and customizing cocoa
bindings my name is ron lee sang i'm a
glue code architected Apple I work on
the cocoa bindings technology which we
introduced last year at WWDC and then
shipped in Panther as the controller
layer for Coco this year I'd like to
take the next hour so and talk about for
high-level topics starting off with a
general overview of cocoa bindings as a
technology and how it can speed up your
application development and raise the
quality of your applications and then
I'll talk about some of the new features
that we've added to cocoa bindings since
the last release and then I'll finish
off with some tips and tricks for using
cocoa bindings in your everyday
development including a section I call
roll your own bindings where we'll talk
about making your view and model
subclasses more bindings friendly so
let's see so let's start off with the
overview of cocoa bindings if I've told
you once I've told you a thousand times
model-view-controller so to understand
cocoa bindings you have to be familiar
with model-view-controller I'll say it
again you separate your application into
three distinct layers the Model View and
controller layer and the controller
layers the part that keeps the whole
application together synchronizing the
data from your model layer with the
display logic in your view layer and
that's why it's called glue code any
cocoa developer will look at this
diagram and see Oh view layer logic app
kit helps me with that and then you can
see that the model layer logic is is
built with foundation code as well as
now core data then the glue code is left
up to you you do that part well you did
until cocoa bindings so now we have a
reusable controller layer so that you
can toss out all that glue code writing
much much less code to get the same
functionality yeah that's right so to
give you an idea of exactly what the
clicker does
there we go so now Coco bindings can
complete the picture of MDC the Coco way
it provides a reasonable set of
controller classes that abstract the
interaction with model layer objects and
also Coco binding Springs with it the
notion of a binding which simply says
what attribute of one object should be
kept in sync with what property of
another object simply description of how
to bind the values between the two
objects so let me just go through the
technology base on which Coco bindings
is built there are three distinct
protocols that are in Coco that are
required for the coco bindings
technology to work the first most of you
are probably familiar with key value
coding then there's key value observing
which we introduced last year and key
value binding key value coding is an
informal protocol that lets you access
members of an object by name indirectly
that we don't directly access it by
instance variable or sending methods
method messages directly p value
observing lets you describe what object
how an object should be notified of
changes from another object so that an
interested party can be notified when
something changes in an observed object
key value binding is provides a
mechanism for establishing a binding for
creating that finding that that
definition of what should be kept in
sync with what other object the way this
works in actual mbc objects is all of
the values that are transferred between
the layers are sent via KABC so key
value coding messages are sent all the
time to notify to send values between
the model and the controller the
controller and the view then key value
observing is used for the view for
example to register itself as an
observer for the controller that way any
changes to
controller like for its selection the
name of its selection can be sent a
notification for that change can be sent
to the view this is how it knows that
something's changed well specifically
this is how it knows that something's
changed the view implements a method
also defined by a key-value observing
the observed value for key fast method
this method is invoked on the view
object on the observer whenever
something in the controller the observed
object changes key value binding lets
you bind a view or multiple views to the
same controller object this is how the
view knows that it should add itself as
an observer of the controller so during
a typical edit cycle when the when the
user is actually interacting with the
view something changes in the view and
it will propagate the new value to the
controller the controller can then on
behalf of the view send that new value
onto the model object thus keeping the
view and the model in sync furthermore
when something does change in the model
the model can tell the controller by a
key value observing but something has
changed and again 124 and again the
controller can notify any other views
that are that are registered with the
controller this way not only do the view
stay in sync with the model objects but
views in the same view hierarchy can
stay in sync with each other and all of
this is done with the magic of interface
builder so you can actually configure
these bindings in ib it's not a code you
can still configure bindings I code but
you've got I beak so think next is a
short demo of how exactly this looks an
IB will go to demo to I believe
so we have a simple mid-season called
simple interface builder Oh could I get
the other other scan please yeah one
more there yeah all right thank you so
uncluttered it here I have a simple
window and another simple panel hooked
up to a simple array controller here you
can see I've defined that the NS array
controller uses immutable dictionary for
its model objects and that my table is
bound to my array controller and it's
displaying the name of all the objects
in the array controller and also the
preferred food of all the people
displayed in the array controller I'll
just show you how this all run a few
tests interface alright you can add a
couple of items here let's go I like
pizza and say andreas who likes
chocolate egg now all I think is a sushi
guy so we can edit all these values and
you'll see here that these text fields
up at the top are kept in sync with the
number of objects that are in the table
there in the array can remove and add
and remove and add and we've also we
also have multiple selection so we can
count how many things are selected you
can even edit other values like the
favorite language of each of these
people pretty sure Angelica German I
think bill like foul language can
remember
so and you know I can change the
attributes of the text field here the
display attributes so the text font size
on a little isn't supposed to be a
preferences panel that yeah well and
even the text color oops oh there seems
to be a break in the binding here let's
go let's go update that so here you can
see I have my text color binding down to
the shared user default and here in the
color well oh it wasn't highlighted well
you get the idea the text color really
does normally change so we can do all
this stuff without writing any code all
ni b we get a lot further developing our
application just finishing the interface
in interface builder so this is what
Koko bindings will give you if we can go
back to the slides
crouching tiger hmm okay so that ends
the demo that's also the end of the
overview section how many of you guys
have actually played with bindings
already by the way oh yeah maybe you
have like like never heard of cocoa
bindings before raise your hands it's
okay are you okay so then the overview
isn't completely without merit so that's
the end of the overview now we go into
new features things that we've added for
Tiger added to cocoa bindings for tiger
the first few features that I'll go over
are the result of a lot of feature
requests the first will be a tree
controller so that now you have
something to bind to from the outline
view in the browser and we also have
filtering built into the NS array
controller so you don't have to subclass
anymore glad you like it let's I'll show
you a little bit more about each of
these first with the tree controller
with the tree controller we wanted to
make it as easy as possible to get used
to using it so it kind of feels a little
bit like using the array controller
except of course the array controllers
manager raised but the tree controller
manages a tree of objects but that tree
isn't specifically nens tree class or
you don't have to import your data into
any specific class or re-architect all
of your objects we just expect that you
have what is probably natural for all of
your data as far as tree goes that you
have a raise of objects that have arrays
as children objects of a raise of the
raise so this graph up here pretty much
sums up what what the tree controller
expects with your data if you can
describe your data this way then you can
use your tree with the tree controller
all you have to do is describe to just
just describe your tree and the main
thing for that description is the
children key they'll feel if you set the
children key
of the tree controller that's what the
key that's the key the tree controller
will use to traverse all of the nodes of
your tree so this has the caveat that
all of the objects in your tree have to
respond to this children key key this
can usually be done by subclassing or by
having a category or changing the source
there are also some optional keys that
you can set the leaf key and the account
key which offer some optimizations for
whether or not the tree controller
should reverse children there then of
course there are some actions that we
expose for the tree controller so you
can bind buttons to it for adding
siblings to the selection as well as
adding child objects to the selection
and removing any of the selected objects
from the tree controller and then after
you've set all the keys and set up your
tree controller you need to tell it
where the root of the tree is you do
this with either a content object
binding or by explicitly setting the
content object the same way as an outlet
just using an outlet from there the tree
controller will start managing the tree
of objects there also some extra key
that we've added they look a lot like
the array controller controller keys
starting off with the arranged objects
which returns the root of the tree after
any sorting has happened to the to the
child object then there's also the
selection that knows how to manage
intelligently multiple selection no
selection not applicable the turning the
appropriate key value binding markers
and we've added a couple of keys just
for convenience in interface builder can
insert child and can add child we also
have cannon certain can add in just
plain form so that now you can find the
enabled value of one of your buttons so
that if the tree controller doesn't
support adding a child then the button
consid disabled we've also added
selection index paths of the controller
key which is the same as selection in
dec
is that's because we needed something
different to identify nodes in the tree
you can think of the NS index path which
we've added the foundation as the
identifier for nodes in the tree it's
similar to thinking about how you you
access elements of an array by index
except now we have a path of indexes
that represents all the children of each
node that you traverse through the tree
so here for nine would indicate the
child at index nine of the childhood
index floor of the childhood is index
two of the root of your tree it's a
condensed way of representing each node
in your tree so now that you have the
tree controller you can bind dns outline
view to the tree controller and the NFL
lines use table columns that looks again
exactly like binding a regular table
view table column to the array
controller you just find the values or
text or font size or anything and then
you bind the content and selection index
path of the outline view to the tree
controller the content binding gives the
outline view all of the objects
basically the root object to display and
then the selection index path is how the
outline view keeps its selection in sync
with the tree controller and as I said
we also have support for in its browser
which has pretty much the same binding
content and selection index paths and
then also a Content values binding that
you want to bind so that it'll actually
get the value to display in the browser
cell rather than just displaying the
description of the content of any of the
content object after that oh one thing
if you go home and play with this
tonight try and hook up the outline view
to the pre controller and you go and
start adding things adding nodes to your
tree and start editing it editing isn't
supported yet sorry that's coming but
you can so you can still browse through
the outline view and adjust the
the layout of the tree that's still
supported and the next major feature is
filtering in the NS array controller
we've added filtering directly to the NS
array controller so you don't have to
subclass anymore to get filtering
support but in the process of adding
filtering support to the array
controller we figured we'd add filtering
support to NS array and we've also
improved the synergy of using the array
controller with the search field and all
that comes to us thanks to the NS
predicates if you caught the core data
talk earlier did anybody catch that talk
yeah good good if with that with core
data we get a new class the NS
predicates basically it's a class that
describes a condition and here the
string representation of one of these
predicates of a simple predicate it
looks a lot like the condition statement
of a sea-based language right so it's
pretty easy to use it's really easy to
work with and once you have a predicate
you can filter an array get a filtered
array from an unfiltered one using this
method filter accusing predicate or
filter a mutable array in place using
filter using predicate and of course you
can filter an NS array controller using
set filter predicate once you have an
array controller and you said it's
filter predicate all of the arranged
objects the objects returned from the
arranged objects accessor of the array
controller are the ones that match the
condition defined in the filter
predicate there's also a controller key
for the fill for the filter predicate so
you can bind objects that provide
predicates to the Ray controller
directly and because of the way the
filtering works there might be strange
user interaction it's for example
someone has filtered out objects in a
table view and they go and add a new
object into the array controller
pressing the little Add button and then
it adds it but immediately filters it
out that can be confusing to some users
but
and so we've added a new option to the
array controller clears silt predicates
on insertion with this option turned on
which is by default the array controller
will clear the filter predicates setting
it to nil and then insert the new
objects this should prevent a lot of
confusion when inserting new objects by
users and just to clarify remember that
the arranged objects of the array
controller is simply a filtered
representation of the content of the
array controller so don't worry about it
deleting the objects from your
underlying array 0 search fields so when
we release cocoa bindings in Panther we
had search field support in the form of
a recent searches binding this gave you
the ability to build search field menus
excusing much like the one that you'll
find in safari with Tiger we've added
support for building search fields that
look a lot like the one in mail so that
you can select what you want to filter
on and then the user can type in the
search criteria and the filtering
happens based on whether it's from or
two or subject and it's pretty simple
you simply bind the filter predicate
bind the predicate from the search field
to the filter predicate of the array
controller and for every binding you
make from the search field you get
another menu in the resulting search
field and again for every binding that
you make for every menu item you have
two options that you can set the NS
display name binding option lets you set
the name of the menu that'll show up in
the search field so this way it's easy
to localize your needs and then NS
predicates format binding option gives
you the gives you the ability to set the
predicate format for that menu item so
defining that the from menu item should
search on the from category of your
of your model objects oh we've also
added some integration with core data
speaking of and its predicate what we've
done is added support for core data like
functionality directly to the nsobject
and NS array controller in in the form
of well actually I'm getting ahead of
myself I should talk to talk to you
about core data first the idea behind
core data is that you define a
description of your data all the model
objects of your application rather than
writing all of the classes you define an
entity so the entity has all the
information that describes the model
objects of your application with a
description you can use an NS managed
object context to manage managed objects
there's a lot of management plan so with
the managed object context though it'll
manage all of your objects I guess
that's really the only way to say it
it'll try and keep a minimal set of
objects that you're working with in
memory so this is a good way to do like
as needed faulting of your objects into
memory space without you having to do
much work and it also manages storage
and retrieval of your data so it can
handle saves and opens for you I think
anyone who went to the core data talk
who knows what I'm talking about so you
don't have to write that extra code in
your NS document subclass for for saving
and and opening documents and the way
the managed object context gets these
objects and how you specify which
objects to its advantage is by using a
predicate the predicate simply defined
for the managed object context which
objects to fetch with these three items
you can you can pretty much manage all
of your model objects just through core
data with a minimal amount of of code
work and what we've done with the
controller's
is that the ability to define which
entity the controller uses to which
entity the controller manages really
this is opposed to what is normally
there which is the defining the object
class now that you can define the entity
you can also define a fetch predicate
which is in this case different from the
filter predicate of the array controller
this is simply the predicate that the
controller should use to fetch object
and there's also a way of setting the
bind setting the managed object context
the controllers will fetch into you can
do this either via binding or by an
outlet in ib so with these three items
with these three pieces of information
the controllers can actually fetch for
you through cord data just by knowing
the entity what such predicates to apply
for the fetch and which managed object
context to fetch into you can even set
the controllers to fetch automatically
for you on nib instantiate or you can
wire up an action from a button so that
users can flick a little such button as
much as they like and something to know
when when you're executing a fetch from
the that clock right when you're
executing a set from the from the
controller o into the object context
sorry so when you're fetching normally
it's possible to define not only a fetch
predicate but also a sort ordering but
once you have an array controller it's
really better to sort in the UI that's
always going to be more correct another
thing is we've added a Content set
binding for the array controller so that
you can bind detail array controller
like an array controller that manages
the relationship from image object
because managed objects in core data
have relationships that are held in sets
the array controller can't directly
handled the relationship objects so
we've added the content set finding
and another cool side effect of
key-value observing of building on those
three kv blah technologies kb star
technologies the key value observing the
controllers are always in sync with what
in the manage job context so you get all
of that magic for free where if
something is started into the context
it's automatically propagated up to the
UI at this point I think I want to do a
demo and this for this I'd like demo to
again sorry false signals ok so we'll
toss out this simple example go to Xcode
first all up demo the tree controller I
have a simple app that I ripped off from
one of my are borrowed from one of my
co-workers and it's a file system
browser no I should show you that I
don't actually have much code in here as
a couple of classes that actually
represent the nodes and the nodes of the
file system so these actually go out and
get the information of the files in the
file system and return it as a path
component and my main controller really
has not much in it oh let's do this
oh yeah that's better so it's not much
in there and again the node that's not
much there beeping and so this is just a
model object sort of thing the infosec
and go back to the app so this is just
an outline view bounce in the top to a
tree controller and the browser bound
for the same tree controller in the
bottom as well as a text field that
displays the selection so I can traverse
through developer documentation and you
can see that the outline view selection
is being kept in sync with the the
browser selection cool so that's pretty
easy and for the for the filtering demo
I was going to run one application but
something's happened to it so I'll skip
that demo I'll try and do something a
little later if I of time so i'll just
go back to the slides now ok so other
new features we've done a couple of
other things beyond just the core NS
controller work we've also added a
binding debug mode to help you guys
debug the binding pro some binding
problems you might run into
pretty simple switch there's a default
right and it's finding debug log level
set that to one and any errors that the
bind that the bindings encounter
accessing or setting values or invoking
methods will get logged for you defining
what was bound and what the error was so
you can track down if there were any
configuration errors in your nib another
thing we've added is info for binding
this way you can get more information
about a binding for any bound object so
if you have a bound view the text field
or something and you invoke in info for
binding you'll get a dictionary back of
information relating to a specific
binding for that text field the
dictionary has information like the
object that it's bound to which is
usually its NS controller as well as the
observed key path so the key path that
the view was bound with and also the
options key gives you back a dictionary
of options that the view is bound with
more new things on the NS array
controller if you've ever worked with
the multiple values selection marker
it's a cool thing if you select multiple
objects in a tree controller in a an
array controller for example and they
all have the same name and you want to
display the selection the name of the
selection in the array controller the
selection foxy the selection the object
you get from asking the array controller
for its selection can actually return
either the multiple selections marker or
the common name for the all the objects
in the selection the way it does this is
run through all of the selected objects
and compares whatever you're going to
display for those objects so if they all
have the same name then we'll display
the name otherwise we display the
multiple selection marker placeholder
this might be a little bit more
information than you need but the point
is now there's a new option to
turn off that behavior so that anytime
that there's more than one item selected
will always return the multiple
selection placeholder the selection
marker so this can be a big awesome
ization for selections that are very
large where all the names might be
similar well the values might be similar
and we rather do we have other random
options and bindings that we've added
and it's view now has a tool tip binding
and as text view as an attributed string
binding so now you don't have to convert
from RTF data blah to get attributed
strings into your text field your text
views and this window now has a display
pattern title binding so you can
customize the display of the window
based on multiple pieces of input from
the controller's the table column now
has a new option for turning off
automatic creation of the sort
descriptors we automatically create sort
descriptors for all the table columns in
your table that way you get sorting for
free some people don't like that so now
you can turn that off and as I said we
have a new new binding for the array
controller content set for working with
the managed objects relationships we've
also added some changes through the way
and it's pop-up button and NS matrix
work specifically we've added content
objects as a new binding with content
objects you can imagine if you bind all
of the if you bind the pop-up button to
an array of objects as its content and
you want to get you want to synchronize
the selected objects of the pop-up
button normally you would get back in
that selected objects array all of the
objects that are selected from the
content array but you might actually be
more interested in objects related to
the objects in the content array so now
with content objects you can define for
example the name of all the people in
the name of the people that you're
displaying at the pop-up will
come the selected object so you can
target a different object in your in
your pop-up it's really simpler to use
and to explain sorry and its matrix this
is pretty simple and its matrix has two
modes that we support three modes really
in radio mode the default we support
single selection so there are two
bindings the selected value and the
selected object when the matrix is in
list or highlight mode we now support
multiple selection so that you have the
selected values and selected objects
bindings available this is the simply
change that we had from last choice oh
right new features that's it now I've
been to some of the tips and tricks for
building Coco friendliness into your own
classes if you have model objects that
you want to use with Coco binding you're
probably done that's usually that's all
you need to do as long as the attributes
that you expect to be bindable our key
value key value coding compliant so in
other words your other words you have
either a key value coding compliant
accessor or the attribute where you
allow direct I've are accessed usually
that's all you really need to do and
part of that is that key value observing
automatically sends out notifications
that that Coco bindings requires as long
as you're the the attributes that you're
exposing is bindable our key value
coding compliant key value observing
does the notification generation for you
if we're if for some reason you have
other attributes that you want to expose
as bindable that aren't key value coding
compliant where you have some really
complex logic that changes lots of
values lots of lots of attributes of
your model object all at once then you
can send out notifications manually
simply invoke self will change value for
key pass defining the key passes
is about to change change the value
related to that keep up and then invoke
self did change key path this is the way
that you send out key value observed
notifications manually so as long as
your object is key value observing
compliance and you have some key values
coding compliant way of getting to the
values the next thing you would need to
do actually this is on the wrong side
key value binding exposing should be on
this slide if you if you have a view
that you want people to be able to bind
um in order so that it has those neat
little attribute boxes show up in
interface builder all you need to do is
let me go back pretend that that last
those last two items are on the next
slide exposed binding and exposed
bindings are two methods that you can
that you can use on your class they're
defined in key value binding H and it
lets you programmatically expose
bindings for your class that way they
show up in interface builder as long as
the class is loaded by a bundle or a
pallet continuing with making your view
cocoa bindings compliant once you've
exposed the binding of your view you'll
need to implement the bind to and unbind
methods the bun to method is how is is
how you get the information of of what
your binding should do of what's the
synchronized between your view and some
controller object typically there you
would simply cash the object your
binding to as well as the key path and
options dictionary that you're going to
be that you're creating the binding with
and immediately after you would
typically add yourself as the observer
of the object you're being bound to so
your view would invoke self add observer
or object that you're biting to add
observer self so that way notifications
in the form of observed value for key
pass
whenever something in the observed
object changes once you have that in
place if you have a view that's actually
doing something that's editing related
editing a value rather than just display
you'll probably also want to implement
the NS editor and NS editor registration
methods well really implements the NF
sedative methods and know about the NS
editor registration methods NS editor is
a proto informal protocol that defines
how the controller can tell your view
that it should stop editing or discard
editing commit editing is invoked on
your view if you should try and end
editing in your in your view and then
you can return succeeded or oh if there
was some sort of verification validation
error discard editing is since when you
should just throw out any changes that
the user is made and revert to previous
value once you start editing once an
editing session has started like the
user has started moving around something
in your view in your control then you
can invoke objects did begin editing on
the controller that you're bound to this
you should be notified if committed if
it should commit edits or discard any
edits and that's course once editing is
done you can send the controller
objected and editing
now once we have your view and it's
bindable and beautiful then you should
really put it on a pallet that's the
best way to take advantage of cocoa
binding so that people who use your view
use your code don't have to write the
manual bind to blah blah blah message in
there in there in there classes now just
going over again some of some of the
basics of how cocoa binding works with
key belly coding observing and binding
when I say a key value coding compliant
access ER I'm really talking about a
name and set name kind of method pair
with that your your model object will be
key building key value coding compliance
for the key name so that way you can
bind the some attribute to an object
that is of your object type with the
keepass name that's all you need to know
for them oh oh that's true now if you're
a view and you want to implement this
bind method again what you typically do
in your implementation is cash away the
observed controller the key path and the
binding options that are sent in during
the binding creation and if you're going
to support more than one binding it's
probably a good idea to cash these in a
dictionary on a binding basis this way
when you get the key value observe
observe value for key best method method
invoked on your on your view you can
keep track of what attribute you're
supposed to update in your view and here
I'd like to ask andreas to come up to do
a little demo he doesn't know what I'm
getting him into so I think a lot of
people are kind of confused about how
cocoa bindings works how to bind to
method works so
perfect so if we pretend that you guys
are the developer of some application
and I love you and Andreas is a
controller not that I'm saying anything
here in order for me to keep some
attributes say my I'd wanted to find a
hat actually say which arm is up if I
wanted to keep that and think with some
value that andreas can give me exactly
see all you have to do is say Ron bind
arm height to andreas Ron bind arm
height to Andre perfect so it's
something like that so now anything on
dreis does I can see and update my state
pretty that it's pretty simple right see
now now the great thing is the great
thing is we with bindings you can also
add value transformers so that anything
that I get from the controller can be
changed before actually sent to the view
so if there was an NF negate boolean
transformer or negate arm high
transformer anything he did would be in
reverse
not done with you yet so let's do a
little role reversal is my therapist
before my face let's pretend that I'm
the controller and that andreas is the
view what really happens is if something
changes that in some model object
somewhere then I would send a
notification Andre and what this really
highlights is not only that the
notification is really lightweight let's
it could so lightweight could you can
get that we can send a lot really fast
so this is this is how you should think
about Coca binding well maybe not but so
you get the idea hopefully that clears
up exactly exactly what's going on when
you bind objects find a view to another
object and with that I think oh now
quick recap yeah yeah there we go so
Model View controller again model view
controller that's what we're based on
Coco lives and breathes Model Model View
controller because of the code reuse
that's really what we get out of Model
View controller here and with Coco
bindings now we get a set of reusable
controller objects as well as the notion
of bindings so that we can we can cut
out all the glue code that were used to
write in and to to keep with the the
outline that I introduced some of the
new features we've added to Coco
bindings includes a tree controller so
now you have something to bind to from
the outline view in the browser we've
also added filtering directly to the
array controller also to NS array and NS
mutable array we've even added core data
supports
the controllers so that you can fetch
directly into controllers and then we've
added some new bindings and bindings
options which you'll see the
documentation forthcoming one more and
so the tips and tricks for for rolling
your own bindings come down to making
sure that your model object and your
view objects are key value coding key
value observing and key value binding
friendly this means making sure that all
of your model objects have actual KBC
accessors that and and that you can do
the key value observing notifications
and then for your view classes it really
helps to to expose the bindings of any
attributes you want and then put that
view on a pallet and with that here's
all the reference stuff and who to
contact would be Matt Formica will be
coming up shortly I believe