高級 3699 分類 收藏
開始影片後,點擊或框選字幕可以立即查詢單字
字庫載入中…
回報字幕錯誤
<
Stanford University.
Okay well, welcome to lecture six of
Stanford CS193P winter of 2015.
So today I am gonna do a little bit of
demo action right at the beginning.
I wanna show you a kind of a cool trick that you can do
inside your storyboard, and we also, last time,
didn't get to the point where we had actually a model for
our MVC, our happiness MVC.
We had worked on the face view and got that working but
we didn't have a model,
so I'm gonna just put that model in there, but then I am
going to jump right back into the slides and I am going to
cover a very important concept, which is delegation.
And I'll have to kinda go over Swift's protocol syntax, and
then I will do a demo to show you how delegation works,
then I'm gonna cover gestures, okay?
We know how to draw in our view now from last time.
So, now we're gonna then talk about how we handle gestures.
Pinches and pans and swipes and things like that.
And I think that'll probably use all of my time up.
But if I have a little bit of time at the end,
I'm gonna get started on the next major topic.
Which we're gonna spend most of Wednesday on.
Which is multiple MVCs, right?
We know how to build an MVC.
It's got a controller, it's got a model, it's got a view.
And now we're gonna build a bigger application by
combining MVCs, okay?
And that's critical, obviously,
to growing the capability of size of app you can build.
So I'll try and fit in five or ten minutes of slides for
that just to make sure we have more time on Wednesday.
Anybody have any questions about any of this?
All right.
So, let's dive into this demo first, before I talk about.
That, okay I am just going to bring up
happiness from where we left off last time.
And really all we had done here was the Face View,
we had not done our Happiness View.
In fact, if I switch over to our Happiness View controller,
you can see it is completely empty.
So one thing we're gonna do is
fix our model here but before we do that I'm gonna show you
something really cool that you can do in story boards.
So here we have our story board and it's pretty blank.
It looks blank there's this big blank square here.
This is our face view in here that I have selected.
You can see the little resize handles are selected but
I can't even really tell that's a face view.
It's hard to tell where it is.
It's just kinda hard to tell what's going on.
And it's actually possible believe it or not to have your
custom UI view subclasses draw in your story board.
Okay? So they can actually be
live drawing in your storyboard.
And it's really incredibly easy to do.
I'm just gonna go back to my face view.
Here it is.
And right before the class here I'm gonna say
at sign IBDesignable.
And if I put at sign IBDesignable in there,
then when I go back to my storyboard,
Xcode automatically notices that's an IB designable
class and it will draw it right here in the story board,
so now I can see much more easily what's going on with my
face view, where it is here.
And if I change something in my face,
like let's go change that smile so it's not a frown.
Whoops where is that, it's right here, minus 0.5.
Let's change that to plus 0.5.
Then you'll notice that this file has changed and
it will recompile it and redraw it.
Okay so you're always seeing the latest version.
Now another thing that would be really
cool here is just like if we have a button or a label.
When we bring up the attributes inspector here
we can edit attributes of a button or a label.
Right? Like its alignment or its font.
Well wouldn't it be cool if we could edit the attributes of
this face view here as well?
And we can do that too.
If we go back here to the face view here's some of
the things that are setable about a face view.
The line width, the color, and the scale.
And you can make any of these things editable inside of your
storyboard by just putting in here i b inspectable.
But I'd be inspectable before them.
Then interface builder,
which is the part of x code that is doing part of your
storyboard will create a new UI to make all those editable.
Here is our storyboard.
Now if you look over here you can see face view.
It's added things to be able to set these.
I can set things like my line width.
Maybe I want thicker lines.
Maybe I want a different color.
So we can go to the color chooser here.
We could pick green color or orange or something like that.
Tangerine.
It looks good.
And we can change the scale as well, too.
We can go down to 0.5, maybe we want to go 0.95, all right?
We can change that.
Now, these are not only changing here in
your storyboard, but they're actually setting the default
value so that when you run your application, so
let's go and run our application here.
It's going to use these values that are set in
the storyboard.
Just like if those were buttons or labels and you had
changed something about them in the inspector, it's going
to change the way it works in your program as well.
Yes, questions.
>> So that overwrites what's in your code?
>> Yes, so the question is does that overwrite what's in
our code?
So for example, back here.
We had equals three, we had equals blue color and
the answer is yes, it overrides it.
Basically, when interface loads it up it respects those.
It will use those but as soon as you start editing them,
then it's going to override them and
reset them to the editor value.
Any other questions about that?
Question?
>> Yes, so the question is are there some,
there's got to be some got-yous, or something.
Why wouldn't it just be the ideal design be the default?
And, yes, there are some gotchas.
There's certain things that, really, it can't do.
It can't load your code up, you might have dependencies on
other frameworks that it can't see, things like that.
So yeah, there are some gotchas,
I don't have time to go through them all but
I just wanted to show you that this is here for
most straight forward sub class UI view,
it works great without gotchas.
But yeah, there are obviously some times when it's not going
to work, because you could have a complicated view, so
any other questions about it?
That's all there is to know about that.
So let's go back to our model here, or
to our controller, and I want to put the model in here for
the happiness view controller.
So it's model, because this is demoed and
I want it all to be really quick and
you can even follow along with me, some of you.
This model's gonna be really simple.
I'm gonna have the model of and
a model you know the model is right?
Your calculator's model was a calculator brain so
it was a whole object that you created to be the model.
Here I'm gonna have my model be the happiness and
it's going to be the very complicated data structure of
an int.
Okay. So
we're gonna represent our happiness as an Int.
And I'm gonna start it out at 50.
And I'm gonna have my happiness mean 0 is very sad,
and 100 is ecstatic.
Okay?
So that's my model.
Super duper simple model, and don't get this model confused
with the smiliness in the face view,
that's a different thing, that's just the angle of
that arc in the face view, totally separate thing.
And you notice they're kind of on different scales anyways.
This is 0 to 100,
the smiliness is minus 1 to positive 1, etc.
And that's okay because one of
the things that controllers do, one of their jobs really,
is to interpret the model for the view.
Okay, or vice versa in what happens in the view.
And they have to figure out what to
communicate to the model.
That's a lot of what a controller does.
And so, we're going to have some coding here,
that does exactly that.
Interprets our 0 to 100 happiness into a smile or not.
Now there's other things that
represent happiness besides smiling.
You know, little crinkly eyes.
And other things that make you appear that you're happy.
But we're just gonna use our face view which only knows how
to smile or not.
Now one thing that we can do inside this model.
I put the curly braces here and
you might say why did I put that there?
That is because I want to use the property observer for
my model to, essentially, validate my model.
So you can use property observers to do evaluation,
really, of any property that you want.
So my happiness can only be 0 to a 100.
If someone passes me happiness minus 1 or
5,000 I need to kind of keep it in range to 0 to 100.
So I'm just going to say, in my setter here,
my property observer here,
I'm going to say min max of my happiness to 0 or 100,
so I'm just keeping it between zero and a hundred, right?
So no matter what someone passes me,
my happiness won't ever be outside of that.
Again, this is kind of a trivial example.
You might have a much powerful model that
needs much more powerful validation this,
but you can see this as a place to put it.
Another thing you might want to have here is if someone
updates your model, you might want to update your UI.
Okay, so I'm going to have update UI,
and I'm just going to have a function down here, update UI,
and it's going to do something to update the user interface,
and that's a common thing.
When your model changes,
you want your controller to cause the UI to be updated.
I think I'm going to put in here also is a little println
happiness equals back slash happiness.
Just so we can see our happiness changing in our
console all the time as we work the rest of the demos.
So we'll work on this update UI piece when we
get back to the demos.
I just wanted to show you the model of happiness.
Right now it's not hooked up to a it's UI.
So if I run my application,
you'll see that this is not happiness of 50.
This is not even looking at the happiness.
I could change this to anything that I want and
it's not going to change this.
And so later we'll show you how we hook up our UI
to our model through our controller,
that's one of the main things a controller does.
Okay, so let's go back to our slides though.
All right here, I'm going to start with this miscellaneous
topic here, kind of a bonus topic, which is extensions.
You read about in your reading assignments, so
you know what this is,
hopefully you've been reading those reading assignments.
But I'm discovering here in class,
not as much because it's an important feature per say but
it can be a little bit of a dangerous feature so
I wanted to cover it a little bit.
So an extension is really simple.
It's just a little syntax, to add methods and properties to
existing classes, structures, and enums.
Okay? You do not have to
have the source code to those things you're adding it to.
You could just add these methods and
properties pretty much at will.
There are some restrictions, one is that you can't add via
an extension a method or property that already exists.
So it's not a way to replace it, this is not sub classing,
you're not replacing or overwriting methods, so
this has to be something where the property or
method you wanna add to a class.
Does not exist.
The second thing is that any
properties you add cannot have any storage.
Okay so they can only be computed properties,
right the get, set, kind.
That's the only kind of property you can have.
Okay, but inside an extension otherwise it kind of
looks like you're in the definition of class.
You can refer to self if you want and
that will be the thing that you are extending.
It's a pretty powerful feature actually.
This feature is easily abused however people putting all
kinds of adding methods to classes making it so it's
completely not understandable of what that does anymore.
It's also whoever designed the class thinks a lot about it,
API and what should be in it and what shouldn't and
now all of the sudden things are being added.
That's kind of weird.
This is really best used for beginners like you
who are just starting with SWIFT to add little
helper functions to enhance the readability of your code.
Okay, so if there's something that it would be
really great if a cgrect could do this little thing, you
could add a little extension to a cgrect to do that.
Or maybe a UI view controller just once.
This extra little property that it can calculate
about itself.
That's the kind of thing that you could use it for.
Now extensions actually can be used by advanced Swift users
by architects, or
for architects, to really organize all your code.
Because you can
put almost everything into extensions, and
use extensions as basically groupings of functionality.
And so, it's really a powerful feature and
I don't want to make it sound like it's only for
little kinda drips and drabs and tiny little helper things.
It can actually be used as a core foundation of how you
architect.
But that does require some one to sit down and
have an architectural plan to do that and
you obviously a little early in the game to be doing that.
So I would say, when in doubt, if you're not sure whether or
not you should make something an extension,
don't do it for now.
And over time, you'll get more comfortable with it,
you'll understand what to do.
And again, the syntax for
it is all explained in the documentation.
Maybe in the demo here, I'll try and throw one in, so
you can see what it looks like.
That was just an aside,
now let's get back to the main guts, okay?
This very important feature called delegation,
I have to teach you about protocols first,
again you probably read about this in reading assignments,
but I want to go over it anyway.
A protocol is basically a way to express your
API a little more minimally.
Not to drag in so much API by, for example,
having an argument to a function be a class where now
you're passing an entire class into that function,
who knows what that function might do with that class.
It could access the entire non private API of that thing.
So really, the function just wants to use the one method of
a class.
Protocols are a way for
the function to express or really, I just want you to
pass me something that can do this one function.
Because that's what I'm going to call in here.
So, it's a way to kind of minimize your API.
A protocol is a type.
Okay, it's just like a class, or an enum, or a struct.
Okay. It's a type.
It can be used everywhere a type is.
A type of an argument to a function.
A var or a let can be a protocol.
Type. So it is absolutely a type.
The only thing that is interesting about it is it
has no implementation.
Okay?
In fact, it's kind of the definition of a protocol,
it's a type with no implementation.
It only has declaration.
Use a protocol to declare various properties and
methods but it has no implementation.
The implementation is provided by other objects that conform
to the protocol.
Okay, and there might be
hundreds of objects that will conform to a certain protocol.
Okay?
But the protocol when you use it looks just like a type,
exactly like a type as you're gonna see here.
Now there's three aspects to a protocol, to using one.
One is the declaration of the protocol.
This looks a lot like declaring your class or
an enum or struct.
It's just that there is no implementations for
any of the properties or methods.
Then there's the declaration part where a class or
a struct or an enum says, I will implement this protocol.
So it declares that it will conform to, or implement,
this protocol.
And then there's the part where that class, struct or
enum actually implements the protocol.
So, it implements that, all the properties and
methods in the protocol that's required, all of them.
Okay?
So we'll see what that looks like in some code.
So here's a declaration of a protocol itself, okay?
The protocol's called some protocol, all right?
This protocol has really what some might call
inherited protocols, or a protocol that inherits.
Which are other protocols that if you want to implement some
protocol you have to implement those too.
Okay that's what this colon thing, so
it kind of looks like this super class kind of thing but
there can be multiple of them, but it's not really
inherent in this, per se, like you think of in classes, it's
more just saying if you want to implement some protocol you
also have to implement inherited protocol one and
inherited protocol two.
If you don't implement those then you
haven't implemented all of some protocol.
Okay?
Now you have to specify, when you do a property,
you don't put the implementation there but
you have to classify whether this is a get only property or
it's a get and set, okay?
The system needs to know whether it's
a set because structs and enums are value types and
it needs to know when it's being mutated so
it can copy them and etcetera, okay?
Any functions that are expected to mutate also need
to be noted with this mutating keyword, okay?
You probably read that in the description,
you know that structs and enums,
insert value types, the system needs to know when a function
is actually changing them, so they can copy it on demand.
It is possible to limit your protocol to only work
with classes.
You put the word class right after that colon.
So SomeProtocol colon class means this protocol can
only be implemented by a class.
It cannot be implemented by a struct or an enum.
Okay? Then you wouldn't need
any mutatings because a class,
since it's a reference passed by reference all the time,
you can obviously mutate with any method or property.
Okay, you can even specify that
a protocol requires the class or
structure enum to implement a certain initializer.
Okay, that way you
know that you can create one of these things.
All right. So, that's kinda cool too.
All right, so that's how you declare a protocol.
See? It's pretty straightforward.
No implementations in here, right?
All right, so now let's talk about the part of it where it
says I'm an implementor.
I want to implement this protocol.
How do I tell the world I'm going to implement this?
You do that by putting at
the end of the declaration of the thing, so here's class,
SomeClass then it inherits from SuperclassOfSomeClass.
You just put a comma and all the protocols that
this class is claiming to implement, okay?
Now, obviously if this was a struct or
enum it wouldn't have that superclass name.
So it would just be colon and then the list of
all the protocols that it is claiming to implement.
So this enum says it's going to implement some protocol,
and it's also going to implement another protocol.
And once it says that, it has to do it or
the compiler will not allow you to compile, okay?
Same thing with the struct, all right?
So pretty straightforward syntax there.
The number of protocols is unlimited,
you can just keep putting more and
more protocols that you say you'll implement.
In a class, if you implement an init in a class,
you have to say it's required.
Okay?
So that's because you wouldn't want a subclasser
using the rules of inheritance of initializers which we
talked about in depth last lecture or the one before.
It can get to a situation where that init is
not even implemented, okay, in sub class.
And that would be no good because you're saying
you conform to this protocol and then that init is part of
this protocol so you have to make them required.
Okay?
You are allowed to add protocol compliance or
conformance with an extension.
And this is very common to do,
again, in a bigger architected system, is you will implement
the entire implementation of a protocol on some class or
structure enum by implementing it as an extension.
Now the only thing about that implementation is,
of course, no stored properties in there.
Only computer properties.
So you would have to be able to
implement that entire protocol without any storage.
But a lot of protocols can be implemented without storage.
Cuz they're fairly simple protocols, okay.
Here's what it looks like to use a protocol as a type.
So I've created a protocol called Moveable.
It has one function in it,
move to, which presumably moves the thing.
I've created two things,
a class called car which is a moveable.
So the car can be moved, and a class called,
or struct rather called shape which can be moveable, so this
might be a graphical shape that can be moved on screen.
Now you see that car and
shape are completely different kinds of things, but
they both could be moved, so they both could be movables.
And you can see that they both properly implement the movable
protocol and they both claimed implement movable.
Then I've created a couple of little variables here prius
and square which are just instances of car and shape.
Okay, so now let's look at some code.
I can create a variable called thing to move.
It is of type movable.
That's protocol, but protocols are types.
And I can set it equal to prius.
This is completely legal because a prius
is a moveable, right?
It implements the moveable protocol.
So I can set a variable that is moveable to a prius,
works great.
I can then say thing to move, move to.
Because thing to move is anything that implements
the moveable protocol.
However, I cannot say thing to move dot change oil, okay?
Change oil is a car thing,
it's not a moveable thing, okay?
So I can't send it to a moveable.
Even though, yes,
that thing to move happens to currently contain a car
it's still a compiler won't even let you put this in.
It'll complain.
It'll say, thing to move is a moveable.
Moveables don't understand change oil.
You understand?
I could then say thingToMove equal square.
That's perfectly legal as well cuz a square is a Moveable.
It implements that protocol so it can do it as well.
More interestingly I could let thingsToMove be an array of
Moveable, and I could set it equal to an array that
has a prius anda square in it.
So it's got a car and a shape, a class and a struct,
all in this array and it's perfectly legal because
they're both moveable so I can create an array of them
because moveable is a protocol It's just like a type.
It is a type.
Okay, make sense?
Why I can do that?
All right I can also have a function like slide,
let's say that slide something along the ground or
something, and you can take an argument which is unmovable.
And then inside of it I can say move to and
that works fine, and I say slide prius,
slide square, all works fine because.
They're all moveable.
It's actually possible to declare an argument like slip
and slide, that implements two, that takes an argument
that has to implement two separate protocols.
Moveable, but also something called slippery, let's say,
which I haven't defined.
Okay, so
this little thing where you say protocol angle bracket and
then as many protocols as you want closed angle bracket,
that says this argument to this function has to implement
both of those protocols.
Or all of those protocols.
And then if I tried to say slip and
slide Prius, not even compile.
Because while Prius is a moveable,
it's not as slippery.
And so it can't do that.
Can't be passed through that argument, okay?
Everyone cool with protocols?
Any question about that before I
start talking about delegation which uses protocols?
Okay. So
delegation is a very important use of protocols.
Delegation, if you remember back to our MVC talk right at
the beginning of the quarter, we had this big graph.
And one of the things we showed was how views need to
be able to talk back to their controller, okay?
But views are generic.
So, they can't know anything about the class or
the controller that's using them.
They're generic building blocks.
Okay? So how do they talk back?
Well, it turns out they talk back using protocols, okay,
and this is called delegation.
Okay?
So, let's talk a little bit about how that works,
how it plays out to do delegation.
First, you're gonna create the delegate protocol.
So, the delegate protocol is just gonna be protocol,
something with a bunch of methods and
perhaps even properties.
And it's going to describe what the view is looking for
someone else to do for it.
Okay?
It's gonna describe the responsibilities the view is
going to delegate to someone else.
Okay? So if this is a scroll view,
something the protocol might be, should scroll to point.
The view wants to know should I scroll to this point?
The user's trying to scroll to this point.
Should I do it?
And the view doesn't know because it
doesn't own its own data.
It doesn't really even know what it's scrolling on.
It needs to ask someone else.
So it's going to create this protocol.
Any time it either needs to notify someone else to
something interesting that is happening or
ask someone else for permission to do something or
to try to get its data, which is a common thing.
It wants its data that it's trying to draw but
it can't own its own data.
Remember views can't own their data,
the data is owned by the controller.
Really, it's probably in the model, but
the controller is responsible for dishing the data out.
So at first you're gonna create that protocol.
Then you're gonna create a property in your view,
okay, called delegate or sometimes it's called data
source if it's delegating the data.
And the type of that property is
this delegation protocol that you're gonna create.
Protocols are just types so
that's what the property type is gonna be.
Okay, then it's gonna use that property to go do all
the delegation.
It's going to send a message to
the delegate property saying, should I scroll to this point,
it's going to send a message to this delegate property.
Maybe it will be called data source in this case, but
it's saying hey, where's my data?
Give me more of my data.
Okay? That's what it's going to
send and it's going to send it to this object right here,
this delegate property.
And this delegate property, all it is is a protocol.
So all that, anybody who implements that
protocol can be set as the value for that.
Delegate.
All right then the controller is going to come along and
it's going to first say that it implements that protocol.
Okay, so it's a class thing, it's going to say, yeah,
I implement this view this delegate protocol.
Then the controller is going to
set it's self as the delegate.
So it's going to set that delegate property inside
the view to itself, which is fine because it just said it
implements that protocol, so that's good.
Then, of course,
the controllers going to have to implement the protocol, and
implement all the methods and properties required by
the protocol so that it conforms to that protocol.
Otherwise compiler is going to complain.
And you're good to go.
Now the view is hooked up to the controller, okay?
But the view still knows nothing about the controller.
It doesn't know what class it is.
It doesn't know what its purpose in life is.
It knows nothing.
All it knows is it implements the methods in its protocol,
in the views protocol.
That's all it knows and that's all it needs to know.
Okay? So that keeps
the view completely generic and allows the controller to
have complete control of this generic minion in its view.
Remember the view is the controller's minions,
it's how it's communicating with the user.
So that's how we do it.
So let's take a look at a demo of doing that in happiness.
We're going to have
the face view delegate getting its data.
Its data is basically its smiliness,
how much smileyness is going on.
It's going to get that from the delegate.
And, of course, the happiness view controller is going to
be the delegate it gets it from.
>> Okay.
Well, let's now use delegation to hook up our
face view to our happiness view controller.
And we're gonna do that by
starting here in the face view.
We're gonna go through the same steps we
just talked about in the slides to do delegation.
So remember the first step is that we need a protocol,
some particular way that the face view is going to talk to
whoever's going to provide its data, and
the face view's data is really it's smiliness.
So the face view has this data.
Now this is a very, very simple data.
Probably in real life if this weren't,
you know a demo where I'm trying to show you delegation,
you would probably just set this, you
can't own it's own data, it's such a simple piece of data.
But we're going to use delegation to
get this piece of data here.
Rather than have it be set right here.
All right, so
we need some sort of protocol that gets this smiliness from
someone and, so we're gonna type in here protocol and
I'm gonna call this protocol.
That I'm developing my face view data source protocol.
And sometimes we call these delegation protocols delegate.
Like face view delegate.
But when the only purpose of the protocol is to
get the data that the view is going to draw.
Because the view can't own its own data,
then we often will call the protocol datasource.
So this just needs to have whatever functions and
properties are required to get this used data.
Well such a simple view that it
just needs something to get the smile in some function so
I'm going to say smiliness for face view.
I have an argument here which is the sender.
Face view.
And this is gonna be myself.
So when I ask somebody else to provide my data by
sending them this message.
I'm gonna pass myself, this face view,
along as an argument.
And you'll see all throughout iOS when they have
a delegate or a data source.
They are always going to pass themselves along.
If you are trying to provide the smiliness for
this FaceView, you have a point or two to FaceView.
You know, which FaceView is asking you that, and
maybe if you need to ask the FaceView some other
questions to answer this, you can do that.
Now, this smiliness what is it going to return?
Now I'm going to have it return a double,
which is going to be that smiliness,
remember that smiliness goes from a plus 1 down to minus 1,
plus 1 that's very smiley and
minus 1 that's very frowny and so we made that double.
I'm also going to make this double be an optional.
And that's because if the data source, if I ask it for
the smiliness, and for
some reason it can't provide that smiliness, then I'm gonna
allow them to return nill, and just have no smile or
no frown, just flatlined mouth there.
Now we only by the way pass one argument here.
But we could definitely, if we were asking our data source,
we could have some more arguments in here.
And so that's perfectly reasonable.
You can have as many arguments as you
need to get this smiliness out of the data source.
Okay, so that's step one, we have this data source here.
Step two is we need to have a public var in our face view,
which I'm going to call dataSource, and
it's going to be of type FaceViewDataSource.
Okay?
I'm going to make that an optional as well.
So you can see here that I'm using FaceViewDataSource,
which is this protocol, just as a type.
And what this means is,
somebody who wants to provide my data,
who wants to be my dataSource,
all they need to do is set themselves as this variable.
And then I'm going to talk to them through this variable to
call this function on them.
Okay?
Now, why did I make this an optional here?
Because it's possible that
I can just live without a data source.
I will just always have a flat line, a flat mouth.
I won't be smiling or frowning.
And so this can be allowed to be nil.
Okay, now normally, this is not going to want to be nil,
because we don't want a face with no frown and no smile.
But, we'll certainly allow it.
So, allow that there.
Now one other thing we have to do about this data source here
is we really want to describe it as weak.
Now this is gonna be the first time we talk about
memory management in this class.
And really the memory's just been
managed automatically for you.
But here we have to be a little bit
careful with the memory management of this pointer.
Because, for example,
our controller is going to set itself as the data source.
So it's going to set this pointer back to itself because
our controller's going to be a FaceViewDataSource.
And, unfortunately, the controller also has
a pointer to this FaceView through the view hierarchy.
Because it's gonna have some outlet to the face view, and
so they'll be pointing to each other.
And since they're pointing to each other they're keeping
each other in memory at all times, so
that kinda memory cycle is really bad.
Because then the FaceView and
the controller can never leave memory.
They'll be stuck in memory forever.
So, by making this weak, if we put weak in front of a var
pointer it means that this pointer, this thing, whatever
this points to, should not be used to keep it in memory.
So the controller is gonna set itself as this data source.
This pointer, since it is going to be a weak pointer,
is not going to keep the controller in memory.
So the controller will be allowed to go out of memory.
And when it goes out of memory,
of course the FaceView loss will go out of
memory with it because its entire view hierarchy,
the controller's view hierarchy will go out as well.
And now you can see that we have an error here, okay?
And this error says weak cannot be applied to non-class
types, okay?
So FaceViewDataSource is a protocol, not a class.
So FaceViewDataSource could be an enum or
a struct and that's a problem because we really need this to
be weak because we
don't want that cycle things pointing back to each other.
So, we can actually make FaceViewDataSource, even
though it's a protocol, we can make it be a class type.
If you remember from the slides in our
protocol declaration, we can say colon class.
And that says that FaceViewDataSource can only be
implemented by a class, it cannot be implemented by
a struct or an enum, and that's perfectly fine and
usually that's what we're going to want anyway, but
we definitely need that so we can have this weak behavior.
So this data source, the pointer it has to whatever its
data source will not keep it's data source in memory.
As long as the dataSource is in memory,
this pointer will be good.
As soon as the dataSource goes out of memory then this
pointer will be set to nill automatically by the system.
So it's pretty cool, these banners are pretty cool.
We don't use them a lot you saw that we used them for IB
outlets and this is the second place that we have used them,
which is for delegation.
We're always gonna use a weak var when we have delegation.
Okay?
That just requires that we make our protocol,
you only work for classes.
All right?
Okay? So now we
have this nice data source right here.
Let's go ahead and go to the next step,
which to use the data source to get our smiliness, right?
So we have our smiliness right here,
it's currently at constant minus 0.5, so we're going to
get it from the data source by just saying to the data
source, please give us our smiliness for FaceViewSelf.
Okay?
Now when I type that in,
Swift automatically put this question mark here.
I didn't type that.
It put it in here.
Why did it put here?
Well it put it here because data source is an optional.
And it could be nil, okay?
This is an optional, it could be nil.
And so Swift is assuming that we wanna use optional
chaining here.
And just, if this is nil, then this whole rest of
this expression is gonna be ignored.
This whole thing would be nil.
And smiliness here would be set to nil, okay?
But smiliness, you can see this error here is
because smiliness, it can't be nil.
It has to be a double.
So we're going to use another cool little feature switch.
Swift which is the question mark question mark operator.
Now what this operator says is,
if the thing on the left-hand side of the question mark
question mark is not nill, then use that.
But if it is nil, then use what's on the righthand side,
and to the right hand side I'm gonna put 0.0.
So what that says is that if the data source is nil,
then we're going to use smiliness of 0,
which is not a frown or a smile, it's in the middle.
Now this is also gonna be working if
SmilinessForFaceView happens to return now because you
remember it is also an optional double right here.
So that'll work perfectly fine there as well.
So whether this returns nill or
whether this is nill, invalidating the rest of this,
we're gonna get no smile or frown.
So this is a cool little operator [INAUDIBLE].
Okay, so we've got our face view doing its part.
It's declaring this nice property,
this protocol right here.
It's got a property which less people set themselves as
the data source and
then it uses that data source to get its smiliness.
All right, so
now let's go back to our happiness view controller.
Okay? The controller has to
implement the other side of delegation.
Now you remember one of the steps it has is it has to
say to the world, I am HappinessViewController and
I implement the FaceViewDataSource protocol.
And it does that by just saying FaceViewDataSource.
Now as soon as I put this on here,
I'm going to get a warning right here,
an error that says,
HappinessViewController does not conform to that protocol.
And indeed it doesn't because we do not implement
that smiliness by anywhere in our class.
So, easily fixed though.
We go down here, now, since, we've already told it,
it implements this.
If I just start typing smiliness it's going to
automatically know to escape complete.
So I'll hit Tab.
I've got my nice method here.
So how am I going to implement this protocol?
Okay, this method in this protocol,
how am I going to implement that?
Well the happiness view controller is going to
interpret the happiness here.
Which is the model.
This is the happiness view controller's model.
It's gonna interpret this for the view, because the view
doesn't know about happiness, it only knows about smiliness.
Smiliness goes from 1 to minus 1.
Here, we're taking about the model which is happiness that
goes from 0 to 100.
So it's a typical job of the controller to
interpret the model for the view.
You also interpret the view for the model and we'll see
that a little bit later when we talk about gestures.
But, here we're going to interpret the model for
the view.
So, I'm just going to return.
Now, happiness is an int, and smiliness is a double, so
I am going to have to convert the happiness.
Also, the happiness is on a scale of 0 to 100, so
I am going to do minus 50.
Divide by 50 to convert it into that plus 1 to
minus 1 scale.
So here I'm just interpreting the model for the view.
Make sense?
Now the last thing that needs to happen here is
that the controller needs to set itself
as the data source of the FaceView.
Let's all go back to FaceView,
I'm going to show you a nice trick here.