Stanford University.
>> Okay, well, welcome to Stanford CS193P. This is
spring quarter of 2016, and this is lecture number 2. And
today, we are going to talk about MVC, okay, I'm gonna try
and really briefly cover that because I know only about half
of you know what MVC is, and it's a very important part of
doing any iOS development. And then after I'm done with
that, I'm gonna continue the demo from last time,
we'll use MVC and learn yet some more things about Swift
and Objective C, all right? All right, so MVC, what is it?
As I mentioned last time, it's essentially a way of dividing
up your application or your source code into
three different camps, okay? The three camps pictured
here are the model camp. The model camp is what your
application does. Okay, nothing about how it's
drawn on screen or anything like that, okay.
It's not how it's displayed, it's just what it is.
So for a calculator app, what it is it's a calculator,
so the model is probably gonna be the part that
does calculating, okay.
Next piece is the controller. The controller is how your
model is displayed on screen. Okay, it's kind of the how.
This is basically all your UI logic, goes into your
controller, all right? And the view, you can think of as
your controller's minions, okay, the things that the
controller's gonna use to put things on screen. So
that's buttons and labels and tables and all those kinda
things that the controller needs to display what's
in the model and to get input from the user
to update the model as well, okay? So
those are the three camps. Now it's one thing to
decide where things go based on the description
of the camp, but a really important piece of it is the
communication between camps, what's allowed,
what's allowed, what's not. And when communication is
allowed, how do you do it, okay, in iOS? How, how is that
communication facilitated? So, to help with this, I've
kind of, drew, drawn here this little Y in the middle. It's
kinda like road signs, okay? It's like double yellow at the
bottom there is don't cross. And then solid white is yeah,
you can cross, but you're not really supposed
to generally do this without being very careful. the traffic is going in
the same direction, so you can pretty much crossover. Probably wanna put
your turn indicator on, but off you go. Okay, so let's
talk about how that works for these three camps. First let's
talk about controller talking to the model. The controller
can talk to the model all it wants. It knows everything
about the model. It can send any message
it wants to the model. The controller is in complete
control of the model. Okay, and the controller needs that
because the controller's job is to present what's
in the model to the user or to get information from
the user and update the model. So it needs full control, so
that's a full green arrow, dashed white road sign, road
line there can do anything at once. Same thing on the other
side, the controller obviously needs to be able to use its
minions however it wants to display the model. And most
of the time, the connection between the controller and
its minions is via an outlet. And you remember we had
an outlet on Monday, right? It was the display? You remember that, it was
a var instance variable. Display with an optional UI
label. And that connection is how the controller was
talking to it's view. That label, that UI label
was part of it's view. It was a minion in it's view.
So that's full green communication,
kind of do whatever it wants, controller knows everything
about both sides. It has to. Let's talk about
the model in the view. Those never speak to each
other. Why is that? Simple, the model is UI independent, so there's absolutely nothing
it has to say to the view, which is completely
UI dependent, that's all the view is.
The view is just the minions of the controller. And so, you
know, it makes no sense for these two to talk to each
other. So that fire, that's double yellow line, don't ever
do that in this class, okay? No communication there at all.
Okay, all communication in the model, in the view goes
through the controller. All right, what about from
the view to the controller? Can the view, like a label and
stuff like that, talk to its controller?
Well, yes and no. The problem with
the view is all the minions in there are generic objects
like UIButton or UILabel. Those were written
by Apple years ago. They know absolutely
nothing about a calculator. So there's way to kind of for
them to talk to a calculator and know it's a calculator.
Okay, so there's limited communication between the view
and the controller. But off course the view needs to
talk to the controller because it's the controller's minions
and things happen in the U.I. and need to tell the
controller what's going on so. The kind of communication we
have there has to be blind and structured. Blind meaning the objects in
the view don't know what class they're talking to. 'Kay? Cause view, buttons don't know
anything about calculator view controllers. And
it's structured because since there is no knowledge
of the Objects on either end. They have to communicate in a
well-defined, pre-defined way, okay. So let's talk about some
of those structured ways that the view minions talk to
the controller. One of them you learned last time is
target action, okay. So target action's very simple,
the controller hangs a target on itself by defining a method
with at sign ib action on it, usually, in Xcode, so that little dot will work,
okay. And then the view when it wants to
talk to the controller simply calls that method and
that connection. Okay. The action being sent,
from the view controller, is wired up usually with
control drag. You saw us do that. It can be done in code.
But 99% of the time we control drag to create this
target action connection. So there's an example. Very
simple communication between. Menu in the View like the UI
button and the Controller, the other method. Okay? Simple
one. All right, what else, what other kind of
communication we had besides Target action? Well,
sometimes the View needs to communicate something a little
more complicated than just I was touched or something
like that. Okay. For example, it might be a school view,
that's a generic view minion. And it might need to
tell the controller, hey, this guy just
started scrolling. Okay. Or the person zoomed into
this zoom scale. All right. So let's notify the controller
cuz the controller might need to know that and
react to that, okay. Maybe it effects the model
when you zoom in or out. Also maybe the view like the
scroll view needs to make sure it's okay to do something,
like if the scroll view says should I allow vertical
scrolling right now? Maybe it wants to ask the
controller that. So you have a lot of messages that have
words in them like should, will, and did, okay?
That the minions wanna ask questions of the controller
involved with controller. Okay? So, [COUGH] This is
done via what's called a delegate. And we're gonna
talk about delegation next week. And the word delegate
is appropriate here because it's essentially the view's
minions are delegating some responsibility to the
controller Okay. The way this is implemented is very simple.
Delegate, the delegate is just a property in the view and
that property, you might ask, what's
the class of that property, because the view doesn't know
anything about the calculator view controller. The answer
is, it's not gonna be a class. It's going to be what's
called a protocol. Okay, and we're gonna talk about
what protocols are. Protocols are basically just
a description of a bunch of methods that the other guy
promises to implement. Okay, and so if you can imagine
if the controller would promise to implement
these will, should, and did things, then the viewer could
talk to it even if the view doesn't know what class it is.
Okay, no similarly There's an important aspect of
MVC which is the views, okay, the view can not own the
data they are displaying. Now, how are they going to display
it if they don't own it? Well, they're going to ask for
it from the controller all the time and the controller
is going to get it from the model. Okay, so that's
another kind of protocol but instead of will did and should you've got messages
in that protocol like give me the data at this location
and how many pieces of data are there, okay? Things that
are asking about the data so the viewer can figure
out what's going on and display it, okay. And that's
also done with delegation, although we call that Delegate
the Data Source. Okay, so there'd be another property
on some views called the Data Source, which is
this protocol based pointer, basically, to
another object and the controller sets itself as
that so it can get involved. And providing the data for
the view. Kay? So those are the ways
that the view can communicate to the controller. You can see
they're all pretty defined, well-defined ways they're
not just open ended. Mkay? Now, this leads
to a situation where the controller's job can be
described as interpreting and formatting the model data for
the view. Okay. It also interprets view
input for the model. So it's an interpreter
between both. That it, controller job so that's
really where all your UI logic is in there. Okay,
how bout the model? Can it talk directly
to the controller? Absolutely not because
the controller is your UI logic. The model is UI independent.
So there's absolutely no way the model could have anything
to say to the controller. However, what happens
if the model, which is UI independent,
has some data that changes, okay? So it's maybe the model
is representing data on a network. In some ways change
is gonna be on the network and it's changing. How does the
model let the controller know? Well, to do this we use what
we call a radio station model, okay? So the radio station
is just a thing that the model can set up, set up its own radio station. And it broadcasts on that
radio station whenever, whenever anything
interesting happens. Okay, and then the controller just
tunes in to that station. So the model is not really
talking to the controller. It's just talking to
anyone who wants to know. What's going on in the model.
Now all that communication on that rad, radio station since
it's done by the model has nothing to do with UI. It's
about the data in the model. I have new data,
my data changed, those kind of messages are going out on
this radio station, okay? Now other greater stations can
be worked between other camps besides the model and
the controller, and some have asked, hey, can I
just create a view that tunes into the model directly, and
short circuit the controller? And the answer is no, you
don't wanna do it that way. Okay? You would want to have
the controller tuning in to the model. And
having the controller set up this generic view thing
to display the data. Question? [INAUDIBLE]
Standpoint, it's easy to understand the controller view
log model just like your idea of how this things
implemented in the software? >> So the question is, so it's easy to understand
what the controller and view are,
they're displaying the UI. The model is less easy
to kinda conceptualize, what that is, so what is
the model? Really the model it takes a little more design
but to design the model you have to think about what is
it my app does fundamentally, independent of how it would
be displayed. Like imagine I wanted a calculator and had a
command line interface where I could type five times
three equals and it would work. Okay, well
that's a user interface but the calculation, the actual
multiplication and stuff, that would be in the model.
So the model is more about trying to understand what it
is your application does, not how it's displayed. That's
the separation that we have to do in this design.
>> So it's kind of like an algorithm?
>> Yeah, it's more of the algorithms,
the data, the databases and stuff like that are more in
the model. And you'll see it by experience. we'll deal
with the calculator today and you'll get an example how
that plays out. Okay. Now, this all only builds
one MVC, okay? One MVC, generally an iOS,
controls one iPhone screen or maybe on an iPad
it's two pieces or three different pieces on the
iPad screen. In other words this is only controlling
a little part of your app. To build a real app we
have to take these MVCs, make a whole bunch of them and
then combine them, okay? That's how we make a big app,
all right? Now, when we do that, it, it's still important
that the communication is well defined and basically the MVC,
an MVC can only serve as part of the view of
another MVC, okay? Do you see how this
is arranged up here? If you look at any of the
purple controllers up there you notice that any arrow
they have to another MVC goes out that view side, okay?
So we always wanna think of these MVCs as part
of the view of another MVC. And there are some MVCs like
tab bar controller that's an MVC that's provider iOS.
Where you might have three or four other MVCs as part of its
view. And those are the things when you press on
the tabs at the bottom, you see a different MVC,
right. So, that's what we built
app at four MVCs let say, one of them is the top
level tab bar controller. And then we have let say,
three other MVCs. And those three MVCs might do
completely independent things and as we build this we really
want each MVC to be completely self-contained, just
like when we design objects we want them to be
completely self-contained. We don't want them reaching into
the internal implementations of other objects, right? So
and sometimes we're building an object orient system
here out of MVCs as well. Okay, now you'll see how all
this works in week three. We'll start doing multiple
MVCs and it'll all make sense. Okay, one thing we don't
wanna do of course is build something when MVCs are
[LAUGH] not working together. If these arrows start
going in every which way direction then there's
gonna be now way to understand how your app works once it
gets to a certain complexity. It's just gonna be beyond
your comprehension. Okay, so, we don't want this.
This is bad. All right, so the demo I'm gonna
dive right into here. Again, this is a slide
you can look at later, important things that I'm
gonna cover in this demo. Cuz I'm not coming back to
the slide so let me summarize, what's coming up? On Friday,
we do have this debugging, session.
It's at 1:30 in this room, okay? I highly recommend
you go to that, especially if you've never
done debugging in Xcode, cuz you'll kinda be wondering
how the heck it all works otherwise. Next Monday we'll
be talking about more Swift, that's when your first
reading assignment is due and your second reading
assignment will go out. And then next Wednesday we're
gonna start about talking about custom drawing in iOS. What if we wanna not just use
a button and a, and a label, but we wanna draw our own
stuff? And that's when programming assignment one
will be due before lecture and programming assignment two
will go out after lecture. Okay? Any questions, you all ready to jump in this
demo? All righty, here we go, I'm just gonna pick up right
where we left off with I'm gonna go to developer here
as our calculator, all right. I'm gonna,
when I wanna relaunch it, I could just launch and get
the splash screen here. And then, click on this to
open it and here it is and the, before, if you remember
where we were, we only had a pi button and then the
keypad. That was great and now we wanna add more buttons, and
that's what we're going to do. We're gonna add
more operations and more sophisticated operations,
like multiplying and things like that. Before I do that I wanna talk
a little bit about a feature in Swift that can really make
your code read a lot better. You notice here that we
have this type conversion. String and pi, right?
Where when the pi button gets pressed, we have to convert pi
to a double which is a string. Well if I think ahead about
all the operations I'm gonna wanna add to my calculator
there all doubles, everything is doubles,
not strings, okay? So am I really gonna have for
all these operations, all kinds of converting back
and forth between strings and doubles as I try to put the
results into the display or get the number out
of the display? That is gonna end up
being really tedious, okay, and it's gonna make
my code kind of a mess, lots of type conversions
back and forth. Wouldn't it be cool if I had a
var called Display Value which was a double, and this bar
automatically tracked what was in that display?
In other words if I ever got the value of this, it would
be the value of the display as a double. And if I ever set
the value of this, it would set the display. Wouldn't that
be cool? Right, that would make all the rest of my code
a lot easier because I would be all in double land and Is not having to be doing
this string version? And the answer is we can
absolutely do that kind of var, a var that tracks
something else, okay? This var, our user is in the middle
of typing, is just stored. That true false value is
stored somewhere with this object. This one, instead of
being stored, it's going to be calculated, okay? And we call
this a computed property. And we do it by just putting
curly braces after it, okay. And inside this curly braces, we're gonna put some
code to calculate the value of this property.
Both when we get it, okay. And when we set it.
So, we have this get and set, keywords here. And inside
here, we just put code to get the value of display value.
And set is the code that gets executed when someone tries
to set the value of this var. Okay? Super simple. So, what's
the implementation of this? Really easy when someone tries
to get the display value I'm just going to return
the display's text. Okay? Unwrapped, but of course, this
is a string. Right? Okay? And this is supposed to be
returning a double. So, I need to convert this string
to a double. So, I'm gonna say double. That, okay, now this
is still not gonna work, okay? Why is that? Let's
look at our error. It says the value of optional double
is not unwrapped. Look it's trying to unwrap this. Okay,
that's really weird. See it's pointing an exclamation point
at the end of this double. I didn't have to
do that down here. When I converted from this
Double to a string, I didn't unwrap it. Why is this?
I'm trying to create a double here using this string. Why do you think this is
returning an optional double instead of a double?
>> Because it might not be convertible.
>> Correct. It might not be convertible.
Right? If I press hello in there as the string. Double of
hello, eh, I don't know. Okay, now again it could return
zero or something else but really it wants to say,
I don't know. I can't do it. And the best way to do that
is with an optional. So, some constructors. Okay? Some of
these initializers for various classes can return optional
versions of the thing. In the case where they can't
necessarily create one for you. Okay? So
that's really kind of awesome. So let's go ahead and unwrap
that. Okay now this would, again, this would crash if we
ever put hello in here, it's gonna crash. So, we're kinda
designing our codes assuming this is always going to have a
number. How about setting it? Okay? Here we want to
set the display's text equal to what the person is
setting the display value to. Okay? When someone sets
the display values they're going to say in their code
display value equals five, right? So, how do I get
the five in here, in this set? And the answer is there's
a special key word called new value. Okay? This new value is
going to be the double that somebody set. Okay? Display
value equals something. Now, I want to put this in
display text, but, of course, this what type is this right
here? The double, right? Because they said display
value equals something and it's a double. And this
has got to be a string. So I've got to convert this to a
string. Just like I did below. That, okay, can always convert
a double to a string so there's no optional,
stuff going on. And that's it, okay. I've
now invented a new property, that is calculated.
And every time I ask for its value I'm gonna get what's
in the display's double. And every time I set it, it's
gonna set the display. Pretty cool? And it makes our code
like down here a lot better. Instead of having this go down
here, we're just gonna say displayValue = Pi, okay?
We don't need to do this type conversion in reference
displayed text, okay? Everyone understand that? And,
this is going to make it a lot easier to add new things.
Let's add another property, or a another, operation here. I'm
gonna add square root, okay? So let's go here
into square root. The square root symbol I'm
gonna get from the edit. If you go into edit menu of
most Mac apps you'll see this emoji and
symbols thing at the bottom, brings up this, window or you
can have a lot of emoji, but you can also have math symbols
and, down here here's square root. Just the square
root symbol, okay. So I'm gonna put the square
root symbol on this button. Square root. Okay?
And, then it's already wired up if I hold over here you can
see it's hooked up because I copy and pasted the pi button.
We can see it's okay here because I didn't copy and
paste the digit button. If I right-click on it we can
see that it's only gonna send perform operation, right,
so that's all good. And all I need to do here is
say if the mathematical symbol equals, that square
root thing then the display value equals the square
root of the display value. Okay? So, you can see that
this code is really nice. If I didn't have that I would
have had to get the display text, convert it to a double,
do the square root, convert it back to a string, and
put it back into display text. See how that would
have been a mess? Okay? And, this is only just
the very first one I added. If we add a whole bunch more
it's gonna be even more and more leverage to
have this thing. But mostly I'm showing you this
because I want you to see what computed properties look like. We use them all the time in
Swift, and we're going to use them yet again in this demo,
and you should get comfortable with the fact that not all
your properties are stored some of them might be computed
like this. All right. I want to add more operations
now, but I have to be careful here because this code
really does not belong in my controller, okay? Because this
is the code of what my app is. It's a calculator and I'm
doing calculations here. So, this needs to move
into a model class. Okay? So now,
it's time to do MBC here and move this stuff into
a model class. So, what's our model class gonna
look like? Let's create it and kinda design in an API for
it and then we'll get back and use it here. Okay?
So, to create it, okay, in fact to create any new file in
x code, you're gonna go file, new File. Okay? File, new
file. And when you go here, it's going to say, what kind
of file do you want to create? And of course, we want to
create an iOS Source file. Okay? Not watch OS or
something. And here we're going to create
a Swift file. If we were creating a Cocoa Touch Class,
like a new view controller, we would go here. But if we're
going to create just a model class, we go here.
So I'm going to double-click. It's going to say where
do you want to put this? I'm going to put it in
the same group, calculator, that all my other
swift files are in. You see,
ViewController.swift there. I'm going to call it
calculator brain because it's going to be the brain
of our calculator. It's going to be the model for
our calculator. Then click create. Here it is
right here. You can see that the very first thing,
it imports Foundation, not UI Kit. Never import
UI Kit in a model file because the model is UI independent.
So it would never do that. If you find yourself importing
UI Kit, you're doing it wrong. Okay? So, Foundation is what
we want. Foundation is that core services layer,
kind of the basic stuff, non-UI. Base stuff.
By the way, let me show you how you can put
different things on each side. So I've got calculator
running over here, what if I wanna have my
controller still be over here? And you do that with these
things at the top. Okay? The top line here is actually
changeable. You can pick other things to show. So, for
example, I can go show my controller here. Okay,
now I can have them both on screen at the same. Which is
kind of convenient, especially if I have a class that I'm
using in another class. I can see its API here, and use
it over here. All right, so I'm going to create a new
class called Calculator Brain, and we know how to do that.
Right? We know how to do that. Okay, class Calculator Brain.
What's its super class? No superclass, right?
CalculatorBrain, this model, it doesn't inherit
from anything. It doesn't need to inherit
from anything, okay? So it's just a base class.
All right, now let's talk about what its API is.
Everyone knows the phrase API, I hope. That means the
interface through which we're going to be programming,
using this, CalculatorBrain. It's all the methods and
properties in it. So, I'm gonna do a little
function called setOperand, okay, which just takes a
Double, okay? That's gonna be part of it. So if I'm using my
CalculatorBrain, I'm gonna set an operand. Then I'm gonna
have another function in here, called performOperation,
which is gonna operate on that operand. And the argument
there is gonna be a String, which is the mathematical
symbol, okay? And then lastly, I'm gonna have a var, which is
the result of the operation, which is gonna be a Double. And I'm gonna do something
interesting here, instead of just having this be a public
var that could be set and got. Because the setting of this
doesn't really make sense for anyone using my
CalculatorBrain to set this. I set it internally, okay,
because of performOperation. So I'm actually gonna
make this computed and only implement the get
side of it, okay? I'm not gonna
implement this set, so now this becomes a read-only
property. Do you, do you all remember another a read-only
property we used last time? Current title in button, okay?
So current title in button is a computed read-only property
in button. That title, that current title, is probably
gotten from a UI label or something that the button is
using to draw its title, okay? It comes from somewhere else,
that's why it's computed, okay? So I'm gonna do the same
thing here. So this is how you can make a property be
read-only to the callers, okay? Yeah.
>> So can we use the get for comparison, not just for
assignments, like with equal equal sign?
>> Okay, so the question is, is the get
used for comparison? Well, comparison is actually
quite interesting in Swift. The equals equals operator
is like a function, and it takes those two
sides as arguments. And those two sides have to
implement certain methods if they wanna be comparable,
okay? Now, we're not, we're not far
enough along in terms of our understanding of Swift to see
exactly how that works. But the answer to your
question succinctly is no, the get really doesn't have
anything to do with equality. Equality is just a function
that is different, okay? All right, so,
I'm gonna return 0 for right now, okay? Just to get
rid of my little, error there. But eventually, we're gonna
have to implement this, internally and make it work. Now, I wanna talk a little bit
about APIs right here, okay? So far, every method and
property we've done in this whole class has been
essentially public. Meaning, any class can call any of the
methods in any of the classes we created. For example,
all of our controller vars, okay, and functions could all
be called by some other class. Now, that's bad,
okay, that's bad. For example, displayValue, we wouldn't want some other
class setting the displayValue in the calculators through
this controller. Because we managed that displayValue by
what our model calculates, right? So this is
internal implementation. In fact, all of this is
internal implementation or control. We do not want other
classes to be able to call it, unlike these three, which are
external, okay? They're, they, we want people calling
these in CalculatorBrain. That's how our
CalculatorBrain works. If people couldn't call this, they couldn't even use
the CalculatorBrain. So how do we specify that
difference between something that should be called by other
people or not? We do that with the private keyword. So
I'm gonna add private, okay, this private
keyword right here, to all of my functions and
methods over here. I don't, this is not really
part of Swift again, this is kind of
an Xcode thing, so I put it after that.
But otherwise, you put it there, and we're
gonna put it for all of these. We're gonna make all
of these be private. And as you program, okay,
you're gonna see that one of the evaluation criteria on
your homework is that you properly make things private
when they should be private. And I generally would err on
the side of making it private. It's a lot easier to make
something private and decide to make it public,
than to use something public, go back later and have a whole bunch of
coders start using it, and then decide, no, no,
I want that to be private. Then you break all those other
people. So err on the side of private first, and then
making things public, okay? Now, it's actually possible to
look at something and see what its public interface is by
going up here to the top and picking Generated Interface.
This will show you the public API of the class in the main
window on the left there. So we're gonna look at the
public API of CalculatorBrain. You can see that it has that
setOperand, performOperation, and result. Notice this looks
just like current title, right, where it's saying
this is a read-only thing. We don't see any
implementation here, this is purely the API,
okay? So no implementation here. Also
notice this says internal, you would think this might
say public, okay? But there's actually a slight difference
between internal and public. Internal means it's public
within your module. Public would mean it's public
to everyone in other modules, so consider UIkit. UIkit has hundreds of public
methods that we can call. But it also has hundreds,
if not thousands of internal methods that only other UIkit
classes can call between themselves. We don't even know
what they are, okay? So, but for your purposes, since you're always gonna
be working in the module, which is your app,
internal means public, basically. Let's go look
at our controller now, and let's look at its public API,
okay? So here I selected it, look over here. And it says,
there's only one public thing, userIsInTheMiddleOfTyping. I
didn't mean that to be public. I wanted that to be private,
too, I just forgot to put the private on there.
So if I go back over here and say private, okay, then you'll
see it goes away. So now we have no public API here. Now,
it's still completely usable, because in Interface Builder,
we can wire up to this controller and make it appear
in a tab bar controller, all those things. We can do
all that without having any of the internal methods
here be public. Okay, so we're gonna go
back to my, oops, sorry. I'll go back to my brain over
here, it's got my controller over here. All right,
so we've got brain and controller. So let's think
about how we're can use this model over here, okay? We
haven't implemented this yet, but we've defined
its public API. So how can we use that over here?
Well, we really wanna replace all of this business with
using our model, right? Cuz this is where we were doing
model things, calculations. So we don't want that, okay?
We wanna get rid of that, and we want to start using our
model here. Well, to have a model in our controller, we
need to be able to talk to it, that big green arrow, okay? So we need a private var,
which I'll call brain, which is gonna be
a CalculatorBrain, okay? And this is the var that
we're, it's gonna create our, we're gonna create
our CalculatorBrain. And we're gonna talk to it to
do all the calculations, okay? So this is just that big green
arrow I showed you on that, those previous slides, where
the controller talks through this to get to the model. Now,
how about creating this thing? Where do we create this? Well, you can see that we
have an error up here, no initializers again. That's because this var, like any other,
has to be initialized. And I'm gonna create
a CalculatorBrain here. And to do that, I have to call one
of its initializers. And every time you create a new class,
you get one free initializer, which is an initializer that
takes no arguments, okay, kinda the basic initializer.
So I'm using that CalculatorBrain
initializer, it came for free. I don't have anything that I
need to initialize anyway. So, that's perfectly fine,
okay, so I've created it. Now, notice that this right here,
do we need this? No, because Swift
can infer that brain is a CalculatorBrain
from that = right there, okay? So we do not wanna put colon
CalculatorBrain. All right, so now that we have this brain,
kay, and it's created here, we can use it to public API right
here, to make things work. Well, one thing we know is
that when the mathematical symbol comes through here, we
wanna ask the brain to perform that operation. Okay, so we're
gonna pass that mathematical symbol as the operation,
we know that. We also probably know that after it's
done performing the operation, we probably wanna put in
the display the result, the brain's result, this
thing right here. Right? And also at the beginning of
the perform operation, if we're in the middle
of typing a number, we better set that number
at the operand for the calculator to work on it.
If we go 235 square root, we got to put that 235 in as
the operand for the brain. So we better say if the user
is in the middle of typing a number then brain.set
operand to be whatever's in the display. You can see
even here, having this display value thing makes our code
read really beautifully. Okay. We can probably put
this inside this if, because no need to set it false if
it's already true. Okay, so that's it! That's all we need
to do to hook our model up to our controller. Okay.
And we've removed everything in our controller that has to
do with actually calculating. We've basically given it
all off to the model to do. So now we have to
implement this, okay? We've gotta implement
this brain over here. I'm gonna make that be
the main window here. And how are we gonna do that? Well, I'm gonna have a data
structure here for my brain which makes pretty much sense,
which is gonna be private, which is gonna be called
accumulator. It's gonna be a double and it's going to
accumulate the results, okay. As operations are performed,
it's accumulating the result. Okay, anyone who knows
how calculator's built, it has internal calc,
accumulator. So, this is our accumulator.
Notice that I, as soon as I put this in
here I get this error. Again, calculator brain has no
initializers, that's because I don't initialize this. So,
I'm gonna say this equals 0.0. Once I do that I do not
need this because 0.0, Swift always infers that. Or
any something dot something, it always infers it to be
a double, okay. So that makes this be a double. You see? If
I made this no dots just zero, then it's gonna infer
this as an int, okay. So, good thing to know there.
So now that I have my accumulator, the result is
always just the current state of my accumulator. So that's
easy, open my result. And same thing when someone says
the operand, that kinda resets my accumulator to be
whatever that operand is. Okay. So those are all easy to
implement. So that just leaves this guy, perform operation.
That's the heart of my model. That's the thing that's really
gonna do some calculation. Now I could right here go back
to what I was doing in my controller which is to have
some, if there is an essence is here, well actually
I'm gonna use switch. So switch is the same as
another language but much more powerful
in Swift and also much more important in
Swift as you will see. Okay. Switch It's very
important thing is Swift. So, I can switch on this
symbol that's legal. The switch on a string. Okay.
And I just put the cases that I wanna try. So, we have for
example pi. And if pi happens, I wanna set my
accumulator equal to pi, okay. If it was for
example, square root, let's go do that. My square
root symbol back, here it is. So if we get square root, then
I'm just gonna say that my accumulator equals the square
root of the accumulator. Okay? So, this is basically getting
us back to exactly where we were before but
now we have a model. Notice we have an error here. That's because one thing about
switch, you must consider every possible value of this
thing you're switching on. Now, this is a string, so
it has infinite possibilities, okay? Now, we could spend the
next few years saying case A, no, we don't wanna do that.
Instead, we're gonna put default break, so default
means, if you can't match any of these other ones than just
break out of this, okay? Now notice my indentations gotten
a little wonky here, I'm gonna teach you something fun.
If you select a curly braced region including your whole
file, and hit Ctrl+I. It'll reformat it, okay?
Re-lay it out. And I strongly recommend that when
you turn your homework in, you select all and
do Ctrl+I. Okay? That way you'll be using the
default indentation, even if you prefer something else, use
the default one because people reading your code are gonna be
able to understand it better. Okay. And believe me, you'll
adjust to whatever indentaki, indentation style this thing
enforces on you, okay? If you start getting, if you
are a computer scientist and you start getting religious
about things like indentation, you're heading down
a pretty rocky road, okay. Because when you wanna
work in the real world you're gonna have companies that say
this is the way we do it, And if you sit there whining I
don't like to do it that way, get used to it. well, you'll probably get
fired. Okay? So don't do that. So here we're just gonna let
the Xcode do our indentation for us. So this is all we
need to do right here, okay. This is full implementation.
We can go back and run our app and it's exactly
the way it was before, but now we're using a model.
Okay. So here we go, let's try 4-5,
that's working square root. That looks like it's working.
We'll just be sure by picking a number we know the square
root of, pi seems to work, square root. Okay, so
we're back to where we were, that's nice. Now, they'll,
thing about this now is I'm about to go add a whole bunch
more operations here. And if for every single one I have
to do the math, do the math, do the math each one, this is gonna be a lot
of duplicated code in here. Because every time I
have a unary operation like square root, it's exactly
the same. If I have cosign or square root or anything
it's exactly the same. The only difference is these
four characters. Square root, or cosign or whatever. Same
thing for these constants, only this part will be
different on every line, even for binary,
like multiplier, whatever. It's probably only
the function that does the calculation that's gonna
be different. So I'm gonna factor this stuff out, so
that all of these things, like pi and square root and
multiply are in a table, okay? And I'm just going to have
this only be doing the generic calculations, generic
constants, generic numeral operations,
generic binary operations. And it's gonna look in the
table to find out what to do. Doesn't that seem like
a much better design, more extensible,
less code, etc? So that's what were gonna do. So
let's create that table, okay? And were gonna call that
table operations. And it's going to be the class,
it's actually not a class. Dictionary, okay, so
dictionary is a Swift thing. It is a generic type. You're
probably used to that in Java. So you specify right here
when you're declaring this what the keys and values are,
what type? And so I want one, I'm gonna start out just
doing the constants. Let's have this table
only do constants, okay, like pi. Okay? So I'm gonna
have my keys be string. That'll be the name of
the constant, like the pie character or whatever. And
the value's gonna be a double. So that'll be like M under bar
pie or whatever. Okay? So, I've declared it here. Now I'm
actually gonna initialize it because remember I have
to initialize all my bars. You can initialize
a dictionary right on the fly just by using the open
square bracket. Notation and you just put like for example pi cuz key colon
m under bar pi the value. Okay so I'm basically filling
up the dictionary here. Let's do another constant how
about E that's M under bar e everyone know what e is 2.71
or whatever it is. Okay? So, we could add a whole bunch
more of these things into our table. Again, we're only
doing constants right now, we're not doing square root
and those kinds of things. So, that changes
my code over here. Instead of having all
that stuff right there, I'm just going to let Constant
equal Operations sub symbol. So,this is how you look
something up in a dictionary. Okay? Here's the name of the
dictionary, right here, and you look it up with square
brackets and the thing to look up. Okay? And now, I could
just say my accumulator equals that constant. Okay? But, this
is not gonna work. Why? Let's find out. Error, it says,
value of optional double? not unwrapped. Uh-oh,
it's optionals again. Okay, what's happening here?
It wants to unwrap constant. In other words, it's saying
this is an optional double. Why would the thing, this dictionary does not
contain optional doubles, it contains doubles? So, why
would looking this symbol up in that dictionary return
an optional double? Anybody have an idea? Someone
besides you, cuz you got it right before. [INAUDIBLE].
>> Yeah? >> I think their scenarios might not have that key?
>> Correct! Exactly the same thing as
before, okay? This dictionary might not contain that key
that we're looking up. So, it's gonna return nil to
say I couldn't find it. So, we simply need to unwrap
it. Now, this is dangerous, because maybe somebody's
using my API, and they perform an operation
that I don't understand, now I'm gonna crash.
That's not very friendly. So, here I'm gonna use if, the if
let and set my accumulator, and I'm just gonna ignore
any operation that I don't understand. I'm not going
to affect my accumulator. Just leave it. Okay? All
right, so let's run, make sure this works. All right. So, the
square root's not gonna work, cuz we don't have square
roots in our table here, we only have constants. But, we have these
are still working, and pi is still working.
Okay. So that's good. So we didn't break pi, at least.
And if we had an e key, then the e key would work
as well. All right. Now, we want to extend this
to do square root. Okay. How the heck we
going to do that? I mean, really, all we want to
do is just say square roots, whoops, I shouldn't have
done that. Square roots, lets get our friendly
neighborhood symbol for square root here. Okay?
Square root we really want to put square root
[LAUGH] right here. Okay?
The square root function. That's really what I want,
what I want to do. And, like, If I had cosine I'd
really want to put the cosine function here. Okay? Now this
is obviously not a double. [LAUGH] That's not
going to work. So, this can't be a double.
This has to be something else. Okay? It has to be something
that would work for a double, and would also work for
a function. Okay? How are we gonna do that? Well, we're
gonna implement a new type, okay, and it's similar to
class. It's called enum. Okay? I'm gonna call this
enum operation, and inside this enum, I'm gonna
have all the different kinds of operations I know how to
do. Now, you're probably used to enum in other languages.
What is enum in In most languages it is a
discrete set of values, right? An enum has to have discrete
values. Same thing in Swift. It has a discrete value.
So, for example, it might be a constant, or maybe it's
a unary operation. Or it might be a binary operation, or many
it's equals, the equal sign, which is kind of a special
operation, okay. So, enums are the same. What's
different about enums in Swift is that they're like classes
in that they can have methods. Okay? So, I can go
down here and say funk, you know, something, take some
arguments, return something. I can do that down here. Okay?
Enums are allowed to have methods. Now, they can't have
any vars. Okay? They can have computed vars, but they can't
have any storage vars because this is essentially their
storage. Okay? The enum. The other thing about them is
they can not have inheritance, so you can't have
an enum that inherits from another enum,
which probably would be weird anyway. So that is not much
of a restriction. Okay? The other thing about
enums is they're pass by value and I am just going to
post while I talk about that until I show you struct,
which is another pass by value data structure, in a moment.
Okay? So, here is operation, that's great. So, now I can
change pi, that's an operation dot constant. Okay?
Comment that out for a second. This is also an operation
of constant. This is an operation dot unary
operation. Okay? And this is also an operation
dot uniary operation. Okay, cool. So, we can now change
this double to the type operation. Okay? And errors go
away. These are all operations and it all works. Now,
small problem here is that, we've lost track of the actual
constants and, functions, and we've commented them out.
They're not even involved here. So, this obviously
had not solved the problem. It's a step on the way to
solving the problem, but it has not solved the problem.
All right, the other thing is, obviously down here, looking
up constants like this and making the cumulative,
this doesn't work, this only works for constants,
so we're not gonna do that. So, how do we look things
up now for operations? Well, we're gonna do
a similar thing here, okay, we're gonna say.
Let, we can if, if let operation equal
operations sub-symbol. Okay? But, now this operation
is going to be one of these. Okay? It's going to be one
of these enums, right? If I click on it, you see, it's a calculator
brain dot operation. Yeah, notice also I defined
this enum inside this class so its full name is calculator
brain dot operation. You can nest these things. You can even put classes
inside classes if you want and they'll just, it's just
a namespace thing right? The names will be whatever dot
whatever dot whatever. Okay? So, I've got
the operation there. Now, I'm going to switch
on this operation, and I know that the cases
can be constant. Okay? And, I'll just break on
all these for now. So, it could be a constant.
It could be a unary operation. It could be a binary
operation. Or it could be equals. Okay? And remembering switch I have
to define every single option, but I don't need default
here because there are only four possible things that
an operation could be. So, I've got a case for
all of them in my switch. Question?
>> Two things. Why is operation, are we
not referring to the same operation as the enum
operation method? Because it's not capitalized.
>> Yeah, this operation?
>> Yeah. >> Not capitalized makes it a local variable, we're making
it a local variable here yeah. And, actually, that's
a really good opportunity for me to talk about how
you capitalize okay? All types you want to be
capitalized, like calculator, brain, dictionary,
operation, string, double. Do you notice they
all are capitalized? Operate, everything,
okay, is capitalized. All local variables and vars
are lowercase first letter and then capital letter for all
the subsequent words in there. So it's called Camel Case,
you guys know of, have heard of that before?
So, that's how you want to do all your naming.
If you don't do that, you're going to get in trouble
with me. Okay? So, I know some people like to use lower case
for class names, forget it. You can't do it in Swift.
Just don't do it, okay. It'll be allowed, but
you'll get in trouble, so don't do it. Okay? Well, you had a second question?
>> Yeah. >> Why are we using the dot in constants? Are we
referring to operation dot, okay that's my confusion.
>> So, why did I say dot constant here instead of
just saying constant? And the answer is yeah, really
we're doing operation dot constant, but Swift can infer
that it must be operation because it knows this
is an operation. Okay? Is that because it's within
the operation's dictionary? >> Its part of the enum for operation, you see,
operation is not really, we're not inside the
dictionary here. We pulled it already out of the dictionary.
>> So, how does it know, is it intelligent enough to
distinguish even though you computed a lower
pace operation, that it's referring
to the email with the uppercase operation?
>> Okay. It knows that this lowercase
operation is a capital operation because I pulled it
out of this dictionary, and it knows that that dictionary
has operations as its value. So, when I pulled out
its value, it knew it. Okay? There you go. All right.
So this is all going good except for, again, we don't
have the pi and the e and the square root and
the cosine in here. So how are we gonna get
those things in there? And the answer is,
you actually already know it. You've heard it before.
Associated values. Okay? Remember optional has that
associated value. All enums have associated value.
In fact, optional is an enum. Okay? This is what optional
looks like if you were to look at it. Enum Optional, case
None, that's the nil case, case Some with associated
value, T. And then, the optional is generic type.
Just like dictionary, it has this generic type. So
this T could be any type, and that's how optional works.
Okay? So, we can do the same thing
down here, we could associate, for example,
a double with constants. Okay? Because constants need
a double, M under broad pi, we need that thing. Okay? And
so, we're doing the same thing that optional does.
Associating a value with our constants. So,
we have this constant double, then here, when we declare the
constant we have to provide the associated value
which is m under bar pi. Okay? Now we can get rid
of our comment there. Same thing here, we can take
this M under bar E, and associate it with this
constant, oops. Okay, see how we're doing
that association? Now, how do we get this associated
value out when we're looking at a constant down
here? Right, here we switched on the operation, we know that
this is a Constant, right? We looked it up in
the operations Dictionary. And we found that
it's a constant, let's say, like this one.
How do we get it? You do that by right here
saying, let associated, you know, constant, value, or
whatever you want to call this is, this is just a local
variable, but you can call it anything you want. Okay? That
will make this local variable glom onto this associated
value. okay? And so, now we can say accumulator
equals the associated constant value. Okay? So, that's why
I said switch is really powerful it does this kind of
pattern matching to get these associated values out, so
you do that with switch. Okay. Now, associated constant
value, it's kinda yucky. I'm just gonna call it value.
Okay. I only called it that long thing just to show you
it can be called anything and that it is the associated
value, but you can probably call it value. Okay, you got
that? All right. Let's run and see if this works. It's only
going to work for constants, cuz that's the only one we're,
we've done any associated values for yet. But here we
go, this is still working, Pi works, okay, square root,
not implemented yet. All right? So, let's do square
root, okay? So square root, what would be the associated value of a unary operation?
Don't be shy. What? A function yes.
It's a function. Okay? So, how do we make a function be
associated value here? Well, the lucky thing
is that in Swift, functions are types just like
any other type. Okay? There's no differences in Swift's mind
between a function type and a double. Exactly the same.
It can be used in all the same circumstances, arguments to
functions, associated values, local variables, anything can
be of type, a function. And not only that,
it's not a generic function, it's a function with certain
arguments and return values. And how do you
declare such a type? How do you say that that's
a type here? You just type it. So, this is a function
that takes a double and returns a double. Okay? That's the associated
value of unary operation. It's a function. So, here when
we want to associate a value, we have to put In here, just
like we put a double here for this one. All right? Here we
have to put a function that takes a double and returns
a double like, I don't know, square root. Okay? Or maybe, cosine. Okay?
Everybody got that? Now, same thing down here. We got to grab that
associated value. So, here I'm going to say let
and again I can say associated function, but I'm just going
to call this function. Okay? Now I have this is a local
variable of type function that takes a double and returns a
double. That's its type. Okay? That's the type of this
function. In fact, watch, I'll click on it. Look at it's
type. It's a function that takes a double and
returns a double. How do I use a variable
like that? Accumulator. Oops, not accessor.
Accumulator. Okay? Now, again this is
just a local variable. I could call this foo and then
I would put foo here. Okay? Its just a local variable.
That's all it is. And it happens to be, its type
is a function that takes a double, returns a double.
All right. Everybody cool with that? All right, let's run
again, see if this is working. All right so 81 square root,
excellent. Okay? Executing this associated
value, it looked up that square root, found that it was
an Unary Operation with this associated value, went down
here and performed operation. Found it here,
grabbed that associated value, and then I used it to
update my accumulator. Question?
>> So, so you just specified the types
and I'm surprised that you're in, operation does not require
[INAUDIBLE] because your dictionary could potentially
just pull anything, any kind of-
>> [COUGH] >> We know that dictionary can only have an operation in it,
right. You can only have one of these and this only
has four possible cases. Even though any given case
might have any associated value, it's still the actual
case of that operation. There's only these four. So down here,
when I switch on it, I only have to cover those
four cases. No more. Okay? All right,
what about binary operation? Okay, well, binary operation,
a little more complicated and why is it more complicated?
Because if you think about the way a binary operation
works like multiply, 3 times 5 equals. Okay, when I press
times I don't have enough information to update the
accumulator yet. I need the 3 and then the equals, it's only
when the equals is hit that I have enough information
to actually do it. So, in binary operation here, I'm still going to grab that
binary function out of there. I can't actually perform that
function like I can here. So Okay? But, I'm going to have to salt away
that function and the operands so far and wait til equals
happens then I can do it. Okay? But, I still need,
just like unary operation, I need to have an associated
value with a binary operation. What do you think that looks
like? Another function, right, that takes two doubles
and returns a double. Okay? Like multiply. So, that's just a different
kind of function. Okay? And so now I can go up
here and add multiply, so let's go ahead and get the, a,
the mathematical symbol for multiply out of my emoji and
symbols. Here it is right here.
Multiply, okay? And that is an operation
tha's BinaryOperation. And look it wants a function
that takes two Doubles and returns a Double. So I'm gonna
put a function there called multiply, which doesn't exist
in Swift, so I'm gonna have to go write that. By the way,
we have another thing here which is equals, which is
Operation.Equals, okay? So i's a kind of
a special operation there, okay? So, it's complaining
here because multiply doesn't exist, all right? So,
I'm going to write multiply. Here it is, I'm gonna make
it a global function even, just like square root.
Func multiply, okay, takes one argument
that is a Double. Takes another argument
tha's a Double. Returns a Double, and
it just returns op1* op2, okay? So I've created this
new function, multiply, here it is, and I can now use
it right here. Sound good, you understand that? Question?
>> Why is that outside.
>> Yeah, so why did I put this outside? Because I wanted it be
a function, a global function. Not a method in this class,
okay? So I just wanted its scope to be wider.
>> So it's more of a style? >> Yeah, it's kind of a style. A little more of a style
thing. All right, so so now we have this
binary operation here, we have to salt away the
binary function like times, and the accumulator so far,
the 5, in 5 times 3 equals, the 5 and the times we have
to wait, salt them away. So I'm gonna salt them away in
a data structure, and I'm, gives me a chance to teach
you another data structure. You know class, you know enum, here's another
one called struct. Okay? Now you know struct from
other languages, of course. I'm gonna call this struct
PendingBinaryOperationInfo, okay? And it's just gonna
contain these two things I want. One of them is the
binary function that I'm going to do. What's the type
of this? Something that takes two doubles and returns
a double, that's it's type. See, I'm just declaring,
that is a type, it's a type like any other
type, like int, okay? We also need to keep track
of the firstOperand for this binary function, which is
gonna be the accumulator so far. And that's gonna be
of type Double, okay? Now, what is a struct? Okay,
we know class, we know enum, what's struct? Okay, struct
is very much like class. Almost identical, okay? It can
have vars, stored vars, and computed vars, no inheritance,
okay? But the big difference between struct and class,
is that structs, like enums, are passed by value,
whereas classes are passed by reference, okay? What does
that mean? All right, so passing something by reference
means that that thing lives in the heap, okay,
lives in memory somewhere, and when you pass it
around to methods or something like that, you're
really passing a pointer to it. And so, when you give
it to someone else, they have the same one you have, because
you both just have a pointer to the same thing that
lives in the heap. That's passing by reference,
okay? Hopefully you know that much of computer science,
that that's pass by reference, okay, and that's what it
means in this scenario. So if I had a class like
calculator brain, and I pass that brain around,
I'm talking about the same calculator brain all the time.
Now I can instantiate another one in the heap and
have a different one, but, but I'm pointing, when I
create one I'm pointing to it, and I'm passing the pointer
to it around. Path by value means that when you
pass it, it copies it, okay? Some would think of it as it's
being passed on this stack, the call stack
of the function. But that's not necessarily
how Swift implements it. But the semantics of it,
are that it is copied. So if you have a, let's say
an array, which is a struct, okay? A double is a struct, it
turns out. An int is a struct. A string is a struct.
These are all structs, okay? And so if I passed an array
to some other method, and then I added something
to that array, it would not be added back in
the caller's array. The caller would have that array without
that thing added, okay, cuz it would get a copy of it.
Now you would think, whoa, this is gonna be really
low performance, because what if I had
an array of 10,000 items and I passed it, it's gonna
copy 10,000 things. My God, my code is just gonna grind to
a halt. No, Swift is really smart about when you
pass a bi-valued struct, it doesn't actually make
a copy of it until you try and touch it, okay? If you try and
mutate it, then it'll make a copy as necessary, maybe
not even a full copy, but it'll mutate it. So if
you're passing something and you don't touch it, then you
are gonna be sharing it, okay? But, all of that is behind
the scenes performance enhancement, you don't
know anything about it. From your point of view it
copies it. Structs always get copied, okay? Understand
the difference there? A very important difference
between structs and classes. And enums are like structs.
All right, so I've got this right here. Now,
notice that I didn't set these equal to anything, but
I didn't get that warning, no initializers. Now usually
if I put a var in a class, if I don't put initial,
then it says, no initializers, right?
So, why is it not saying here? That's because for structs,
unlike classes, classes we got a free initializer. What were
the arguments to it? Nothing, right? Like calculator brain,
parenthesis, no arguments. So, that's the free initializer
you get for classes. For struct,
the free initializer you get, is an initializer that, whose
arguments are all of its vars, every one of its vars, okay?
So let's go ahead and call that, because here
in BinaryOperation, I need to create one. So
I'm gonna create a private var here. I'm gonna call it
pending. It's gonna be of type PendingBinaryOperationInfo,
and it's gonna be an optional. So here I am creating
my first optional. It's an optional struct, okay?
Why am I making this optional? Because this
PendingBinaryOperationInfo is only there if I have
a pending binary operation. If I haven't typed times or
divide or something, I don't have one of these, so
I want this to be nil, okay? I want this pending var that's
holding this pending stuff, to be nil at that point.
And then when I have one, I'll set it to something,
okay? And that's exactly what I'm gonna
do here in BinaryOperation, I'm gonna say, pending. That's
this thing right here, okay, = PendingBinaryOperationInfo. And when I open parentheses,
look. I got a constructor for this PendingBinaryOperation
that has these two things as its two arguments.
See, binaryFunction, and firstOperand. So now I can
apply these values, this is function, and the firstOperand
is the accumulator. Okay, so now I've created one of these
pending hoo-has right here, and that's all I've done.
I pressed time, but I'm doing 5 times 3 equals, I
press the times, all I did was create one of these structs,
and put the times and the 5 in there.
Now in Equals, right here, I'm gonna say if
pending != nil. So if I have a pending operation,
then I'm going to evaluate it. So 5 times 3 equals works,
but if I just say 5 equals, I don't have any pending times,
so I'm just gonna ignore this. So I'm only gonna do this if
I have a pending one, and what am I gonna do? Well, I'm
gonna set my accumulator =, evaluating that pending
function, which is pending!, because it's an optional,
.binaryFunction. Called with the arguments of
the pending!.firstOperand, and my current accumulator. Okay, and now pending is nil,
because I no longer, I just handled that
pending thing, so now I no longer have
a pending operation anymore. That make sense? Okay, so
let's go take a look and see if this works. All right,
here we go. Let's try, we don't have a times button.
Let's go back to our UI and add a times button [LAUGH]. In
fact, we'll add of our binary operations here. Okay, so,
I'm gonna just copy and paste. Put this here, paste another
one. Here, we'll put all my binary operations across
the top here, paste, okay. Go here, we'll go to our
emoji and symbols things. Here's times. We'll put
divide right next to times. We'll put plus right here.
We'll put minus right here. We can put some other buttons
down here too, like maybe we'll put, cosine, yeah,
let's put cosine in there. Let's cosine. Did I have
another one? E I guess I had, right? Put E in there too. E. Let's also put a equal sign.
Gotta have that. We'll put it down here. Equal
sign. And here, in this empty space is just begging for
me to put something there. I'm gonna put period.
Because in your homework, you're gonna have to add
the capability to be able to enter floating point numbers.
So you'll need this one. So I'll put it there for you.
Okay? All right, so here's our nice UI. Looks really pretty.
And let's run it. All right, let's try 4 x 5 =,
woo hoo, it works. A miracle the first time.
Okay, let's try something
a little complicated. How about this? Well,
let's do some other things. The square root's still
working, cosine, let's play pi cosine. That worked, cool. All
right, there's E, 2.71, nice. Here's something that doesn't
work though, watch this. 7 x 8 x 2 x 3, uh-oh, this is not working. And this
is not working because it's requiring me to press equals
to evaluate minor operations. So I have to go 4 x 7= x3 =
x8 =, really, what I want is an automatic equals anytime
I press a binary operation. So I can go 4 x 5, and when I
go times, it doesn't equals. And then let me do it. So
let's just do that real quick. Let's go back to our brain.
I'm just gonna take this little thing that
equals uses and make it into a function,
private func, we'll call it executePendingBinaryOperation.
It's just gonna, I'm just pasting in
the exact same thing. I'm gonna call that here,
executePendingBinaryOperation. And I'm also gonna call it
here. Okay, I personally like, if I have any of my cases
that go onto second line, I like to put them all there.
I just think it looks a little nicer than having sum on the
end. It doesn't really matter to SWF, but I just think this
looks a little nicer. Okay, so we did that.
So that'll fix that case. All right, the last
two things I wanna do, okay let's take this
4 x 7 x 8 x 9 = okay. Now the last thing,
two things I wanna do is one, I'm gonna show you how to
make, divide and plus and minus work without creating
a whole ton of these little extra functions like multiply
cuz that's really gross. And then second, I'm gonna
make our UI stretchy, so it works with landscape and
portrait. Okay, those are the two things
I'm gonna do. All right, so let's go ahead and make our
other four operations here, which is divide,
plus and minus. So I have to bring up our
emoji again. Okay, so this one will make the divide.
We'll make this one be plus. And we'll make this
one be minus. Okay, now here I could have
a function called divide, and another one called add,
another one called subtract. And then, I could go up here
and make one of these for divide, and one of these for
add and one. Okay, but if I start doing that, what a
mess. Okay, I-I've hardly even gained anything by having this
nice table of operations, if I also have to have
a separate function for everything I want to do. Well,
SWF is gonna take care of us on that front because
it implements closures. How many people know
what closures are, the computer science
term closures? Okay, hardly anybody, whoo, okay.
So a closure is basically, you can think of it as
an inline function, okay? But it's an inline
function that captures the state of it's environment.
And we're gonna see why that's important later
in the quarter. But, for now, you can just focus on the
inlined function part of it. So, I can actually take this
multiply function, okay? I'm just gonna select the function
without the word multiply. And I'm gonna cut, and I'm gonna
paste it right in here. Okay? Now, I can't quite do that. I
have to do two things. One, I have to take this curly brace
and put it at the beginning so that the arguments here is
inside the curly brace, because the whole closure has
to have curly braces beginning to end. And then,
since I need to separate this from the rest, I also put the
word in right there. Okay, so that's how you make a closure. It's exactly the same as
a function, except for the curly brace starts before
the arguments and you put in after the arguments. Got that?
Now, this doesn't look, so that I don't need function
multiply any more. So this doesn't look that
much better. It's still kind of a mess. But we're gonna use
type inference, yeah, to make this look a lot better. Now,
remember that SWF knows that this binary operation takes
a double, two doubles, and returns a double. So
this is all redundant, okay? SWF can infer that
that's a double. It can infer that's a double. And it can infer that it
re-returns a double. So this is wow, all of a sudden
looking a lot better already, okay? We can make this look
all in one line. Okay, that's looking pretty good.
I mean, that alone is probably really, really good. However,
it gets better than that, because closers also can
have default arguments. The default argument
names are $0, $1, $2, $3, however many
arguments it has. So you can put those as
the names of the arguments instead of having op one or
op two whatever you want to call it. Okay? And if you do this, then you
don't even need that. Okay? If you use the $0 and $1, and
since this is a double, and SWF can infer that this
return's a double, you don't need return right here.
>> [LAUGH] >> Okay? >> [LAUGH] >> So we've cleaned up our code quite a bit. And in fact,
now divide is just this. And add is just this.
And subtract is just this. Okay? So that's closures.
Super powerful. Used a lot in the iOS API.
You're going to be able to use it in your code
to your heart's content. It's very fun.
Let's make sure it actually works. All right,
7 x 8 = all right, divided by 5 equals?
Looks good. minus nine equals? All right, so all of our
things here are working. Okay? We also could, so
we can do that for our UnaryOperations as well.
What if we wanted, for example, something like change
sign. Let's go find something to be change sign. How about
this? That's not really [LAUGH] a change sign symbol,
but I'm gonna use it for that. I could say change sign
is Operation.constant, or .UnaryOperation, sorry.
UnaryOperation and I need a function that takes
a double returns a double, how about -$0. Okay,
that changes the sign of the one argument. And Swift is
smart enough to know that this has one argument. And that it
is returning that argument and that unary operation
is double double, so it knows that this must be a
double. It'll even infer that. Okay. All right, so that's
it for our calculator brain. And if we look back at
our calculator brain and the code in it. All the code here has nothing
to do with UI. It's purely about calculating
and it's super-extensible. If you want to add more
operations here, all you need to do is to provide
the type of operation and what's specific to
that operation. All the calculation is
done is this very simple function right here, the only
complexity of which is this pending binary operation thing
we have to do. By the way, this right here, this struct,
should also be private. Okay, this struct which is
calculatorBrain.PendingBinary- Info, that's its full name,
that should be private as well, because we're only
using that internally. Same thing with
this operation. It should be private. Cuz we're not using it in our
public API and same thing with this operation, should
be private. Okay, should make everything private that you
can make private, okay? Make the things public that
you intend to support forever in your object. Okay? So let's
do that UI thing I was telling you about. Let's go back to
our story board here, and we want to make this thing so
that when we, let's see what it looks
like now, actually. Okay, so our UI, we know it
doesn't look very good, this is not lined up. This is
kind of nice right here but it's not lined up.
But what happens if we rotate to landscape? The way
we do that is Hardware, in the simulator, Hardware >
Rotate Left and Right, okay? I'm gonna use command keys to
do it. Cmd+arrow. That really looks bad because I can't even
say equal six times four. Okay. I can't even
use this UI, it's so bad, okay? So,
we need to fix this UI so that when it's in portrait,
it's using the whole space. Laying the buttons out
to make it work and, when it's in landscape,
it's using the whole space and the buttons are a different
shape. Okay, how are we gonna do that? Well
I'm gonna do that by taking each of these and putting them
in a little stack. And then I'm gonna take the five stacks
and stack them together. And then I'm gonna stack this
whole thing with this, okay, and create a stack of stacks.
And then I'm going to bind the left, top, right and
bottom edges of that whole thing to the outer edges
of my UI. That way, when the outer edges of my
UI change, that thing will change. And the stacks
automatic gonna how to, you know, reallocate the
space. Okay, simple as that. So that's what we're gonna do.
So let's make stacks here. The way we do that, we select
the things we want to stack. We go to editor Embed In >
Stack View. Okay, and that's gonna put it in a stack view
here. Now, we can also go over to the inspector and inspect
some things about this stack view like I want some spacing,
10 points between each one. Also, you see how the cosine
one is wider then the dot? I don't want that,
I want them all the same, so I want it to distribute its
space equally. Okay, so now they're all equal. Okay, same thing here.
Okay, 10 points, and fill equally. Now, by the way,
there is no command key for this, but you could go to
Preferences over here, Xcode > Preferences, and
go to the key bindings and give it a command
key if you wanted. If you were using stacking
a lot, like I am, you could do that.
So let's put these in here. 10, fill equally.
This one. Oops. 10, fill equally, and
this last one. [BLANK AUDIO] All right. Now I have
these five stacks right here. Okay, horizontal stacks.
Now I'm going to take them and put them in a stack. Okay? So I'm going to put them in a
vertical stack. [NOISE] Okay? Now, these, I want, here,
to all be spread out. So right now you see
the alignment is leading, so it's putting all these
things on the leading edge? I want them to fill instead,
so they fill the whole width. Okay? I also want
spacing here, okay? 10 between all of them, so
I've got kind of a nice little key pad. Now let's
stack this with this. So I'm going to select both
of these and stack. Okay, put them in a stack together.
Again, I want spacing. I want, do definitely do not want fill
equally here, because that would make this blue thing the
same height as this big stack. So we don't want that, we just
want Fill. That means they're gonna be their natural size,
okay? [COUGH] So for this, it's gonna be the size that
fits this text and for this, it's gonna be a size for all those stacks to fit
their contents. All right, now I'm gonna finally use the
blue lines. Okay, because I'm gonna put this thing up in the
upper-left corner right here. Okay? And I'm gonna anchor
it to that corner and here's how we do that.
We use the Ctrl key, just like we did when we
were dragging to the code. We can also drag between
elements in the UI. So, I'm gonna drag between this,
stack thing and this outer container. So, I'm just
dragging up to its top edge. Now when I do, when
I Ctrl+drag between things, I can constrain them to
be related in some way. Like I could make them be
equal widths. I can make this thing be the same width
as the container view. Or I can do what I want, which is
constrain the vertical spacing of this to the top layout.
In other words, kind of attach that to that,
so I'm gonna create that. And you can see it creates
this little I-beam, this little tiny I-beam
right there. Okay, I'm gonna do the same thing
to this edge, right here. I'm gonna attach the leading
space to the container margin, okay? And
I can do the same thing. Now, by the way, when you do this,
be careful when you Ctrl+drag, you wanna make sure the thing
you're dragging from is the entire stack. Don't be, you know, just Ctrl+dragging
from this eight or it'll actually pin the eight to the
edge. Okay, you want to pin this whole stack view and I'm
going to show you how you can select the whole stack view
in a second here. Let's drag this over, this is going
to be the trailing space. Okay. And now, here I'll show
you how to, if I click on this thing right here, it's
selecting the two. But I want to select the whole thing, so
I'm going to do Ctrl+Shift. Ctrl+Shift, okay, see it down
in the lower left there, Ctrl+Shift? Ctrl+Shift-click.
When you do that, it says, what thing under the
mouse do you want to select? Do you want to select that
outer container, the big stack view, or this little, interior
stack view? So here, I want the big stack view, the one
that contains the whole thing. All right, so and then when
I Ctrl+drag, I'm being careful not to Ctrl+drag from
one of these buttons. And here, I'm Ctrl+dragging
from one the spaces there, okay. So this is to vertical
space into the bottom. And so now I've tied them to
the edges. Unfortunately, I've tied these two edges
too far away from the edges. Okay. I wanna tie these two
edges to right up next to it. And the way I do that is,
I can do it via the Inspector right here, by clicking
on this I-beam, you see. This constant saying
how far it is. I can also double-click
on this I-beam. And it puts up a little thing
here. So, I don't want her to be 338 points away, I want
her to be either some standard value, or if a standard value
doesn't make sense here, which it doesn't,
that's why it's grayed out, then I'm gonna put it 0
points away. Bam. Okay? Same thing I can do down here.
Let's double-click this one. Here, a standard value
is available, so I'm gonna click
standard value. And now it's putting its standard
value from the bottom. Okay. Now, when it's stretched
there, it made these tall. Okay, so that means we did
something bad with our, you know, spacing of
the things, which is, what did we do wrong here?
Those are all fill equally. Yes. How about this guy
right here? Maybe this, this guy fill equally. Okay
we want this internal one. Okay, this internal stack
view, to be fill equally. Glad I made that mistake, so
I show you how to do that, okay? So, we've got this all
equally spaced out. This looks pretty kind of funny in
a square, but I bet it's gonna look pretty good in
portrait and landscape, let's go take a look. All
right here's portrait. Hey, that looks pretty darn good.
4 times 8, you know, plus 9 equals. Square root, okay,
cosine, pi, cosine. Excellent, let's take a look at
landscape, woohoo! It worked, okay. So, very little work
here. And we can make our UI stretchable, okay? Now, later
in the quarter, we're gonna have more sophisticated UIs
than just these stack things, but we'll still be using that
Ctrl+dragging to the edges. Now, your homework assignment
is to reproduce everything I've done in these two days. Add that floating
point number, add a little text field
that shows a history of all the things that have
been typed in, and add some more buttons. So
you're gonna be doing outlets, actions, and
a little bit more. And that's basically your entire homework
okay? It's all posted. See ya next week.
>> For more, please visit
us at stanford.edu