WWDC2014 Session 224

Transcript

X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
>> Welcome to Core
iOS Application
Architectural Patterns.
My name is Bill Dudney
and I work on UI kit.
Thanks for being here.
[ Applause ]
>> So exciting!
There's so much cool
stuff this year.
Okay so by way of introduction,
what we're going to talk
about today is sort of the list
of common patterns that we find
across all of the frameworks
in iOS and Cocoa Touch.
We are also going to
spend some time talking
about how we can apply
these patterns to your code.
How we can make our
applications better
by understanding
these patterns, one,
and then applying the concepts
defined in those patterns
to the code that we write.
All right, so common
patterns in UI kit and beyond.
The great thing about
these common patterns is
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The great thing about
these common patterns is
that once you understand
it in one context,
the way that we use them
across all of Cocoa Touch ends
up being very similar.
So when you first look at
the list of documentation,
we have all these frameworks.
The core video, core audio,
core animation, foundation,
core data, and so forth.
It can be a little overwhelming.
You look at that list
and say holy cow,
that's a giant fire hose that
I have to ingest right now.
Well the great thing,
though, is that, again,
these patterns are used
in a common way throughout
this whole stack of frameworks.
So when you understand one
pattern in one framework,
you can apply that knowledge
across the whole stack
of frameworks, so it
really levels out the amount
of learning that you have to do.
So let's get started
with the first pattern.
And that's target action.
Now, target action
is a consistent way
to connect controls
to custom logic.
Things in your user interface
connected to the code
that makes your application
what it is.
So if you've ever
done this in X code,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
you have seen target
action in action.
When you drag that
connection from the button
to your view controller,
it's saying hey,
whenever this button is
activated, kickoff this message.
Here's an example from
one of our applications.
This is the message application.
And we have several
buttons on here.
That top one, the cancel button.
Of course when that's
tapped, that's going
to send a cancel message, it's
going to delete the message
and get rid of this
Presented View controller.
When the user taps on send, it's
going to package up the message,
push it off into the
interwebs, it's going to end
up in whoever's device you're
having the conversation with.
Now, the really cool
thing is these two classes
that make these instances, the
classes for these instances,
are from completely different
places in the class hierarchy.
UI Bar Button item is a
subclass of NS Object.
UI Button is a subclass
of UI Control.
But both of them apply
this target action paradigm
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
But both of them apply
this target action paradigm
so that you don't really
have to think about the fact
that they're different classes.
They both apply this pattern
in a very consistent way.
So once you understand it for
one, you understand it for both.
Getting a little more abstract,
talking about target action,
the idea is you have a
controller, an initiator,
something that kicks
off the message send.
That has a target object
that it sends the message to,
and then the particular message
that it sends is called
the action message.
Once you understand this,
again, wherever we use this,
it's used in such a consistent
way that if you understand it
in one context, you understand
it in all the contexts.
So with gesture recognizers,
same thing.
A gesture recognizer has
a target and an action,
and when you create that gesture
recognizer you specify that,
so again, it's exactly the same
kind of concept as what we see
with the control objects.
So that's target action.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
A way to specify a
connection between two objects,
and get those control objects
to invoke custom code
in your application.
Next up is the responder chain.
The responder chain lets your
application handle events
without knowledge of which
particular object is going
to be used to handle that event.
Responder chain kicks off
with some sort of initiator.
It's just some object
in your application
that kicks off the process.
It could be user action,
it could be a control,
or a controller.
That sends an action
to the first responder.
And that first responder
might respond to it.
And if it does, then
the process is done.
That responder has handled
that message and it's complete.
But if it doesn't, it's going
to ask its next responder, hey,
do you respond to this message?
And if it does, then of
course it will handle it.
But if it doesn't, it keeps
going up the responder chain
until it finds some responder
that actually implements the
message, whatever that was
that was asked to be done.
Change the color of a text
field, or copy the contents
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Change the color of a text
field, or copy the contents
of a text field, or
whatever you happen to send
up the responder chain.
A particular place where we
use this is with motion events.
So when the user
shakes the phone,
we send this motion
began, motion ended,
and motion canceled,
to the responder chain.
And so that travels up
the responder chain,
looking for the object that
responds to that message.
And the great thing is you
can use the responder chain
to respond to things like
that, like motion ended,
by implementing it
wherever it makes sense
in the responder chain.
So here's a picture
that diagrammatically expresses
what all applications have,
which is their responder chain.
It starts off in
the view hierarchy,
it travels up the view hierarchy
until it gets to
a view controller.
The view controller, if it
doesn't implement, it passes it
up to the window, the
window to the application,
and then finally the application
to the application delegate.
And that's the responder chain.
It lets you build a group
of objects that are going
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
It lets you build a group
of objects that are going
to eventually find
out who is responsible
for implementing a
particular message.
Next up is Composite.
Composite lets us
manipulate a group of objects
as a single object, and
we use this extensively
in the view hierarchy.
So I start off with a single
view, created alloc init
with frame, I create a new
view, and then call add subview.
Now, these two objects, the
parent view in blue here,
and the child view,
the one in green,
are in this composite
relationship.
So now I can treat
the whole hierarchy
and I could have hundreds of
views beneath that blue view,
but I get to treat all of
them as one Composite object,
so I can do things like
move that parent view.
And when I do, all of its
subviews move along with it.
Same thing with other actions
that I tell that view to do.
Move it back and
then I rotate it.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Move it back and
then I rotate it.
All of the subviews in that
Composite are treated together
as one object.
We also use the view
hierarchy, as I said earlier,
in the responder chain.
So as you add child views
to a view, its superview,
the new child view that was just
added, its superview becomes
that view's next responder,
and so that's how it gets
up to the point where it finds a
view that has a view controller.
It travels up its
superview hierarchy.
And again, we use this same
pattern in multiple places.
If you've spent much time
using the UI Dynamics,
a dynamic behavior is able to
have a child dynamic behavior,
and if you group them
together in a composite
by calling Add Child Behavior,
then those two behaviors are
treated together as one thing
by the physic simulation that's
running in the background.
So that's Composite, allowing
us to build a group of objects
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So that's Composite, allowing
us to build a group of objects
into a tree that then we can
treat as one single object.
Next up is delegation.
That allows us to customize
behavior in our applications
without subclassing the
object whose behavior we
are customizing.
So a great example that you see
in almost every introduction
to doing iOS development
is talking
about the application delegate.
The application is delegating
to the application delegate
to customize the way it behaves.
So there is a set of methods
that the application
delegate protocol specifies,
application is going to
go into the background.
Application is going to
come into the foreground.
Application wants to open
this URL and so forth.
All of those methods
that you implement
in your delegate customize
the way UI Application acts,
but you don't have
to know anything
about the details
of UI Application.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
about the details
of UI Application.
So this was a very particular
decision made by UIKit
to use this form of delegation.
We could have, on the other
hand, we could have asked you
to subclass UI Application,
and that would've worked.
There's actually GUI frameworks
out there that ask you
to subclass the objects that
come out of the GUI framework.
But if we asked you to subclass
UI Application, you would have
to understand a lot of
detail about UI Application.
Which methods are
safe to override?
Which methods are
not safe to override.
If I do override this method,
do I have to call super,
or is that optional?
We don't want to put that
cognitive load on you.
We don't want you to have
to think about that stuff.
So instead, using this idea of
delegation allows us to delegate
to your code to say
what do you want custom?
What do you want special to have
happen when the application goes
into the background or when
it comes into the foreground?
That allows you to customize
the way UI Application works
without us having to force
you to understand all
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
without us having to force
you to understand all
that detail about
UI Application.
Now, of course, there's still
a lot of detail that you have
to know, but that's what
makes you awesome developers.
And again, we use this in many,
many frameworks throughout iOS.
Here's just a few.
AV Foundation makes
extensive use of delegates.
Core animation has
delegates on their layers.
Game Kit has a couple
of different classes,
including GK session,
that have delegates.
And in every case,
that delegate is
about customizing the behavior
of those other classes,
without you having to
subclass from them.
Okay, so that's delegation.
Next up is data source.
That allows you to customize
data retrieval without having
to subclass the object
that needs the data.
A common example from UIKit,
UITableView has a
UITableViewDataSource.
That allows the table view to
know how many sections it has.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
That allows the table view to
know how many sections it has.
How many rows are
in each section?
What data belongs in each of the
rows that are in that section?
So the table view asks its data
source all these questions.
That gives you the chance
to customize how the data is
retrieved, where it comes from,
and so forth, and provide
it to the table view.
But you don't have to
subclass table view.
It would be the same situation
subclassing table view
and require you to know all
sorts of detail about that,
that we didn't want to have
to force you to think through.
So here's some other
examples inside the UIKit.
Same basic story, UIPickerView
says hey how many things belong
in my picker view?
PageView controller.
Hey, how many things
show up in my page view?
Give me the next thing that's
going to show up in here.
So again, if you understand
data source in one context,
when you see that
word data source,
it means the same
thing throughout all
of the frameworks.
So again, you get to
leverage that learning
across all different things.
So back to the definition
here of data source.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So back to the definition
here of data source.
Customize data retrieval
without subclassing.
That looks an awful lot
like customize behavior
without subclassing.
And in fact these two
ideas are really similar.
It's the idea of
composing an object rather
than extending a class, and so
you use a couple of objects,
compose them together
to get custom behavior,
rather than subclassing.
It's a powerful idea
that we use, like I said,
in many different places.
So that's data source.
It allows you to customize where
data comes from for an object
that needs data without having
to subclass that object.
All right, next up is
Model View Controller.
Model View Controller is in lots
and lots of our documentation,
lots of books have
lots of things to say
about model view controller.
There's probably a definition
for Model View Controller
for every person in here.
Or maybe more.
The way I like to think about it
is Model View Controller gives
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The way I like to think about it
is Model View Controller gives
us a way to organize, to build
an organizational structure
around the responsibilities
that our application has.
So let's start off
talking about the model.
So I like to think of
the model, or the way I
like to describe how to think
about the model is it's
the data, it's the stuff
that makes up your application.
And this is typically something
that people don't have
trouble getting their heads
wrapped around.
They typically can look at
what their application is doing
and say "Oh, I see,
that's a model object."
The view also ends up being a
pretty well understood piece
of the MVC puzzle.
It's the thing that displays
the information to the user,
and takes user interaction,
taps and moves and so forth,
and turns those into state
changes on the model--
or sorry, and allows the user
to make those kind of gestures,
and the controller is then
what's responsible for shuffling
that back and forth, so it takes
information from the model,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that back and forth, so it takes
information from the model,
and shuffles it so that it
can show up in the view,
and then takes the user's
interaction in the view
and shuffles that back into
state updates on the model side.
So that's model view controller.
An organizational structure
for how we can think
about the objects and
their responsibilities
in our applications.
So now let's take these
ideas, these set of patterns
that we've discussed, and talk
about how they apply
in our applications.
How they're used.
To do that, we're
going to sort of think
through a sample application.
And when you build an
application, I hope that all
of you have downloaded the HIG,
the Human Interface Guidelines.
It's in iBooks as well.
It's very near the Swift book.
If you go look at the
Swift book and then you tap
on related books, you should
see the HIG book in there.
In there, there's
a whole section
where we spend time talking
about something called
an application
definition statement.
Many people who have unfocused
applications aren't able
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Many people who have unfocused
applications aren't able
to come up with this.
Their architecture ends up being
very disbursed or whatever,
not well thought-through.
So I like to tell people to
really spend some time thinking
about this 30 second
elevator pitch
of what your application
is and who it's for.
So our application is
going to allow people
to share simple short updates
about what's happening
in their lives.
So this simple phrase
here has a bunch
of architectural implications
for what our application
needs to look like.
And some requirements
that the application has.
So the application
needs to share.
So if I'm going to share
some information with you
and we happen to be
in different places,
we need to have a network, so
I can take that information,
push it out to the Internet,
and then you're able
to pull it down.
It's going to be short updates.
That sort of implies
there's going to be a lot,
so we have a scrolling
list of information.
And then finally,
what's happening,
and since it's what's happening
now, it needs to be fast.
So we'll call our application
Qwinkle, and here's a few ideas
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So we'll call our application
Qwinkle, and here's a few ideas
of things that this
application needs to do,
or we might want it to do.
Mark items, edit
post, add photos.
So in the process
of sort of thinking
through what our
application does
and then what the architecture
of it is going to be,
this is sort of the process I go
through whenever
I'm building an app.
What's the application
definition statement?
From that, I get a list of
features that I think might fit
in that, and then, the
all-important step of figuring
out what to say no to.
So you have this long list, then
you run it through the filter,
of what is my application about?
What's the first thing
that I need to focus on?
What's the most important
thing that I want to focus on?
And so that's going to allow us
to drop these last three
entries, and we're just going
to focus on these
first four things
for how our application
is going to work.
So now let's go through and
talk in a little more detail
about the application, now
that we have a sort
of a picture of it.
So here's a wire frame
of the application.
We have a list of
updates from our friends.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We have a list of
updates from our friends.
They have avatars, and then
we have this plus button
on the top, where we
can add a new entry.
So the first thing to do is sort
of spend some time
conceptualizing what does our
application look
like through the lens
of the Model View
Controller design paradigm.
And the first thing I like to
do is talk about the model.
And a really good sort of first
cut approach at how to come
up with what does the
model look like, I think,
is to write down
some user stories,
or maybe if you've ever used CRC
cards, like the titles of those,
the list of things that you know
that the application is going
to have to do, and then
pull the nouns out.
So here we have a statement
a user can specify an avatar,
well that tells us user and
avatar, these other statements--
a user can have an entry,
a user can follow a friend,
so there's relationships
between these users.
All of these items,
all the nouns
out of this list tell us
what the model objects are,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
out of this list tell us
what the model objects are,
and so from that, we come
up with this simple model
where we have Qwinkers have
friends, they have avatars,
and then they have a list of
Qwinks, so that's the model.
Next up is the view.
So how we're going to display
this, since we're using UI Kit,
we're on top of iOS,
and we're going
to make a beautiful application.
We're going to use a table view.
That table view is
arranged in a composite.
Of course you have the
table view at the top.
It has a list of
table view cells.
Those table view cells have a
text view and an image view.
Since they are arranged
in a composite,
whenever this table view
scrolls, and I move its bounds,
I only have to move
the table view.
Aren't you glad you
don't have to iterate
through all the table view cells
in your table view and move them
by the appropriate amount?
I do enough math without
having to do that.
All right, so that's the view.
Next up is the controller.
Now, remember the controller's
role in our application is
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now, remember the controller's
role in our application is
to shuffle the data between
the model and the view,
and then take updates, and
apply that back to the model.
So our view controller
is going to act
as the data source
for our table view.
So we have our UITableView.
It has this dotted line
or weak relationship
to its view controller, and that
view controller implements the
data source protocol.
So our view controller is
going to tell the table view,
here's the number of sections
and here's the number of rows,
based on interacting
with the model.
Our view controller will also
be activated, will be told
to do things by the
user interface,
and will use target action, of
course, to make that connection.
So when you tap on
the plus button,
it says "what's my target?"
Oh, my target is this
object here, which happens
to be the Qwinks
view controller,
what message should I send?
Oh, that's the add
a new entry message.
Our view controller is also
responsible for dealing
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Our view controller is also
responsible for dealing
with the networking stuff.
So the view controller has
to manage the networking.
It has to be able to get
the data from the internet,
turn it into objects that we
can display on the screen.
We'll talk in more
detail about that shortly.
So that is the model
view and controller
for this initial scene
in our application.
We have our Public
Timeline View Controller,
which acts as the data
source for the table view,
and is able to get information
from the model and shuffle
that into the view
by implementing
that table view data
source protocol method.
The entry view-- sorry, the
table view, is a composite.
When we scroll it, everything
moves together as one.
The next piece that
we had talked
about was adding a new entry.
So when the user is
adding a new entry,
we're going to have a new view
controller, and a new view,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
we're going to have a new view
controller, and a new view,
because we have a different
way to present stuff.
But the model class, the
set of model classes,
is going to be reused.
We're going to use the same
classes to represent that data.
So it's a different
amount of shuffling,
or a different kind
of shuffling, right?
Because we're shuffling
data for a particular entry
into the view, and
of course the view,
what the view does is different,
so there's different stuff
for the controller to do.
The model class ends
up being the same.
So we're able to reuse that.
So the user taps on the button,
that sends the action message
to its target, which is the
Public Timeline View Controller.
We present the add a new
entry, and then these cancel
and done buttons would be
connected via target action
to the new entry
view controller.
Now this view controller
also has
to interface with the network.
When the user finishes
entering this new entry
and they tap the done
button, we need to package
up this information, push
it out to the internet,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
up this information, push
it out to the internet,
it's going to live on
some server somewhere.
There's a potential
smell going on there,
because now we have two
controllers that have
to manage the same
kind of stuff,
and that's probably not good.
We'll talk more about
it shortly.
The last piece of taking
our common set of patterns
and looking at the way they
work in this application,
the UI Application
is, of course,
going to have an app
delegate for application,
and that's going to handle
things like state restoration,
it's going to handle
background downloading,
and the application
becoming active and going
into the background
and so forth,
that whole stack of stuff.
So now we have this
built, and change happens.
Our users come up with new
things that they want to do.
Our designers come to us and
say hey, can you change this,
and make this thing
do this other thing?
And so forth.
So we have our initial
table view controller,
and our next set of requirements
that we want to address is
to be able to send
private messages.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to be able to send
private messages.
So now we have our
initial view controller,
which has this networking
code in it.
What are we going to do about
this new view controller?
It also needs to have
networking code in it.
This is really starting to be
some pretty smelly code, right?
We don't want to
copy and paste this.
If we took the understanding
of how to download information
from that initial view
controller, we could, of course,
copy and paste it into
our new view controller,
but then what happens over
time if something changes,
a URL changes, or
who knows what else?
The interface to
that thing changes,
and we have copy
and pasted code.
Now when we fix it in
one place, it's not going
to get updated in the others.
So bad idea.
So instead, what we will do is
let's re-factor this and pull
that URL code out of the
view controllers and put it
into a download service.
When we do that re-factoring,
we'll start off
with our Public Timeline
View Controller,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
with our Public Timeline
View Controller,
which probably had
the networking code
in it to start with.
We'll pull all of that
from the view controller
into the download service.
So we'll call download on that
object, and when it's done,
it's going to send
back a response.
Now, I put a solid line in here
specifically because I want
to talk through the idea of
making a hard relationship
between these two things.
The Public Timeline
View Controller has
to know the download
service, because it's going
to be responsible
for creating it,
but it's the download service,
also has the hard
relationship back
to the Public Timeline View
Controller, then we're going
to have to add a property
to that download service,
and it's going to have
to have a relationship
to this Public Timeline
View Controller.
When we add a new
view controller,
do we add a new property?
Like, we don't want
to go down that path.
So instead let's make
that a weak relationship,
and use delegation.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So notice how we took the idea
of delegation that we have
in UIKit, and now we're applying
that to the code
in our application.
We're going to define
a delegate protocol
for this download service
to call back to our code,
so that we can customize
what happens
when that download
service does things,
like when it finishes
downloading code,
or downloading a JSON
file and so forth.
Now, when we need to use
this again, to interface
with the private message view
controller, it implements
that download service delegate,
and the download service
doesn't have to know anything
about either of those
types other than the fact
that they implement
that protocol.
All right, and with that,
let's go take a look
at the demo [beep sound].
All right, when I
started writing the demo,
I sort of went off the deep end,
and I tried to build
this whole application,
I was building a service, and I
realized this is just too much
for us to cover in the last 15
minutes or so that we have left,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
for us to cover in the last 15
minutes or so that we have left,
so instead, what I've done is
I've made a vastly simplified
idea of this application.
Let me run it for you, and
I'll talk through what it does.
So I started with the master
detail template out of X code,
which creates for you a table
view, and then that table view,
when you tap on items
in there, it navigates
to a detailed view controller.
I took out the detailed
view controller just
so we would have focus on
this one view controller.
I added a refresh control,
so that when you pull down,
it kicks off the refresh, it
downloads some information,
and then it logs in the
background to let us know
that it was successful in
downloading that information.
So in a real application,
of course, you're going
to be processing the JSON that
comes back from that download,
and doing all sorts
of fancy stuff.
But for our demo, we're
going to be simple,
and just have this
download happen.
So let's look at the way the
code works over here, briefly.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So let's look at the way the
code works over here, briefly.
So here's our view controller,
and notice it's implementing
all these delegate protocols
for the NS URL stuff.
We want to move that
from our view controller,
over to this new object,
the download service
that we're going to implement.
We don't want our table view
controller to understand all
of this detail about
how networking works.
We want to capture that in
one place so we can reuse it.
So we're going to go
through all this code here
that does all that,
and just move it.
Now, I'm not going
to make you sit
and watch me type all this stuff
in and copy and paste it in,
and have me mess it up
and have it not work.
So instead, I have
a bunch of get tags
in here [tapping sounds].
Awesome! Okay, so our view
controller now no longer has
this knowledge about the URL
session and how it works.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
this knowledge about the URL
session and how it works.
We removed all those,
and moved them
over to our download service.
We also took all that code from
in here that was interfacing
with the network, and moved that
over to our download service.
And that's the URL that we're
using to download and so forth.
So our view controller did
have all this knowledge,
and we've moved it over
into our download service.
Now the download service
has all that information.
Our download service, though,
doesn't have any API on it yet.
So we haven't made it so that we
can actually interface with it.
Our view controller still has to
manage making the network call.
Right? We don't want the
download service just going
rogue and downloading stuff
whenever it feels like it.
The view controller, being in
control of how things happen
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The view controller, being in
control of how things happen
with the user, taking the
user's input from the screen
and turning that into stuff
that happens on the back end,
we want the view
controller to be in charge
of making that happen.
So we need to add a couple of
methods to our download service
to allow it to first
do the connection,
create the NS URL session,
all the configuration stuff
that goes along with that,
and then we also want a method
to start that, to kick it off.
So we'll do another magic
switcho-change-o [assumed
spelling], and our download
service now has these two
methods connect and start.
In the connect method,
we're creating NS URL
session configuration stuff,
and then in the start method,
we create the download task
and tell that to start.
From our master view controller,
we are still kicking
off the download
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
we are still kicking
off the download
from our refresh
control, and of course,
that refresh control uses
target action in order
to make the connection between
the control and our custom code.
But we've greatly
simplified what's happening
in our view controller.
Instead of it having any
knowledge about this networking,
it only has knowledge
about kicking it off.
About starting it.
About making it happen.
All right, so now we can
run the application again.
Now when we pull down, notice
here it's telling us in the log
that it finished, but our
refresh item hasn't stopped.
So the issue, what's going on,
is our downloader now has all
the knowledge about what's going
on with the download, but no
one is informing the controller
that that happened,
that it's finished.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that that happened,
that it's finished.
And so it finishes just fine,
but our refresh isn't able
to stop, because our view
controller doesn't know
that the download is finished.
If only we knew a way
to customize the behavior
of a reusable class.
Of course, we do, right?
We use delegation
to make that happen.
So now, what we need to do is
create a delegate protocol.
We need to create a
property on our downloader
to have a delegate
property and make
that delegate property
implement that protocol.
[ Background Sounds ]
>> So our download service
has this method spelled
out in the delegate
that says, hey,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
out in the delegate
that says, hey,
the download service did
finish downloading this URL,
which is the original URL that
was asked for, it downloaded it
to a particular URL, and then
that last R unit is an error,
saying everything is fine if
we pass nil there, or hey,
something went wrong, and
this is what happened.
Now, if we were going to build
a more sophisticated networking
stack here, what we'd want
to do is provide many
more delegation points.
Many more places
for customization.
Things like, hey, I need some
authentication information.
Other things like that.
Or, I have finished downloading
10 bytes out of the 100 bytes
that I'm going to download,
so you could update the
spinner appropriately
from the view controller.
But we'll just leave it
at this for right now.
And then in our download
service, really important piece
of the puzzle is when the URL
session finishes downloading,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of the puzzle is when the URL
session finishes downloading,
when the, you know, we
kick off the download,
and when it finishes, it's going
to call back the NS URL download
task is going to call back
and say hey, I'm finished,
we need to make sure
and tell our delegate
that that happened.
That callback goes from
our download session
to the view controller, which is
then going to use that knowledge
that the download has
finished to end refreshing.
We also put the responsibility
of what to do with that document
into the view controller.
So if you notice up
here, further up,
we're doing some file moving
around, taking the file
and moving it and so forth,
in a real application
this is another place
where I would create
another service.
Probably something like a
JSON parser, and I would take
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Probably something like a
JSON parser, and I would take
that JSON parser and say,
hey, here's the stuff
that just got downloaded,
would you please take care
of parsing it and turning
it into real objects,
create another delegate
protocol for the JSON parser,
and the JSON parser would
call me back and say, hey,
everything has finished parsing.
And then that's when I
would actually have all the
information I need to change the
way the user interface looks.
One other thing that
I always like to talk
through with developers is we
have stepped over the boundary
where we understand and can
start thinking about how UIKit
and Foundation are implemented.
So let's take a step
back and take a look
at our download service.
So the download service
specifies
that it implements
this set of protocols.
Every one of those protocols'
names ends in delegate.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Every one of those protocols'
names ends in delegate.
The responsibility of
anything that is a delegate is
to customize the
behavior of the object
for which it is the
delegate, right?
So what we are doing
is specifying
that we are able to
fulfill that role.
Now, in the code, I don't want
to have to go show it to you
because there's so much
code there, but in the code,
I am making this download
service the delegate
of the download task
NS URL session.
So imagine with me, if you
will, what the code looks
like in NS URL session
or in NS download task.
There's got to be a chunk
of code in there somewhere
that does something
very similar to this.
I hope that helps
you think through,
like how does the
puzzle fit together?
How does all this work?
We do the same things
that I'm asking you to do.
We define a protocol that says
here's the customization path,
here's the customization
points that you have
for this reusable object.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
If you implement this method,
I will call it, at
a particular time.
Now you're building that
for your own application.
You're defining this download
service delegate protocol.
And it has a single method in
it right now that says, hey,
I finished downloading this
stuff to this particular URL.
That would be a perfect place
for us, as I said earlier,
to take that URL, pass
it off to a JSON parser,
let the JSON parser crunch
on it for a little while,
perhaps put the data through
core data into a database,
message us back and say yes, all
that information has been parsed
and all that information is
sitting in your database,
and you're ready to
update your table view.
Okay, so one last piece
of stuff in the demo here
that I'm not particularly
happy with.
Well, let me go ahead and
run it again just for fun,
so we can see it stopping.
So now we're back
to the functionality
that we had before we
started hacking and slashing
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that we had before we
started hacking and slashing
and doing surgery
on our application.
All right.
So one last, like I said, one
last piece of stuff in here
that I'm not particularly
happy with.
If we go up here in the
download service, and I glanced
over this earlier, because
I didn't want to confuse
where we were in the talk.
If we go in the download
service, we see this thing
where we're calling out to UI
application, shared application,
give me your delegate.
And then we're casting that
to a class that we know about,
and we had to import
that header file.
So now we've made our
download service dependent
on our application delegate.
That is, that's smelly code.
You don't want to do that.
Because your app delegate,
its responsibility is
not providing information
to download services.
The application delegate
is supposed to be
about maintaining
the relationship
between your application
and the rest of the OS.
The methods on there are
things like I'm about to go
in the background, I came
back from the background.
That's the stuff
that you should focus
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
That's the stuff
that you should focus
on for your application
delegate.
I see this pattern repeated
in many people's code,
and it's a really bad idea.
If you're casting
shared application,
application delegate
to your class,
and then you're sending it
messages, that's a bad idea.
So let's do a little bit
more clean up to fix that up.
[ Background Sounds ]
>> So a couple things
that we did.
The first part is adding
an additional call-back
into our delegate protocol.
So we added a new method,
download service did
finish with identifier.
So that's going to let the
download services delegate know
that this download has
finished that's related
to this particular identifier.
And we're going to call
that in the same place
where we were calling out to
the UI Application delegate.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
where we were calling out to
the UI Application delegate.
Then, in our view controller,
in the implementation
of that additional delegate
method, we're going to invoke
that background session
completion handler.
And not to go too far into
the details around there,
because it's not germane to
talking about delegation,
but that's just a call-back
that we tell the OS.
Hey, we're finished
processing this download
and you can take a new
snapshot of the application.
I have a link to the talk on
NS URL session from last year,
and there was also one this
year that has a lot more detail
about how all that works.
Now we have gotten
rid of the dependence
from our download service
to our application delegate.
So we no longer have this sort
of marrying of these ideas
or placing too much
responsibility
on the application delegate.
The application delegate is
responsible for one thing.
Keep it focused on
that one thing,
and don't start spreading it
out throughout your whole
application and using it
for many different things
that do not include its
set of responsibilities.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that do not include its
set of responsibilities.
So in summary, there are
lots of frameworks in iOS.
But the cool thing is that once
you understand these common
patterns that are used
throughout all these frameworks,
delegation, data source,
target action, responder chain.
Once you understand that in
one place, you understand
across the whole
stack of frameworks.
So you get to leverage
your learning,
understanding these patterns
gives you power to use all
of these frameworks
in your application.
And the next thing
I want to say,
in terms of summary,
is just go for it.
There-- I have talked to many
other developers who spend time
like fretting about, "is
this thing a controller?
Is this thing a model?
Is this thing a view?"
Just go for it.
Build stuff.
Go out there and make amazing
stuff you can always re-factor
it like we did here, not quite
live on stage, but pretty close.
You can always do that.
So just make stuff and you will
learn so much from doing that.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So just make stuff and you will
learn so much from doing that.
All right, so for
more information,
you can talk to my buddy, Jake.
There's also the DEV
[assumed spelling] forums.
Here's a link to those
related sessions I was telling
you about.
The talk this afternoon
on Advanced iOS Application
Architecture
and Patterns has tons of
fantastic stuff in it,
and it's got a little bit of
information about Swift and some
of the new patterns that
we're going to see emerge
because of the new language,
which I'm really excited about.
And then here are two other
talks from previous years
that have more information.
Thank you very much
for being here,
and I hope you have a great
rest of your WWDC [applause].
[ Silence ]