Placeholder Image

字幕表 動画を再生する

  • 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

Stanford University. >> Okay, well, welcome

字幕と単語

ワンタップで英和辞典検索 単語をクリックすると、意味が表示されます

A2 初級

スタンフォード - SwiftでiOS 9アプリを開発する - 2.MVCの適用 (Stanford - Developing iOS 9 Apps with Swift - 2. Applying MVC)

  • 82 6
    馮凱嵩 に公開 2021 年 01 月 14 日
動画の中の単語