
Chinese: 
本字幕由志愿者义务贡献，采用许可协议
知识共享 署名-非商业性使用-相同方式共享 3.0 美国
Stanford University. >> So
斯坦福大学
welcome to Stanford CS193P, this is Developing iOS
欢迎参加 2017 年冬季学期斯坦福
Applications, winter of 2017. So today I'm gonna give
CS193P 课程，iOS 应用程序开发
another brief set of slides on Model View Controller, this
今天的幻灯片是关于 MVC，模型——视图——控制器
design methodology that we're gonna use to build all of our
一个编写所有 iOS 程序都会用到的设计模式
iOS apps. And then I'm gonna continue the demo that we
之后就接着完成星期一开始的
started on Monday. We're gonna actually incorporate MVC into
那个程序。我们会把这种设计模式
the calculator. And it's also gonna be an opportunity for
运用到计算其中。这也是一个大好机会
me to show you a lot of other cool Swift, language features.
能让我展示 Swift 的许多优点、语法和特性
So what is MVC? Model view controller, what is that?
什么是 MVC，模型——视图——控制器呢？
Basically, it starts out being a way that we divide up
从大体上看，这是我们把代码
all of the code in our app into three different camps.
分割成了三个“阵营”
These three different camps are the model camp, the model
“阵营”的一个是 Model，模型
is the "what" of your app, so what your app is. So,
模型体现了你的程序“是什么”，也就是你的程序是干什么的

English: 
[MUSIC]                         
Stanford University.            
>> So                           
welcome to Stanford CS193P,     
this is Developing iOS          
Applications, winter of 2017.   
So today I'm gonna give         
another brief set of slides on  
Model View Controller, this     
design methodology that we're   
gonna use to build all of our   
iOS apps. And then I'm gonna    
continue the demo that we       
started on Monday. We're gonna  
actually incorporate MVC into   
the calculator. And it's also   
gonna be an opportunity for     
me to show you a lot of other   
cool Swift, language features.  
So what is MVC? Model view      
controller, what is that?       
Basically, it starts out        
being a way that we divide up   
all of the code in our app      
into three different camps.     
These three different camps     
are the model camp, the model   
is the "what" of your app,      
so what your app is. So,        

English: 
in the calculator case, i's     
the brains of the calculator,   
i's the thing that              
calculates, tha's the model,    
and tha's a UI independent      
part. I's what the app is,      
not how it displays or          
anything like that.             
How it displays is              
the controlle's job. So         
the controller decides how      
to take this UI independent     
thing, the model, and           
display it on your screen and   
interact with the user. That's  
what the controller job does.   
It's the, how it displays.      
Model is the what it is.        
Controller is how it displays.  
The view is the minions         
of the controller, okay?        
Things that the controller      
uses to do its job,             
almost always, these things     
in the view are generic,        
things like UIButton or         
UIScrollView, okay?             
Things that come from Apple or  
somewhere else,                 
even things you write, and you  
generally try to write them to  
be pretty generic reusable UI   
things. And the controller is   
trying to use those generic     
things to build a specific UI.  
Now the key to making MVC work  
is managing the communication   

Chinese: 
in the calculator case, it's the brains of the calculator,
用计算器来举例子，那模型就是它的大脑
it's the thing that calculates, that's the model,
负责计算的那个部分就是模型
and that's a UI independent part. It's what the app is,
和 UI 是没有关系的。仅仅是背后的逻辑
not how it displays or anything like that.
和具体怎么展示出来是没有关系的
How it displays is the controller's job. So
决定如何展示的是 Controller，控制器
the controller decides how to take this UI independent
控制器决定如何把这个与 UI 无关的
thing, the model, and display it on your screen and
这个模型显示到你的屏幕上
interact with the user. That's what the controller job does.
来和用户交互。这就是控制器的作用
It's the, how it displays. Model is the what it is.
决定如何展示出来。模型是程序的本体
Controller is how it displays.
控制器决定如何展示
The view is the minions of the controller, okay?
View，视图，是控制器手下的用人
Things that the controller uses to do its job,
控制器通过视图来实现它的功能
almost always, these things in the view are generic,
通常视图都是能通用的
things like UIButton or UIScrollView, okay?
比如 UIButton 或者 UIScrollView
Things that come from Apple or somewhere else,
由苹果或是其他平台提供的
even things you write, and you generally try to write them to
包括你自己编写的。你应该尽量写通用的
be pretty generic reusable UI things. And the controller is
能够重用的 UI 控件。而控制器
trying to use those generic things to build a specific UI.
则是使用这些通用的控件构成特有的 UI
Now the key to making MVC work is managing the communication
使用 MVC 的关键是组织联系

Chinese: 
between these camps because if we don't manage
这几个阵营。如果我们
that communication,
没有控制好交互
we might as well just put them all in the big camp.
而只是把这些代码都堆在一起
And they can all talk to each other however they want. So
三个阵营之间都能随便调用的话
if we're gonna have three camps,
那这分类也就没什么实际意义了
we gotta think about how they communicate.
所以我们要考虑好三者之间是如何交互的
So I've used this road sign kind of imagery here, okay,
我这里用的道路交通标线来表示
the roads, like the road lines in the middle of a road
就是马路中间的那些线
between them to help you visualize what is allowed
让你们能形象地理解
in terms of communication.
哪些沟通是被允许的
So, let's talk about every boundary here between all of
让我们来逐个分析阵营之间的交互
these camps. Let's start with the controller talking to
我们从控制器访问模型开始
the model, okay. Can the controller talk to
控制器能和模型通信吗？
the model? Absolutely, it can say anything to the model that
肯定是可以的。控制器能够访问
the model publicly allows to be said to itself. So,
模型所有公开允许访问的内容
it's a green arrow. It's a dashed white line on the road.
所以我用绿箭头。这是白虚线
You can go across there all you want.
你可以随便跨过去
And you can see why this is.
这是可以理解的
It is the controller job to get that model onto screen.
因为控制器的功能就是把模型展示到屏幕上
It has to be able to talk to it all at once. So, there's no
控制器应该是有全权处理的
restriction of the controller talking to the model. And
控制器访问模型是没有限制的
similarly, there's no restriction of the controller
同样的，也不会限制控制器
talking to the view, because the view are the controller's
与视图的沟通，因为视图和控制器

English: 
between these camps             
because if we don't manage      
that communication,             
we might as well just put       
them all in the big camp.       
And they can all talk to each   
other however they want. So     
if we're gonna                  
have three camps,               
we gotta think about            
how they communicate.           
So I've used this road sign     
kind of imagery here, okay,     
the roads, like the road        
lines in the middle of a road   
between them to help you        
visualize what is allowed       
in terms of communication.      
So, let's talk about every      
boundary here between all of    
these camps. Let's start with   
the controller talking to       
the model, okay.                
Can the controller talk to      
the model? Absolutely, it can   
say anything to the model that  
the model publicly allows       
to be said to itself. So,       
it's a green arrow. It's a      
dashed white line on the road.  
You can go across               
there all you want.             
And you can see why this is.    
It is the controller job to     
get that model onto screen.     
It has to be able to talk to    
it all at once. So, there's no  
restriction of the controller   
talking to the model. And       
similarly, there's no           
restriction of the controller   
talking to the view, because    
the view are the controller's   

Chinese: 
minions. Right, so you gotta be able to tell your minions
是从属关系。你肯定要能够和下属沟通
what to do without restriction. Now,
告诉它们该做什么。这不应该被限制
these connections between the controller and
这些控制器和视图之间的关连
a view, we call them outlets. And you've already seen one in
叫做 Outlet，出口。你们已经在计算器里见到过了
the calculator, we created an outlet, if you remember,
如果你还记得的话，我们创建的那个出口
it was called display, right?
就是叫做 display 的那个
It was an instance variable in our controller. Remember that
控制器的实例变量
class ViewController we saw on Monday,
星期一看到的那个 ViewController 类
that's the controller of the MVC that we built on Monday.
我们周一就是构建了那个控制器
And that display var, was an outlet,
那个变量 display 就是 outlet 出口
and it's just wired up to a UILabel in our view. UILabel
和视图里面的 UILabel 关连起来的
is one of the minions for the controller in the view. Okay,
那个 UILabel 就是视图中、控制器下属的其中一个
so you've already seen that happen. The model and the view
所以你们已经见过这种交互了。模型和视图
can never speak to each other. Double orange line there,
它们之间是不能有交互的。双黄线
no crossing either way across here. And this makes perfect
两边都不能跨线。这也是很有道理的
sense because the model is completely UI independent,
因为模型是完全和 UI 分开的
and the view is completely UI. That's all the view is.
而视图全部是 UI 相关的
So, they have nothing to talk about,
所以它们并没有共同语言
these two guys, okay? Cuz they're completely, you know,
这两者之间，你知道的

English: 
minions. Right, so you gotta    
be able to tell your minions    
what to do without              
restriction. Now,               
these connections between       
the controller and              
a view, we call them outlets.   
And you've already seen one in  
the calculator, we created      
an outlet, if you remember,     
it was called display, right?   
It was an instance variable in  
our controller. Remember that   
class ViewController            
we saw on Monday,               
that's the controller of the    
MVC that we built on Monday.    
And that display var,           
was an outlet,                  
and it's just wired up to       
a UILabel in our view. UILabel  
is one of the minions for the   
controller in the view. Okay,   
so you've already seen that     
happen. The model and the view  
can never speak to each other.  
Double orange line there,       
no crossing either way across   
here. And this makes perfect    
sense because the model is      
completely UI independent,      
and the view is completely UI.  
That's all the view is.         
So, they have nothing           
to talk about,                  
these two guys, okay? Cuz       
they're completely, you know,   

Chinese: 
different camps that make no sense to talk to each other.
它们的交互完全是天方夜谭
It's up to the controller to manage communication between
控制器才是负责它们之间交互的
these two. So, never shall you just communicate between those
所以永远不要让模型和视图互相调用
two camps, all right? How about the view talking back to
好吧？那视图反过来，和控制器交互呢？
its controller? Can the view, those minions, can they talk
视图，作为仆从，能够联系
to its controller? Now this is something you would clearly
它的控制器吗？很明显的，这是我们希望有的
want because the minions gotta work with the controller, but
因为它们是给控制器干活的
it's a bit of a problem here.
但存在一个小问题
Because these things in the view are generic.
那就是这些控件都是通用的
They're things like UIButton. The class UIButton shipped
就像 UIButton 那样的
from Apple last year. It knows nothing about a calculator,
苹果去年编写的 UIButton 类对我们计算器一无所知
so how can that UIButton talk to a calculator? Well, we can
那么 UIButton 要怎么和我们计算器通信呢？
do it. We just have to sort of do it in a blind, meaning
可是可以，不过它是被蒙在鼓里的
we don't know the class of the thing we're talking to.
因为我们并不知道我们联系的究竟是谁
And structured manner, so that we can clearly understand what
这个通信也是规范化的，才能保证大家都能理解
communication is happening. So you've already seen a blind
发送的是什么信息。你已经看到过这样的
structured communication between the view and
规范化的匿名通讯，在视图
the controller. It's target action, okay. So
和控制器之间使用。这叫 target-action，目标对象-操作模式
the controller can drop a target on itself
控制器可以把自己设置为目标

English: 
different camps that make no    
sense to talk to each other.    
It's up to the controller to    
manage communication between    
these two. So, never shall you  
just communicate between those  
two camps, all right? How       
about the view talking back to  
its controller? Can the view,   
those minions, can they talk    
to its controller? Now this is  
something you would clearly     
want because the minions gotta  
work with the controller, but   
it's a bit of a problem here.   
Because these things in         
the view are generic.           
They're things like UIButton.   
The class UIButton shipped      
from Apple last year. It knows  
nothing about a calculator,     
so how can that UIButton talk   
to a calculator? Well, we can   
do it. We just have to sort     
of do it in a blind, meaning    
we don't know the class of      
the thing we're talking to.     
And structured manner, so that  
we can clearly understand what  
communication is happening.     
So you've already seen a blind  
structured communication        
between the view and            
the controller.                 
It's target action, okay. So    
the controller can              
drop a target on itself         

Chinese: 
by basically creating a method with that @IBAction,
然后创建个响应对应 @IBAction 操作的方法
remember that from Monday? And then you just control drag and
还记得我们星期一的时候干的吗？按住 Control 键拖拽
that lets the view UIButton talk,
来创建 UIButton 视图的通讯
basically connect up to that target. And now every
也就是关连那个通讯目标
time that the UIButton wants to talk to the controller,
现在每次那个 UIButton 想要给控制器发送消息
it's just sending that target action. So that is
只需要把操作发送给目标对象即可
super simple blind structured communication from the view
这就是视图使用的标准化匿名通讯机制
back to the controller. But, that's a little too simple for
并以此来联系控制器。但是有的时候
all the communication that these minions might wanna do.
这种方式不足以实现这些下属的需求
For example, sometimes, something in the view wants to
比如有时候视图想要
synchronize itself with the controller.
和控制器保持同步
Or it wants to know what the controller intends as it's
或了解控制器使用自己想达到的目标
being used. Let's use the example of a scroll view.
拿 UIScrollView 举例子
Okay, a scroll view,
滚动视图
when it's scrolling around,
在四处滑动的时候
might wanna ask the controller,
可能会想问控制器
should I allow the user to scroll over here? Or
我能让用户滑动到这里吗？
they might just wanna tell the controller, hey, the user
或者想要告诉控制器
scrolled down here. These kind of notifications and
用户已经滑动到这里了。这种通知
questions about whether it can do things, they kind of end up
和询问能否做某些事情的行为

English: 
by basically creating a method  
with that acts on IBAction,     
remember that from Monday? And  
then you just control drag and  
that lets the view              
UIButton talk,                  
basically connect up to         
that target. And now every      
time that the UIButton wants    
to talk to the controller,      
it's just sending that          
target action. So that is       
super simple blind structured   
communication from the view     
back to the controller. But,    
that's a little too simple for  
all the communication that      
these minions might wanna do.   
For example, sometimes,         
something in the view wants to  
synchronize itself              
with the controller.            
Or it wants to know what        
the controller intends as it's  
being used. Let's use           
the example of a scroll view.   
Okay, a scroll view,            
when it's scrolling around,     
might wanna ask                 
the controller,                 
should I allow the user         
to scroll over here? Or         
they might just wanna tell      
the controller, hey, the user   
scrolled down here. These       
kind of notifications and       
questions about whether it can  
do things, they kind of end up  

English: 
in things that start with       
these words I have up here,     
"will," "should," and           
"did." Like,                    
should I scroll to here?        
I will scroll right here,       
if the scroll view was          
about to scroll. And            
then I did scroll down here     
after the scroll view is done.  
So those kinds of               
communications.                 
And the way we make that        
communication work,             
we can't just do this simple    
one method control drag,        
instead we use what's called    
a delegate. And I'm gonna talk  
a lot more about a delegate in  
future lectures. But basically  
the idea of a delegate is,      
it's a var in the view, so      
like a var on scroll view. And  
it's of a special type; that    
type is called a protocol.      
I know that a lot of you,       
even though you have object     
oriented experience,            
maybe you don't have            
experience with protocols. But  
essentially, a protocol         
is a way of                     
saying that this type, this     
thing that I'm talking about,   
it responds to a certain set    
of methods. I don't know what   
classage it is, I don't know    
if it's a view controller,      
I don't know what it is, but    
I know it's gonna respond       
to these methods like will      
scroll, did scroll,             
should scroll,                  

Chinese: 
in things that start with these words I have up here,
通常都能被这样归类
"will," "should," and "did." Like,
“will”（将要），“should”（能否）和“did”（已经）
should I scroll to here? I will scroll right here,
“我应该滑动到这里吗”？“我将要滑动到这里”
if the scroll view was about to scroll. And
如果滚动视图要开始滑动了
then I did scroll down here after the scroll view is done.
以及完成之后的“我已经滑动到这里了”
So those kinds of communications.
就是这类的通讯
And the way we make that communication work,
我们实现这类沟通的方法
we can't just do this simple one method control drag,
并不只是简单的按 Control 拖拽
instead we use what's called a delegate. And I'm gonna talk
而是通过 delegate，委托代理
a lot more about a delegate in future lectures. But basically
之后的课程里我会细讲委托模式
the idea of a delegate is, it's a var in the view, so
简单来说代理是视图里的一个变量
like a var on scroll view. And it's of a special type; that
比如 UIScrollView 里的一个属性，类型十分特殊
type is called a protocol. I know that a lot of you,
叫做 protocol，协议。我知道你们大部分人
even though you have object oriented experience,
即使有使用面向对象编程的经验
maybe you don't have experience with protocols. But
也很有可能没有使用过协议
essentially, a protocol is a way of
协议本质上是一种
saying that this type, this thing that I'm talking about,
我这里的这个变量
it responds to a certain set of methods. I don't know what
能够响应这些方法
class it is, I don't know if it's a view controller,
我不知道它具体是什么类型，也不知道是不是 ViewController
I don't know what it is, but
虽然我不知道具体是什么
I know it's gonna respond to these methods like will
但是我知道它拥有这些方法，比如
scroll, did scroll, should scroll,
willScroll, didScroll, shouldScroll

Chinese: 
those kinds of methods. That's all I know about it. So
我所知道的就是它有这类的方法
the controller, it signs up to listen to those methods,
所以控制器如果想要监听这些事件
and then it sets itself as the delegate in the view.
就可以把自己设为视图的 delegate
Okay, and we're gonna see this in action, so
我们还会实际用到的
don't worry about too much now, but that's how we can
所以现在理解不了不用担心
have structured communication where they're agreeing.
不过这就是规范通讯的方法
The view, this generic object is agreeing to
通用的视图同意
send certain messages to the controller,
给控制器发送一定的信息
not where the controller can be of any type and
所以控制器可以是任何类型的
still serve this purpose of controlling its view.
同时又能实现控制视图的功能
Now there's a special kind of communication between the view
控制器和视图之间还有一种特殊的联系
and the controller that arises because a view cannot own
起因是视图不会包含它所需要的数据
the data it displays. And what does that mean? That means you
这是什么意思呢？
don't want to have inside your view class, and remember, view
这意味着你不希望在视图
classes are like scroll views, buttons, things like that.
也就是比如滚动视图，按钮这些类中
You don't wanna have data in there that is
你不希望有特定的数据
the data you're displaying. I'll give you an example.
也就是要展示的数据。我们举个例子
Let's say your entire iPod music library,
比如你 iPod 里面的音乐库
let's say you have hundreds of thousands of songs in there.
里面有成千上万的歌曲
Okay, so I wanna have a list of them on screen. So
我希望把它们展示出来

English: 
those kinds of methods.         
That's all I know about it. So  
the controller, it signs up     
to listen to those methods,     
and then it sets itself as      
the delegate in the view.       
Okay, and we're gonna           
see this in action, so          
don't worry about too much      
now, but that's how we can      
have structured communication   
where they're agreeing.         
The view, this generic          
object is agreeing to           
send certain messages           
to the controller,              
not where the controller        
can be of any type and          
still serve this purpose        
of controlling its view.        
Now there's a special kind of   
communication between the view  
and the controller that arises  
because a view cannot own       
the data it displays. And what  
does that mean? That means you  
don't want to have inside your  
view class, and remember, view  
classes are like scroll views,  
buttons, things like that.      
You don't wanna have            
data in there that is           
the data you're displaying.     
I'll give you an example.       
Let's say your entire           
iPod music library,             
let's say you have hundreds of  
thousands of songs in there.    
Okay, so I wanna have a list    
of them on screen. So           

Chinese: 
I'm gonna use a generic item in my view called table view.
因此我用一个通用的 UITableView 来展示
Table view just shows a big long list of something.
表格视图的功能是显示一长串内容
It can be a list a million items long, okay? So
比如一个有一百万项内容的列表
if I really had to take my entire iPod library and
如果我需要把整个音乐库里的歌曲
put it in the value of a var of
放到 UITableView 的某个变量中
the table view to display it, that would be ridiculous.
让它去展示，那这样做是很荒唐的
Not just from a performance standpoint, but
先不考虑程序的性能
now I have two copies of my iPad, or
因为我现在相当于有两个 iPad
my iPod music library, one inside this table view, and
有两个 iPad 的音乐库：一个在表格视图里
one in some database somewhere in my phone. That's bad, where
一个在 iPhone 上的某个数据库里。这是不合适的
they could get out of sync, managing the synchronicity,
它们无法保持同步，内容可能会过时
what if I have multiple apps doing that? Ugh,
又比如我有很多个程序都在这么做呢？
it's a mess, so the view never wants to own that data, okay?
那简直是一团糟。所以视图不应该保存一份数据
So how the heck is it gonna get the data then?
那又要从哪里获得数据呢？
I've got 100,000 songs, I need to show it in this table,
我这里有很多首歌，我需要把它们显示到列表里
how's it gonna do it? Well, it's gonna use another one of
实现的方法是通过另一个
these protocol based vars, okay, called the data source.
存储协议类型的变量，这个叫做 dataSource
And the data source has different methods in it,
数据源拥有和代理不一样的方法
it's not will, should, did, it's how many items are in
就不是 will，should 和 did 了。数据源知道有多少
this piece of data? Give me the data at this location. And
也就是数据的具体个数，这个位置的数据是什么

English: 
I'm gonna use a generic item    
in my view called table view.   
Table view just shows a big     
long list of something.         
It can be a list a million      
items long, okay? So            
if I really had to take my      
entire iPod library and         
put it in the value             
of a var of                     
the table view to display it,   
that would be ridiculous.       
Not just from a performance     
standpoint, but                 
now I have two copies           
of my iPad, or                  
my iPod music library, one      
inside this table view, and     
one in some database somewhere  
in my phone. That's bad, where  
they could get out of sync,     
managing the synchronicity,     
what if I have multiple         
apps doing that? Ugh,           
it's a mess, so the view never  
wants to own that data, okay?   
So how the heck is it           
gonna get the data then?        
I've got 100,000 songs, I need  
to show it in this table,       
how's it gonna do it? Well,     
it's gonna use another one of   
these protocol based vars,      
okay, called the data source.   
And the data source has         
different methods in it,        
it's not will, should, did,     
it's how many items are in      
this piece of data? Give me     
the data at this location. And  

English: 
that, again,                    
is a var that controllers       
set in the table view, let's    
say, that points back to it.    
And so now every time           
the table view wants data,      
it asks the controller.         
And the controller almost       
always turns around and asks    
the model, give me that data.   
Now this also allows something  
like table view that's showing  
100,000 items. It can only      
show 10 on a screen at a time,  
so it only asks for 10 and      
shows them. And if you scroll   
down to somewhere else,         
it's gonna ask for that 10.     
And it's only keeping           
the ones it's displaying. So    
it's transferring a lot less    
data, only the data you're      
actually viewing, 10 out of     
100,000 songs. And so it's      
a lot more efficient, both      
in terms of memory usage and    
everything. Now you might       
be a little scared,             
like, every single              
time I'm gonna scroll,          
I'm gonna be asking for         
this data. But                  
keep in mind, the model for     
the iPod's music library is     
probably a SQL database or      
something, something that can   
serve up data super fast.       
That's it's job as a model to   
be the source of that data,     

Chinese: 
that, again, is a var that controllers
控制器会把 dataSource
set in the table view, let's say, that points back to it.
表格视图里的变量设为自己
And so now every time the table view wants data,
之后表格视图想要数据的时候
it asks the controller. And the controller almost
就会问 dataSource，也就是控制器
always turns around and asks the model, give me that data.
接着控制器一般会问模型，让它提供数据
Now this also allows something like table view that's showing
所以对于那些需要显示大量数据的表单视图
100,000 items. It can only show 10 on a screen at a time,
因为实际屏幕上每次只能显示 10 个
so it only asks for 10 and shows them. And if you scroll
可以只临时获得 10 条数据来显示。如果你向下滑
down to somewhere else, it's gonna ask for that 10.
滑动到了其他地方，它又去要另外 10 条
And it's only keeping the ones it's displaying. So
每次只缓存当前展示部分的数据
it's transferring a lot less data, only the data you're
所以每次传送的数据都很少，只是实际上
actually viewing, 10 out of 100,000 songs. And so it's
在展示的部分，比如十万首歌只选十首
a lot more efficient, both in terms of memory usage and
因此也变得更加高效，包括使用更少的内存
everything. Now you might be a little scared,
和其他的方面。现在你可能会担心
like, every single time I'm gonna scroll,
每次我滑动的时候
I'm gonna be asking for
我都要去获取这些数据啊
this data. But keep in mind, the model for
这你不必担心，你想想
the iPod's music library is probably a SQL database or
iPod 音乐库很有可能是类似于 SQL 的数据库
something, something that can serve up data super fast.
能够快速地获得数据
That's it's job as a model to be the source of that data,
这是它作为模型的任务就是提供数据

Chinese: 
okay? So that is usually not your performance bottleneck.
所以一般不会在性能上拖你的后腿
We're gonna talk about performance later in this
之后的课程我们会讲到性能
class, by the way. Usually the performance bottleneck is
这方面你通常会遇到的瓶颈
drawing on the screen. Things like getting data out of
是在屏幕上绘制内容。像这种从数据库中获取数据
databases, forget it. Drawing on the screen is much slower
你可以忽略不计。在屏幕上绘制很慢
and then going over the network is even slower.
通过网络加载内容更慢
So those things tend to dominate the performance of
这些才是影响你程序性能的主要原因
your app. Okay, so don't worry about that. So anyway, so
所以可以放心大胆地从模型加载数据
that's a couple of examples how we have the structured
通过这几个例子，我们具体了解了
communication from generic objects back to our
通用控件是如何采用规范化的通讯模式
controller. Now what about sorry, one statement that's
联系控制器的。等等，还有一句话
good to put in your mind that has all three camps in it,
你最好记住，在这三个阵营中
is that the controller interprets and formats
控制器负责把模型里的数据
the model for its views. Cuz its views are generic, they
转化为视图能接受的类型。因为视图是通用的
don't really know how to deal with any particular model.
它们并不知道如何处理任何特定的模型
A controller knows about both, so that's part of its job.
但控制器知道，所以由它负责
So a lot of times I'll be saying,
以后我会常说
the controller's job is to do this, and you'll be like,
“控制器负责这个”。这时候
yeah, I remember him saying that. All right, now what
你最好能想起我提到过这个。好，下一个
about the model communicating with the controller?
模型去联系控制器呢？

English: 
okay? So that is usually not    
your performance bottleneck.    
We're gonna talk about          
performance later in this       
class, by the way. Usually      
the performance bottleneck is   
drawing on the screen. Things   
like getting data out of        
databases, forget it. Drawing   
on the screen is much slower    
and then going over             
the network is even slower.     
So those things tend to         
dominate the performance of     
your app. Okay, so don't worry  
about that. So anyway, so       
that's a couple of examples     
how we have the structured      
communication from generic      
objects back to our             
controller. Now what about      
sorry, one statement that's     
good to put in your mind that   
has all three camps in it,      
is that the controller          
interprets and formats          
the model for its views. Cuz    
its views are generic, they     
don't really know how to deal   
with any particular model.      
A controller knows about both,  
so that's part of its job.      
So a lot of times               
I'll be saying,                 
the controller's job is to      
do this, and you'll be like,    
yeah, I remember him saying     
that. All right, now what       
about the model communicating   
with the controller?            

Chinese: 
Now this can never happen as well because the model is
这是不应该发生的，就像模型不依赖 UI 一样
UI independent. It knows nothing about any particular
模型对用户界面一无所知
UI, so there's no way it could talk to a UI guy like
所以它不能够和负责 UI 的控制器交流
the controller, okay? So what happens, though, if the model
那如果模型发生了变化呢？
changes, the data changes? That controller needs to know,
数据发生了改变呢？控制器必须要知道啊
because it wants to update the screen in that case.
这样它才能更新显示的数据
Well, the way we do that is with a model that
我们实现的方法是
kind of looks like a radio station, okay? The model
在模型中建立一个“电台”
basically has a radio station, and it broadcasts on that
通过这个电台发送广播通知
radio station, hey, I changed, or this about me changed. And
说“数据发生变化了”，或者是“这部分数据发生了变化”
then the controller tunes in to that radio station. And
控制器通过观察收听的那个电台
when it hears a broadcast, it asks the model what changed,
在接到通知的时候，就问模型什么数据变了
down that green arrow there, you see? Okay, so
还是通过我们这里的这个绿色通道
that's the model we're gonna use, that's the mechanism
所以这就是我们用的机制
we're gonna use to get stuff for our model that changes
通过这种方式让模型
to notify our controller. Some people ask, can
通知控制器。有人会问
a view tune in to a radio station? And the answer is,
视图应该收听那个电台吗？当然你可以
yeah, it probably could. It wouldn't necessarily violate
也并不一定会违背 MVC 的原则

English: 
Now this can never happen as    
well because the model is       
UI independent. It knows        
nothing about any particular    
UI, so there's no way it        
could talk to a UI guy like     
the controller, okay? So what   
happens, though, if the model   
changes, the data changes?      
That controller needs to know,  
because it wants to update      
the screen in that case.        
Well, the way we do that        
is with a model that            
kind of looks like a radio      
station, okay? The model        
basically has a radio station,  
and it broadcasts on that       
radio station, hey, I changed,  
or this about me changed. And   
then the controller tunes in    
to that radio station. And      
when it hears a broadcast, it   
asks the model what changed,    
down that green arrow there,    
you see? Okay, so               
that's the model we're gonna    
use, that's the mechanism       
we're gonna use to get stuff    
for our model that changes      
to notify our controller.       
Some people ask, can            
a view tune in to a radio       
station? And the answer is,     
yeah, it probably could. It     
wouldn't necessarily violate    

Chinese: 
MVC. But the problem is a generic view wouldn't know
但问题是，通用的视图并不知道
what radio station to tune into anyway, so it's really
具体要收听哪个电台。因为这是无法实现的
not an issue there. All right, so an MVC like this, though,
所以不会成为我们考虑的问题。然而，这样的一个 MVC
really is not, like your whole app isn't one big MVC.
不可能代表你整个程序，它不会只是一个大的 MVC
Each MVC controls either one screen on an iPhone or
每个 MVC 只会控制屏幕上的一个部分
maybe even a subpart of a screen on an iPhone or
甚至只会是屏幕上的一小部分
an iPad. Maybe there's two or
有可能 iPhone 或 iPad 上
three MVCs controlling what's going on on the screen, so
一个屏幕同时有两三个 MVC 来控制
how do we build a big app? An app, you know,
那我们如何构建一个大型项目呢？
it's building an Instagram app. I gotta have MVCs for
比如 Instagram 这种图片社交程序
posting, I gotta have MVCs for image editing so
我需要发图片的 MVC，我需要编辑图片的 MVC
I can do my sepia tone. I gotta have an MVC for
加个棕褐色的怀旧滤镜。我还需要一个 MVC
scrolling through the latest posts that are coming up.
让我通过滑动查看最新发布的内容
I mean, I need all kinds of MVCs. How do these things, how
我想说的就是我们需要各种各样的 MVC
do we combine them together? Well, looks like this.
这些 MVC 是如何协同工作的呢？实际上看起来是这样的
MVCs, when other MVCs point to them, it's always as
当一个 MVC 指向另一个 MVC 的时候
part of another MVC's view. So look at the three
被指像的那个会被作为当前 MVC 的视图
MVCs that are down here in the lower right corner.
看这里右下角的三个 MVC

English: 
MVC,. But the problem is        
a generic view wouldn't know    
what radio station to tune      
into anyway, so it's really     
not an issue there. All right,  
so an MVC like this, though,    
really is not, like your        
whole app isn't one big MVC.    
Each MVC controls either        
one screen on an iPhone or      
maybe even a subpart of         
a screen on an iPhone or        
an iPad. Maybe there's two or   
three MVCs controlling what's   
going on on the screen, so      
how do we build a big app?      
An app, you know,               
it's building an Instagram      
app. I gotta have MVCs for      
posting, I gotta have MVCs for  
image editing so                
I can do my sepia tone.         
I gotta have an MVC for         
scrolling through the latest    
posts that are coming up.       
I mean, I need all kinds of     
MVCs. How do these things, how  
do we combine them together?    
Well, looks like this.          
MVCs, when other MVCs point     
to them, it's always as         
part of another MVC's view.     
So look at the three            
MVCs that are down here in      
the lower right corner.         

English: 
You see these three MVCs? See   
this MVC up here, this purple   
one? Look how it points to      
them as if they were part of    
its view. You see that? There   
are no other arrows that point  
from one controller to          
another MVC except for          
that goes through this          
view side of the MVC.           
Let me help you make that       
more concrete why that is.      
Let's say I had an app and it   
was a calendar app, and it was  
showing me the year, okay,      
a whole year's worth of my      
calendar entries. Well, on a    
tiny screen it's barely gonna   
be able to show me the 12       
months, let alone the days and  
the things, right? So it's got  
this picture of the months.     
So that's a year MVC, let's     
say, in my calendar app. So     
I click on one of the months    
cuz I want some more detail.    
And now that year MVC           
moves out of the way and        
puts up an MVC that's showing   
all the days of a month, okay?  
Well, that month MVC, which     
is a totally separate MVC,      
do you see how it's part        
of the year MVC's view?         
Because the year MVC            
is showing months.              

Chinese: 
You see these three MVCs? See this MVC up here, this purple
看到这三个了吗？看到上面中间的这个紫色的控制器了吗？
one? Look how it points to them as if they were part of
它就是通过像连接自己视图一样指向这些 MVC
its view. You see that? There are no other arrows that point
看到了吗？这里所有的箭头
from one controller to another MVC except for
其中从一个控制器到另一个控制器的那些
that goes through this view side of the MVC.
无一不是通过视图这边连接的
Let me help you make that more concrete why that is.
我再具体解释为什么是这样
Let's say I had an app and it was a calendar app, and it was
比如我有一个日历程序
showing me the year, okay, a whole year's worth of my
展示了整整一年，一年里所有的日期
calendar entries. Well, on a tiny screen it's barely gonna
对于比较小的屏幕来说，很难让它
be able to show me the 12 months, let alone the days and
展示十二个月里全部的日子和其他内容
the things, right? So it's got this picture of the months.
所以我选择只显示每个月
So that's a year MVC, let's say, in my calendar app. So
这就是这个日历应用里负责每一年的 MVC
I click on one of the months cuz I want some more detail.
如果我需要更多细节，就点对应的月份
And now that year MVC moves out of the way and
这个时候每年的 MVC 就隐藏了
puts up an MVC that's showing all the days of a month, okay?
同时换上显示这个月每一天的 MVC
Well, that month MVC, which is a totally separate MVC,
这个负责每个月的 MVC 和之前的是完全分开的
do you see how it's part of the year MVC's view?
可以看出为什么是作为年这个 MVC 的视图了吗？
Because the year MVC is showing months.
因为每年里会展示这些月份

English: 
You wanna look at it,           
it's trying to zoom in on it,   
it does it with another MVC.    
And same thing, in the month,   
if I click on a day, the month  
MVC's gonna move out of         
the way. Put a day MVC that     
shows me all my appointments,   
for a day and that day MVC      
would be part of the view of    
the month MVC, okay,            
make sense? So that's why,      
that's the only relationship    
we have between MVCs is across  
this view boundary. Now there   
can be other communication,     
however. Look right here.       
This MVC, the purple one        
in the top middle there,        
it's communicating to a model   
that is the same model as some  
other MVC. So MVCs can share    
the same model. That's          
perfectly fine. The models      
are completely UI independent.  
They don't care how many MVCs   
are looking at them, okay?      
Cuz they don't even             
know about controllers.         
Right, they're completely       
independent of that.            
Also notice these two           
models down at the bottom,      
they're talking to each other.  
That's okay, too, because       
a model can be defined any way  
it wants. It's UI independent,  
it can talk to other models,    
whatever.                       

Chinese: 
You wanna look at it, it's trying to zoom in on it,
你会在看了之后尝试放大到每个月的视图
it does it with another MVC. And same thing, in the month,
这是通过另一个 MVC 实现的。同理，在每个月里
if I click on a day, the month MVC's gonna move out of
如果我点具体一天，负责那个月的 MVC 就消失了
the way. Put a day MVC that shows me all my appointments,
换成现实当天日程的 MVC
for a day and that day MVC would be part of the view of
这个每一天的 MVC 又是那个月 MVC 的视图
the month MVC, okay, make sense? So that's why,
我说的有道理吧？这就是为什么
that's the only relationship we have between MVCs is across
MVC 间的关系只会是
this view boundary. Now there can be other communication,
作为另一个的视图。我们再看看其他种类的通信
however. Look right here.
比如看这里
This MVC, the purple one in the top middle there,
这个上面中间的紫色控制器
it's communicating to a model that is the same model as some
它联系的模型和另一个 MVC 是相同的
other MVC. So MVCs can share the same model. That's
也就是 MVC 之间可以共享模型
perfectly fine. The models are completely UI independent.
这是允许的，因为模型不会和 UI 挂钩
They don't care how many MVCs are looking at them, okay?
因此并不会介意被多个 MVC 共享
Cuz they don't even know about controllers.
它们也不了解具体的控制器
Right, they're completely independent of that.
所以也是能保持独立的
Also notice these two models down at the bottom,
还要注意这下面的两个模型
they're talking to each other. That's okay, too, because
它们在相互传递信息。这也是可以的
a model can be defined any way it wants. It's UI independent,
因为模型想怎么实现就怎么实现，和 UI 不相关
it can talk to other models, whatever.
所以能够联系其他模型

English: 
Now of course, it's still       
gonna wanna radio broadcast if  
maybe this model changes        
something in it. But            
it still can talk               
directly to the model, so       
that's the other communication  
that can happen. But            
no other communication          
can happen.                     
We do not want our apps         
to look like this. Okay,        
we've got these MVCs, and       
look, see this view over here?  
It's talking to a different     
controller. This controller is  
talking directly to another     
one, not out of view, but       
just off to this side. You      
don't want this mess. If you    
do this mess, you really,       
you're not even doing an MVC.   
Cuz everybody's                 
in the same camp,               
they're all just                
talking to each other,          
okay? So this is a no-go.       
And, of course,                 
I'll be showing you, not next   
week, but the week after,       
how we build these connections  
between MVCs. For the first     
two weeks, we're just gonna     
focus on building one MVC,      
our calculators, one MVC. But   
we're gonna add another MVC to  
our calculator in week three.   
And you're gonna see, that's    
how we wire these things up,    
okay? So that's MVCs.           
We're gonna dive back into      
continuing our calculator       
demo here. Again,               
this is a slide you're          
gonna look at later and         

Chinese: 
Now of course, it's still gonna wanna radio broadcast if
当然，如果模型的内容会发生改变
maybe this model changes something in it. But
还是要通过“电台”通知
it still can talk directly to the model, so
同时直接联系当然是可以的
that's the other communication that can happen. But
这就是最后一种沟通的方式
no other communication can happen.
除此以外就没有了
We do not want our apps to look like this. Okay,
我们不希望程序最后变成这样
we've got these MVCs, and look, see this view over here?
我们有一团 MVC。看这里的这个视图
It's talking to a different controller. This controller is
它在和不同的控制器通信
talking directly to another one, not out of view, but
这个控制器不是通过视图
just off to this side. You don't want this mess. If you
而是直接操作另一个控制器。你不会想要这样的乱局
do this mess, you really, you're not even doing an MVC.
如果最后变成了这样，其实你是没有使用 MVC 的
Cuz everybody's in the same camp,
因为没有分工，都在一个阵营里
they're all just talking to each other,
想说就说，为所欲为
okay? So this is a no-go. And, of course,
所以这是不被允许的
I'll be showing you, not next week, but the week after,
我会在再下一周展示
how we build these connections between MVCs. For the first
如何建立 MVC 之间的联系
two weeks, we're just gonna focus on building one MVC,
我们前两周的时间，只会用到一个 MVC
our calculators, one MVC. But
我们的计算器只是一个 MVC
we're gonna add another MVC to our calculator in week three.
第三周的时候再加入另一个 MVC
And you're gonna see, that's how we wire these things up,
然后你就知道如何把它们链接起来了
okay? So that's MVCs. We're gonna dive back into
MVC 就讲完了
continuing our calculator demo here. Again,
我们继续完成计算器
this is a slide you're gonna look at later and
同样的，这一页是给你们之后看的

Chinese: 
say, did I learn all these things? I hope so.
问问自己是否学会了。我希望是的
And I'm not going back to these slides.
我准备现在把课件放完
So let me talk about what's coming up. On Friday, we have
所以讲讲接下来几节课的内容
this debugging Friday session. I still don't have a room for
星期五是讲调试，我还没有找到教室
it, but it will be announced on Piazza.
找到后会在 Piazza 上通知
It's gonna be around noon, maybe 1 o' clock,
课程大概在中午的时候吧，也许是下午一点
maybe 11. I know some of you have conflicting things
或者是上午十一点。我知道你们那个时候都很忙
in that time and might not be able to make it.
很有可能没法来上课
It's optional, I hope you're all able to make it, however.
这是选修课，不过我还是希望你们能尽量参加
We'll also in that one, be going over some like Xcode
不过我们还会讲些 Xcode 里常用的快捷键
shortcuts, how to get around in Xcode a little more easily.
如何更便捷地使用 Xcode
Cuz I always end up clicking on everything, so
我总是通过点击操作
you can see what I'm doing. But
好让你们看清我在干什么
there's command keys you can do to really master Xcode. And
不过你可以掌握 Xcode 提供的快捷键
then don't forget Monday's a holiday, so
星期一放假
don't show up here.
你们不要跑来上课
And then next Wednesday, the reading assignment I
下周三，要完成我星期一布置的阅读作业
assigned on Monday, plus the programming assignment that
以及编程作业
I just put on Piazza today, are both due
我今天才放上 Piazza 的那个
next Wednesday. And then next Wednesday, you'll get another
下周三两个都要交。下周三
reading assignment and another programming assignment,
我还会布置另一个阅读作业和编程作业
which will be due a week later, okay? Okay,
再下周交，好吧
here we go, back to our calculator, here's where,
好了，可以开始编计算器了

English: 
say, did I learn all            
these things? I hope so.        
And I'm not going               
back to these slides.           
So let me talk about what's     
coming up. On Friday, we have   
this debugging Friday session.  
I still don't have a room for   
it, but it will be              
announced on Piazza.            
It's gonna be around noon,      
maybe 1 o' clock,               
maybe 11. I know some of        
you have conflicting things     
in that time and                
might not be able to make it.   
It's optional, I hope you're    
all able to make it, however.   
We'll also in that one,         
be going over some like Xcode   
shortcuts, how to get around    
in Xcode a little more easily.  
Cuz I always end up             
clicking on everything, so      
you can see what I'm doing.     
But                             
there's command keys you can    
do to really master Xcode. And  
then don't forget               
Monday's a holiday, so          
don't show up here.             
And then next Wednesday,        
the reading assignment I        
assigned on Monday, plus the    
programming assignment that     
I just put on Piazza today,     
are both due                    
next Wednesday. And then next   
Wednesday, you'll get another   
reading assignment and another  
programming assignment,         
which will be due a week        
later, okay? Okay,              
here we go, back to our         
calculator, here's where,       

English: 
exactly where we left off       
right here. And as I said when  
we were there, this is          
a great little calculator,      
it's nice. But it's kind of     
bad that this code right here,  
which is the what of this       
calculator, what is this?       
This is a calculator. Here's    
the calculations happening.     
That really needs to be         
in a different camp.            
It can't be in the controller   
like this. So that's the main   
thing we're gonna do in         
this demo right here,           
is we're gonna                  
create a model for              
this calculator,                
where we're gonna put           
all this calculation.           
And then we're gonna make this  
model really powerful and       
extensible as you'll see. So,   
we need to create a new data    
structure for our model, and    
we do that with                 
File > New File.                
Any time we wanna create a new  
class or new structure or       
any kinda new data structure,   
this is what we do.             
So we hit this, it's gonna      
be a Swift File right here.     
We'll look at it, maybe one or  
two of these others,            
actually we probably            
won't even look at those.       
It's almost always gonna be     
a Swift File that you create    

Chinese: 
exactly where we left off right here. And as I said when
这是我们之前讲到的地方
we were there, this is a great little calculator,
之前说这个计算器看起来不错
it's nice. But it's kind of bad that this code right here,
只不过金玉其外，败絮其中
which is the what of this calculator, what is this?
主要是这部分实现计算器功能的代码
This is a calculator. Here's the calculations happening.
这是什么？一个计算器，由这里完成计算
That really needs to be in a different camp.
这应该放到另一个阵营里
It can't be in the controller like this. So that's the main
并不应该放在控制器中。所以我们主要的内容
thing we're gonna do in this demo right here,
也就是我们今天要完成的是
is we're gonna create a model for
给这个计算器
this calculator,
创建一个模型
where we're gonna put all this calculation.
负责所有的计算
And then we're gonna make this model really powerful and
然后我们要把这个计算器编的很强大
extensible as you'll see. So,
同时可高度定制
we need to create a new data structure for our model, and
我们控制器需要一个新的数据结构
we do that with File > New > File.
所以通过菜单栏中的 File > New > File
Any time we wanna create a new class or new structure or
任何时候我们想要新建一个类，结构体
any kinda new data structure, this is what we do.
或是其他数据类型的时候，我们都这样新建一个文件
So we hit this, it's gonna be a Swift File right here.
我们点这个 Swift File
We'll look at it, maybe one or two of these others,
我们也许会用到这些
actually we probably won't even look at those.
其实基本上不会用到
It's almost always gonna be a Swift File that you create
我们基本都会选 Swift File

Chinese: 
here. Here it is, it wants to know the name. So this is
点 Next 之后问你文件的名字
the brain of my calculator, right, the guts of it.
因为它是计算器的“大脑”，内部结构
So I'm gonna call this CalculatorBrain. That's gonna
所以叫做 CalculatorBrain
be the name of the data structure that I'm gonna use
我们把它作为这个数据结构的名字
here. And I'm gonna make sure I put it in the same group,
确认我下面选择把它放在
down here, as all the rest of my
和其他文件同一个 Group 中
classes like ViewController, see that ViewController.swift?
比如 ViewController，看到 ViewController.swift 了吗？
I'm gonna put it in the same place there.
我要把它们放在一起
All right, so here it is on the left and right,
好了，一左一右
actually, let's just make it fill the whole screen.
还是隐藏 Assistant Editor 好了，全屏
If we look in the navigator, now we have three files,
如果我们看这里的导航器，现在就有三个文件了
okay, there's our controller, there's our view, and
ViewController 是控制器，Storyboard 负责视图
there's our model, MVC, voila, okay, it's that easy. Now,
最后是模型。MVC，看吧，就这么简单
we need (in this model) to think a little bit about what its
要好好想想这个模型应该包含哪些公共 API
public API is. In other words, what does this model allow
公共接口，也就是这个模型允许其他人
other people, like controllers,
比如控制器
to do? Okay, that's one of the most fundamental things that
实现的操作。最基础的部分
you wanna do whenever you're doing design.
你设计数据结构的时候都要考虑的
Just think about what the public API, does everyone know
设计好公共接口。大家都知道什么是应用程序编程接口吗？

English: 
here. Here it is, it wants      
to know the name. So this is    
the brain of my calculator,     
right, the guts of it.          
So I'm gonna call this          
CalculatorBrain. That's gonna   
be the name of the data         
structure that I'm gonna use    
here. And I'm gonna make sure   
I put it in the same group,     
down here,                      
as all the rest of my           
classes like ViewController,    
see that ViewController.swift?  
I'm gonna put it in             
the same place there.           
All right, so here it is        
on the left and right,          
actually, let's just make       
it fill the whole screen.       
If we look in the navigator,    
now we have three files,        
okay, there's our controller,   
there's our view, and           
there's our model, MVC, voila,  
okay, it's that easy. Now,      
we need in this model to think  
a little bit about what its     
public API is. In other words,  
what does this model allow      
other people,                   
like controllers,               
to do? Okay, that's one of the  
most fundamental things that    
you wanna do whenever           
you're doing design.            
Just think about what the       
public API, does everyone know  

English: 
what API means? Application     
programming interface.          
It's all the methods and        
properties. Snd so              
your public API is the methods  
and properties you're gonna     
allow other classes or other    
data structures to access.      
So we really, really wanna      
think about that. Quickly also  
notice that we've imported      
Foundation here, not UIKit,     
because this is not going to    
be a UI class, right? This      
is UI independent, this is the  
model. Now I could say here,    
okay, let's create a class      
called CalculatorBrain. Nope,   
not Brian, brain. So I could    
do that, but I'm actually not   
going to do that. I'm gonna     
use a different data structure  
here than a class, all right?   
I'm gonna use a struct. Now,    
you're probably used to using   
struct in other languages, but  
you probably think of it as     
just like a little collection   
of other variables is           
a struct. In Swift,             
struct is a first               
class citizen,                  
very much like the class,       
okay? And I'm gonna talk about  
the difference between that     
in a second. And in fact,       

Chinese: 
what API means? Application programming interface.
Application Programming Interface，API
It's all the methods and properties. Snd so
即所有的方法和属性
your public API is the methods and properties you're gonna
public API，公共的接口是
allow other classes or other data structures to access.
你允许其他类和结构体访问的方法和属性
So we really, really wanna think about that. Quickly also
所以我们要好好考虑
notice that we've imported Foundation here, not UIKit,
注意到这里是 import Foundation，而不是 UIKit
because this is not going to be a UI class, right? This
因为这不会是和 UI 相关的类
is UI independent, this is the model. Now I could say here,
这是模型，是独立于用户界面的。我在这里可以写
okay, let's create a class called CalculatorBrain. Nope,
class CalculatorBrain，创建一个类
not Brian, brain. So I could do that, but I'm actually not
打错了，是 Brain，不是 Brian。我可以这么做
going to do that. I'm gonna use a different data structure
但我不会这么做。因为我会使用另一种数据类型
here than a class, all right? I'm gonna use a struct. Now,
不是 class（类）而是 struct（结构体）
you're probably used to using struct in other languages, but
你可能在其他语言中使用过结构体
you probably think of it as just like a little collection
认为那就是个集合
of other variables is a struct. In Swift,
包含了些其他的变量
struct is a first class citizen,
在 Swift 中 struct 是一等公民
very much like the class, okay? And I'm gonna talk about
和 class 是差不多的
the difference between that in a second. And in fact,
我马上会讲到底有什么区别

Chinese: 
most of the commonly used classes in Swift are structs,
事实上 Swift 里常用的“类”其实都是结构体
like string, double, array, dictionary,
比如 String，Double，Array，Dictionary
these are all structs, they're not classes. So
都是结构体，不是类
what's the difference between a struct and a class?
那结构体和类的区别在哪里呢？
I'm gonna talk in detail about it next week, but
我下周会详细说明
I'm gonna tell you two important differences,
但接下来会先说说两个重要区别
the two most important differences.
非常重要的区别
One thing, classes have inheritance,
第一个，类是可以继承的
structs do not, okay? So if you're building
但结构体不行。所以如果你想
something that you think is gonna need to be sub classed
构造一个能扩展的对象
to be extensible, you probably wanna make it a class. I'm
就必须用类
gonna make my CalculatorBrain extensible in a different way
我用其他方式扩展 CalculatorBrain
as you'll see, so
如你马上所见的
it doesn't need to be a class. I could possibly change
所以我没有使用类。如果我稍后改变主意
it back to a class if I change my idea later, but
可以随时改为类
my current architecture does not need to be sub classed,
但我当前的结构不需要 CalculatorBrain 的子类
so that's one difference. The other difference,
这是其一。另外一个区别
huge difference, and
本质的区别
the one that's gonna take the most getting used to for
也是你需要理解的概念
you conceptually, is that classes live in the heap, and
类存储在堆中
you have pointers to them. Structs do not live in
通过指针传递。结构体存储在栈上
the heap, and they are passed around by copying them, okay?
通过拷贝值传递

English: 
most of the commonly used       
classes in Swift are structs,   
like string, double,            
array, dictionary,              
these are all structs,          
they're not classes. So         
what's the difference           
between a struct and a class?   
I'm gonna talk in detail        
about it next week, but         
I'm gonna tell you two          
important differences,          
the two most important          
differences.                    
One thing,                      
classes have inheritance,       
structs do not, okay?           
So if you're building           
something that you think is     
gonna need to be sub classed    
to be extensible, you probably  
wanna make it a class. I'm      
gonna make my CalculatorBrain   
extensible in a different way   
as you'll see, so               
it doesn't need to be a class.  
I could possibly change         
it back to a class if I         
change my idea later, but       
my current architecture does    
not need to be sub classed,     
so that's one difference.       
The other difference,           
huge difference, and            
the one that's gonna take       
the most getting used to for    
you conceptually, is that       
classes live in the heap, and   
you have pointers to them.      
Structs do not live in          
the heap, and they are passed   
around by copying them, okay?   

Chinese: 
We call the copying style value types.
我把拷贝值传递叫值类型
We call the, in the heap file, style, reference types.
存储在堆中的方式叫引用类型
Because we have a reference to them in the class case,
类通过引用来使用
we actually copy them around in the struct case.
而结构体需要拷贝值使用
Now, you know, that might seem like a big restriction.
那看起来，使用结构体会有很大的限制
I gotta copy these things around, what if they're big?
结构体很大的时候，也会拷贝吗？
But as I mentioned on Monday, these things are passed around
星期一提到的，凡是通过拷贝值传递的
copy on right. So when you pass them around, if you don't
都会采用“写时复制”，也就是如果
actually change them, then no copy is actually made. Okay,
没有改变它的值，那么是不会进行拷贝的
but it's all behind the scenes for you, all right?
这些都是在内部自动完成的
So that's a huge difference.
这就是本质的差别
Now why would I want my CalculatorBrain to be a struct
为什么我会把 CalculatorBrain 定义为结构体而不用类呢？
instead of a class? Well, I don't imagine I'm gonna have
因为我想象不到会有
a whole bunch of different people referencing it.
其他地方需要引用它
The CalculatorBrain is a brain for an MVC.
CalculatorBrain 是 MVC 的核心
So that MVC is gonna access it, but I, I don't see a lot
所以 MVC 会访问它，除此之外
of other entities somehow trying to point to this thing.
没有其他实体会尝试引用它
So I don't really need to be reference type,
所以我不需要引用类型
okay. I can have it be a value type from that standpoint. So
基于这点，我使用值类型
it's probably fine. Also it's a great opportunity for
而且这是个很好机会

English: 
We call the copying             
style value types.              
We call the, in the heap file,  
style, reference types.         
Because we have a reference     
to them in the class case,      
we actually copy them           
around in the struct case.      
Now, you know, that might       
seem like a big restriction.    
I gotta copy these things       
around, what if they're big?    
But as I mentioned on Monday,   
these things are passed around  
copy on right. So when you      
pass them around, if you don't  
actually change them, then no   
copy is actually made. Okay,    
but it's all behind the scenes  
for you, all right?             
So that's a huge difference.    
Now why would I want my         
CalculatorBrain to be a struct  
instead of a class? Well,       
I don't imagine I'm gonna have  
a whole bunch of different      
people referencing it.          
The CalculatorBrain is          
a brain for an MVC.             
So that MVC is gonna access     
it, but I, I don't see a lot    
of other entities somehow       
trying to point to this thing.  
So I don't really need          
to be reference type,           
okay. I can have it be a value  
type from that standpoint. So   
it's probably fine. Also        
it's a great opportunity for    

English: 
me to show you what it looks    
like to make a struct because   
making a struct looked almost   
just like being a class,        
but there's a couple            
minor differences,              
which you're gonna see          
real soon here, okay?           
So now back to the public API,  
what is the public API of       
this? Well, I know that         
this CalculatorBrain is gonna   
need a func that performs       
operation. Okay, for sure       
because that's fundamentally    
what it does. It performs       
an operation. And we'll use     
the same mechanism we used      
on Monday to define it.         
I will have some mathematical   
symbol be the thing that        
defines what operation we're    
performing, okay? And notice    
that I made the external name   
be blank. It's a close call     
here as whether you would       
want it to be symbol.           
In other words, would I call    
performOperation like this,     
okay, performOperation(symbol,  
whatever. Or                    
whether I want it to be blank,  
and I say performOperation,     
and I just put the string,      
the symbol in here like pi or   
whatever.                       
It's a close call here,         

Chinese: 
me to show you what it looks like to make a struct because
让我展示如何使用结构体
making a struct looked almost just like being a class,
像使用类一样使用结构体
but there's a couple minor differences,
但多多少少还是有些区别的
which you're gonna see real soon here, okay?
你很快就会知道
So now back to the public API,
OK，回到 public API（公共接口）
what is the public API of this? Well, I know that
这里需要定义什么公共接口呢？
this CalculatorBrain is gonna need a func that performs
我知道 CalculatorBrain 需要一个方法来执行数学计算
operation. Okay, for sure because that's fundamentally
这是最基本的要求
what it does. It performs an operation. And we'll use
它需要执行数学计算
the same mechanism we used on Monday to define it.
我们用周一使用的方式来定义它
I will have some mathematical symbol be the thing that
我会通过数学符号
defines what operation we're performing, okay? And notice
来判断需要执行什么计算
that I made the external name be blank. It's a close call
注意，这里实参标签（argument label）为空
here as whether you would want it to be symbol.
但你可能觉得实参标签叫 symbol 更好
In other words, would I call performOperation like this,
或者说，我会这样调用 performOperation
okay, performOperation(symbol, whatever. Or
performOperation(symbol: XXXXX)
whether I want it to be blank, and I say performOperation,
相比之下，我觉得留空更好，我会这样读 performOperation
and I just put the string, the symbol in here like pi or
然后把像 pi 或者其他符号放进去
whatever. It's a close call here,
这更贴近调用的意思

English: 
this is a close judgement       
call as to which is better.     
I'm gonna go with this because  
I think reading this code,      
performOperation pi makes       
perfect sense to me.            
Adding the word symbol          
in there doesn't really         
make it any clearer to me, so   
that's the way I'm gonna        
go with this one. Okay,         
what else do I need? Well, if   
you're performing operations,   
you have to have operands       
to perform one, right?          
If you're doing square root,    
you have to do square root      
of something, whatever. So      
I'm gonna have to have some     
func that sets the operand as   
well, okay? And again, I'm      
gonna have no external name,    
and we'll call it the operand.  
And I'm gonna have my           
entire CalculatorBrain          
work in doubles. It's           
gonna be a double precision     
CalculatorBrain, so I'm gonna   
have the operand be a double.   
Now, here's a case where I      
definitely know that I don't    
wanna have an external name,    
because saying setOperand       
(operand: 5.0), that's          
ridiculous, that's completely   
redundant, don't need it.       
It's very clear, if I do this,  
setOperand(5.0).                
That's clear what I'm talking   
about. So no question in my     

Chinese: 
this is a close judgement call as to which is better.
很容看出哪种调用方式更好
I'm gonna go with this because I think reading this code,
我会保留这样，因为我觉得代码更通顺易读
performOperation pi makes perfect sense to me.
performOperation("π") 读起来更通顺
Adding the word symbol in there doesn't really
在这里增加 symbol 字符作为实参标签
make it any clearer to me, so
并没有提高可读性
that's the way I'm gonna go with this one. Okay,
所以我选择这样写
what else do I need? Well, if you're performing operations,
OK，接下来还要做什么？很明显，如果要执行计算
you have to have operands to perform one, right?
就必须要一个操作数
If you're doing square root,
如果要执行平方根
you have to do square root of something, whatever. So
那么你必须对某个操作数执行平方根
I'm gonna have to have some func that sets the operand as
所以我必须定义一个方法来设置操作数
well, okay? And again, I'm gonna have no external name,
参数这里依然没有实参标签
and we'll call it the operand. And I'm gonna have my
形参名称（parameter name）叫 operand
entire CalculatorBrain work in doubles. It's
我让整个 CalculatorBrain 都使用 double（浮点类型）
gonna be a double precision CalculatorBrain, so I'm gonna
所以 CalculatorBrain 是浮点精度的
have the operand be a double. Now, here's a case where I
所以我定义 operand 也是浮点类型
definitely know that I don't wanna have an external name,
这里我也没有定义实参标签
because saying setOperand (operand: 5.0), that's
因为 setOperand(operand: 5.0) 并不通顺
ridiculous, that's completely redundant, don't need it.
有点累赘，完全是多余的，所以不需要
It's very clear, if I do this, setOperand(5.0).
setOperand(5.0) 更容易理解
That's clear what I'm talking about. So no question in my
而且读起来也更通顺，我觉得

English: 
mind that that's better.        
And then you set the operand,   
you perform operations,         
guess what? You gotta           
get the result. Now, I could    
have a func to getResult or     
something like that.            
That returns a double, right?   
That's one thing I do. But      
that's really not very Swift.   
Really in Swift what you would  
do is you say, here's a result  
var, that returns result. Now   
the only problem with that UI,  
or that API rather, is I don't  
want anyone to set my result.   
I'm the calculator brain,       
I calculate the result. So      
this needs to be read-only.     
Anyone remember how we          
can make a var read-only?       
No? Someone suggest let.        
And that's kinda                
not exactly what let does.      
Let makes it to constant,       
meaning that it's read-only.    
But it can only set once.       
Whereas result is constantly    
changing. So we can't do let,   
unfortunately.                  
But it's a really good guess.   

Chinese: 
mind that that's better. And then you set the operand,
这样更好。然后这里设置 operand
you perform operations, guess what? You gotta
执行了某个运算，然后呢？
get the result. Now, I could have a func to getResult or
你需要一个方法来获取计算结果。我可以定义一个方法
something like that. That returns a double, right?
像 getResult 之类的，返回的是浮点类型
That's one thing I do. But that's really not very Swift.
就像这样，但不推荐在 Swift 这么做
Really in Swift what you would do is you say, here's a result
在 Swift 里，最好这样，定义一个 result 变量
var, that returns result. Now the only problem with that UI,
这就是计算返回的结果。唯一要注意的是
or that API rather, is I don't want anyone to set my result.
对于这个 API（应用程序接口），我不希望其他人能修改结果
I'm the calculator brain, I calculate the result. So
结果应该计算器来计算
this needs to be read-only.
所以要定义这个变量为只读
Anyone remember how we can make a var read-only?
有谁知道怎么设置变量为只读？
No? Someone suggest let. And that's kinda
没人知道吗？有人说用 let
not exactly what let does. Let makes it to constant,
用 let 有点不太准确。因为 let 定义的是常量
meaning that it's read-only. But it can only set once.
虽然也是只读，但 let 只能在定义的时候赋值
Whereas result is constantly changing. So we can't do let,
计算结果需要不断变化，所以不能用 let
unfortunately. But it's a really good guess.
但这是个好想法

English: 
Actually we do it with the      
computed property thing. Okay,  
remember we computed            
that display value and          
we had get and set? Well, we    
just don't do the set, right?   
In this case we're just not     
gonna do. Just not put that on  
there. Boom,                    
this is a read-only property.   
Everybody got that? It's        
like currentTitle on button.    
It's get only. All right now,   
I'm gonna think a little        
bit about the internal          
implementation of this before   
I go and start using this       
thing. I know that a            
calculator brain, internally,   
it kind of accumulates its      
answer as it's going. And       
so I'm actually gonna have an   
internal var, and watch this,   
private var. I'm gonna          
call it accumulator, I'm        
gonna make it a double, okay?   
So this is gonna be internal.   
So now, other people            
can't access this.              
That's what private means.      
And for all your homeworks for  
this entire quarter, I want     
you to put private in front of  
things that you think           
are internal implementation.    
To any class you've create in   
this, in this course, okay?     

Chinese: 
Actually we do it with the computed property thing. Okay,
实际上可以使用 computed property（计算型属性）
remember we computed that display value and
记得之前定义 displayValue 变量的
we had get and set? Well, we just don't do the set, right?
get 和 set 属性吗？只要去掉 set 就可以了
In this case we're just not gonna do. Just not put that on
在这里，把 set 去掉，留下 get
there. Boom, this is a read-only property.
这就是只读属性
Everybody got that? It's like currentTitle on button.
就像 button 的 currentTitle 属性
It's get only. All right now,
也是只读的。接下来
I'm gonna think a little bit about the internal
在使用之前，我需要考虑下
implementation of this before I go and start using this
这里内部如何实现
thing. I know that a calculator brain, internally,
我知道计算器内部
it kind of accumulates its answer as it's going. And
需要保存计算的结果
so I'm actually gonna have an internal var, and watch this,
所以我定义一个私有变量，看这里
private var. I'm gonna call it accumulator, I'm
private var（私有变量），命名为 accumulator
gonna make it a double, okay? So this is gonna be internal.
类型为 double（浮点类型）。这是一个私有变量
So now, other people can't access this.
其他外部成员无法访问它
That's what private means. And for all your homeworks for
这就是私有的含义。在这季的所有作业里
this entire quarter, I want you to put private in front of
我希望你在所有你认为是内部使用的变量前
things that you think are internal implementation.
都增加 private 关键字
To any class you've create in this, in this course, okay?
任何本课程中写的代码都这么做

English: 
So get used to doing that.      
It's very important.            
These three are not private.    
They're public.                 
I'm gonna allow other           
people to call these. But       
this one is internal.           
Now, one thing you notice is    
I don't have any error up here  
that says no initializer.       
Remember that when              
I created a var in              
the view controller,            
and it said that there's no     
initializers. And I had to      
make userInTheMiddleOfTyping    
equal false. Why don't          
I have to do it here? That's    
because this is a struct. And   
structs automatically           
get an initializer.             
That will initialize all of     
their uninitialized vars,       
okay?                           
You get a free initializer.     
You don't get that with class.  
Only with the structs, so       
there is one difference         
between class and structs.      
So we're gonna have a struct,   
for CalculatorBrain, or         
an initializer for              
CalculatorBrain. That will      
take a double and it'll         
initialize as accumulator.      
But actually,                   
I don't wanna do that.          
Because let me think of what    
is accumulator's initial value  
really wanna be? When someone   
creates a CalculatorBrain,      

Chinese: 
So get used to doing that. It's very important.
要成为一种习惯，这很重要
These three are not private. They're public.
这三个不是私有的，是公有的
I'm gonna allow other people to call these. But
其他外部成员可以访问调用它们
this one is internal. Now, one thing you notice is
这个是内部私有的。有一点要注意
I don't have any error up here that says no initializer.
这里没有初始化，但没有提示任何错误
Remember that when I created a var in
记得之前在 ViewController 中
the view controller,
创建变量吗？
and it said that there's no initializers. And I had to
会抛出没有初始化的错误
make userInTheMiddleOfTyping equal false. Why don't
必须初始化 userInTheMiddleOfTyping 等于 false
I have to do it here? That's because this is a struct. And
为什么这里不需要呢？这是因为这是结构体
structs automatically get an initializer.
结构体会自动提供一个构造器
That will initialize all of their uninitialized vars,
通过那个构造器来初始化所有未初始化的属性
okay? You get a free initializer.
所以你并不需要自己提供一个构造器
You don't get that with class. Only with the structs, so
但在类中就不能这样做，只有结构体可以
there is one difference between class and structs.
这也是类和结构体的一个区别
So we're gonna have a struct, for CalculatorBrain, or
好，现在已经有个叫 CalculatorBrain 的结构体
an initializer for CalculatorBrain. That will
它自动提供的构造器
take a double and it'll initialize as accumulator.
会通过浮点类型的参数来初始化 accumulator 变量
But actually, I don't wanna do that.
但实际上，我并不希望它这么做
Because let me think of what is accumulator's initial value
我们真正想把 accumulator 初始化为什么？
really wanna be? When someone creates a CalculatorBrain,
当 CalculatorBrain 被创建的时候

English: 
I don't wanna have them to      
tell me what the accumulator's  
initial value is.               
Because I know what the         
initial accumulator internally  
its initial value is when       
I start up. It's not set.       
So I'm gonna make               
this be an optional.            
Do you see why I'm              
making that an optional?        
Because the accumulator when    
I create my brain. I haven't    
accumulated any result.         
So I'm in this not set state.   
So, it's a perfect opportunity  
to make this a double or        
an optional so I can express    
that in my code. All right? So  
if I have this internal         
accumulator right here,         
how can I use that              
to implement these?             
Well, two of them are easy.     
Okay, setOperand                
just sets the accumulator       
equal to that operand. Okay,    
cuz when you set a new          
operand to operate on,          
that replaces anything you      
have on your accumulator.       
It's what you're now            
accumulating. So that, that     
could be any, any easier than   
that. And then we get results,  
you're just gonna return        
the accumulator. Now,           
we've got a couple of           
errors here that we             

Chinese: 
I don't wanna have them to tell me what the accumulator's
我并不想知道 accumulator 变量的
initial value is.
初始化值是多少
Because I know what the initial accumulator internally
因为我认为 accumulator
its initial value is when I start up. It's not set.
在我使用之前是不应该有值的
So I'm gonna make this be an optional.
所以我把它的改为 optional（可选）类型
Do you see why I'm making that an optional?
知道为什么吗？
Because the accumulator when I create my brain. I haven't
因为我在创建 CalculatorBrain 的时候
accumulated any result. So I'm in this not set state.
accumulator 没有记录任何结果，所以它是缺省值的可选类型
So, it's a perfect opportunity to make this a double or
这是完美的解决方案，我可以在代码中把它设置为
an optional so I can express that in my code. All right? So
使用可选的浮点类型
if I have this internal accumulator right here,
如果 accumulator 是私有的
how can I use that to implement these?
这些怎么实现呢？
Well, two of them are easy. Okay, setOperand
这两个地方都很容易实现
just sets the accumulator equal to that operand. Okay,
setOperand 方法只要设置 accumulator 等于入参 operand
cuz when you set a new operand to operate on,
因为当你传入新的 operand 时
that replaces anything you have on your accumulator.
就会覆盖掉 accumulator 的旧值
It's what you're now accumulating. So that, that
这就是当前 accumulator 的值
could be any, any easier than that. And then we get results,
这很容易做到。当你获取 result
you're just gonna return the accumulator. Now,
你只要返回 accumulator 的值就可以了
we've got a couple of errors here that we
我们看到这里提示有几个错误

Chinese: 
have to deal with. What's this one right here?
需要我们处理。这一个是什么错误？
This looks perfectly fine. How could this be bad?
这看起来并没问题，为什么会出错呢？
Accumulator is an optional double, I'm setting it to
accumulator 是可选浮点类型
a double. It's gotta work, what's the problem?
赋给它一个浮点类型。这应该是可以的，会有什么问题？
Says I cannot assign to this property, because self is
这里提示 “I cannot assign to this property, because
immutable. Self meaning the calculator brain is immutable.
self is immutable”。说因为 self 不能被修改
And it's saying, do you wanna fix this by making this method
提示还说，如果你想修复这个错误
be mutating? You see he's trying to add this here.
需要在该方法前增加 mutating。它已经提示这么做了
Another difference between structs and
这是结构体和类的另一个区别
classes, if you have a method, okay? Or a property
如果你有一个方法，或者属性
that you're setting, that well, if you have a method and
当你在某个方法内
it changes the value of this thing,
修改它的值
you have to mark it mutating. You have to tell Swift, this
必须加上 mutating 关键字。你必须要告诉 Swift
method can change the value of this struct. Why is that?
这个方法可以修改结构体的值。为什么会这样呢？
It's because of that copy on write thing. Remember,
这和写时复制有关
I told you that structs are passed around by copying them.
记得之前说过结构体通过拷贝传递
And when you write to them, then it copies it. So
但当发生修改时，才会实际进行拷贝
it has to know you're writing it by calling setOperand.
所以它必须知道你在调用 setOperand 修改了值
So, you have to make setOperand be mutating func.
所以你必须为 setOperand 增加 mutating 关键字

English: 
have to deal with.              
What's this one right here?     
This looks perfectly fine.      
How could this be bad?          
Accumulator is an optional      
double, I'm setting it to       
a double. It's gotta work,      
what's the problem?             
Says I cannot assign to this    
property, because self is       
immutable. Self meaning the     
calculator brain is immutable.  
And it's saying, do you wanna   
fix this by making this method  
be mutating? You see he's       
trying to add this here.        
Another difference              
between structs and             
classes, if you have a method,  
okay? Or a property             
that you're setting, that       
well, if you have a method and  
it changes the value            
of this thing,                  
you have to mark it mutating.   
You have to tell Swift, this    
method can change the value     
of this struct. Why is that?    
It's because of that copy       
on write thing. Remember,       
I told you that structs are     
passed around by copying them.  
And when you write to them,     
then it copies it. So           
it has to know you're writing   
it by calling setOperand.       
So, you have to make            
setOperand be mutating func.    

English: 
So that's the difference        
between class and a struct.     
With that, what's this error    
down here? A different error.   
Anyone know what this           
error is? Louder? Okay,         
the problem here is we're       
trying to return a double,      
an accumulator is an optional.  
Okay, so it's saying here,      
hey unwrap this. Now, I do      
not wanna do this here. Okay,   
because it's perfectly valid    
for the accumulator to be not   
set. In fact, this starts       
out not set. And in fact,       
I can think already of another  
case where the accumulator is   
gonna be not set. What if I     
say, five times three equals,   
in my calculator?               
After I say five times,         
my accumulator is               
not set right now.              
Cuz I need the three equals     
until I can get the result. So  
my accumulator's often gonna    
be going back to not set.       
When we're in that weird five   
times three equals five times,  
the accumulator's not set       
right now. Three, okay,         

Chinese: 
So that's the difference between class and a struct.
这是类和结构体的区别
With that, what's this error down here? A different error.
下面还有一个不同的错误
Anyone know what this error is? Louder? Okay,
谁知道这是什么错误？
the problem here is we're trying to return a double,
在这里，我们尝试返回浮点类型
an accumulator is an optional. Okay, so it's saying here,
但 accumulator 是可选浮点类型，所以这里提示
hey unwrap this. Now, I do not wanna do this here. Okay,
没有解包，但我不想这么解包
because it's perfectly valid for the accumulator to be not
因为这样的话，accumulator 就不能缺省可选值
set. In fact, this starts out not set. And in fact,
但实际上，accumulator 一开始就是缺省值的
I can think already of another case where the accumulator is
我能想到另一个例子，accumulator
gonna be not set. What if I say, five times three equals,
会是缺省值。例如我要计算：“5 x 3 = ”
in my calculator? After I say five times,
当我输入“5 x”
my accumulator is not set right now.
的时候，accumulator 是缺省值的
Cuz I need the three equals until I can get the result. So
因为我输入“3 =”时才会计算结果
my accumulator's often gonna be going back to not set.
所以 accumulator 经常变成缺省值的可选类型
When we're in that weird five times three equals five times,
在“5 x 3 =”中，输入“5 x”时
the accumulator's not set right now. Three, okay,
accumulator 是缺省值的

Chinese: 
the accumulator's set again, equals, okay,
输入“3”时，accumulator 有值了，输入“=”号
here's the result. Okay,
就计算出结果了
so I can't have this be exclamation point.
所以这里不能有感叹号
Or this thing is gonna crash every time someone asks for
这样的话，每次输入“5 x”的时候获取结果
the result after they say five times. So we can't have that.
程序就会崩溃，肯定不能这样
So instead, I'm going to turn result into an optional. And
所以取而代之的，把返回结果改为可选类型
that makes sense too.
这是有道理的
Because if someone using this object in the middle of five
因为如果输入“5 x”时
times says, what's the results? It'll tell you it's
获取到的结果是什么？这里会返回缺省值
not set, because I'm in the middle of five times, right?
因为还没执行计算
And in your homework, you're even gonna make it clearer to
做作业的时候，你们尽量搞清楚
users of this why this might not be set, okay? So
为什么这里会是缺省值
you'll see that. All right, so
你会明白的
that's a good start to the implementation of this thing.
这是一个好的开始
But before we go into deeper in this implementation,
但在我们继续深入之前
let's go back to our controller and use this public
我们回到 controller，并使用
API that I just designed. Okay, I wanna use this.
我们刚刚设计的公开应用程序接口。OK，用这里
So I'm gonna go back to my controller. Now,
回到 controller
I wanna have my controller and my model on screen on the same
我希望 controller 和 model 并列在屏幕上
time. Just so I can see them side by side. And
我可以同时看到它们
the best way to do that is to bring out this assistant
最好的方式是点一下这个 assistant editor

English: 
the accumulator's set again,    
equals, okay,                   
here's the result. Okay,        
so I can't have this            
be exclamation point.           
Or this thing is gonna crash    
every time someone asks for     
the result after they say five  
times. So we can't have that.   
So instead, I'm going to turn   
result into an optional. And    
that makes sense too.           
Because if someone using this   
object in the middle of five    
times says, what's the          
results? It'll tell you it's    
not set, because I'm in the     
middle of five times, right?    
And in your homework, you're    
even gonna make it clearer to   
users of this why this          
might not be set, okay? So      
you'll see that. All right, so  
that's a good start to the      
implementation of this thing.   
But before we go into deeper    
in this implementation,         
let's go back to our            
controller and use this public  
API that I just designed.       
Okay, I wanna use this.         
So I'm gonna go back            
to my controller. Now,          
I wanna have my controller and  
my model on screen on the same  
time. Just so I can see         
them side by side. And          
the best way to do that is      
to bring out this assistant     

English: 
editor thing again, right?      
And you can go up to the top.   
And you can actually            
manually pick. Or               
I'm gonna teach you             
one little Alt thing.           
If you hold down Alt and click  
on some other file over here,   
you'll get that to              
appear on the right.            
So Alt-clicking means           
bring it up on the right.       
Okay, so here I have            
my model on the left.           
And here I have my              
controller on the right.        
So what I need to do now is     
fix this broken code that is    
doing model stuff inside the    
controller by using the public  
API of my model.                
Now, notice that                
touchDigit does nothing when    
it comes to calculating.        
All it does is get the digits   
from the keyboard and           
put them in the display. It's   
not doing any calculating, so   
we don't have to touch that.    
Same thing here with this       
display value computed var.     
All it's doing is converting    
the display from                
a double to a string and        
back. That's all it does.       
It has nothing to do            
with being a calculator.        
That's just the UI for          
this particular calculator. So  

Chinese: 
editor thing again, right? And you can go up to the top.
然后选择最上方这里
And you can actually manually pick. Or
然后手动选择
I'm gonna teach you one little Alt thing.
或者我教你使用 Alt 快捷键
If you hold down Alt and click on some other file over here,
如果你按住 Alt 键，并点击其他文件
you'll get that to appear on the right.
Assistant Editor 会在右边打开它
So Alt-clicking means bring it up on the right.
Alt + 点击操作意味着在右边打开它
Okay, so here I have my model on the left.
现在左边打开了 model
And here I have my controller on the right.
右边打开了 controller
So what I need to do now is fix this broken code that is
现在要做的就是修复代码
doing model stuff inside the controller by using the public
把一些 controller 的逻辑替换成
API of my model. Now, notice that
调用 model 的应用程序接口。这里需要注意
touchDigit does nothing when it comes to calculating.
touchDigit 方法和计算过程无关
All it does is get the digits from the keyboard and
它只是把键盘输入的值
put them in the display. It's not doing any calculating, so
显示到 display 上，它没有参与任何计算
we don't have to touch that.
所以我们不用管它
Same thing here with this display value computed var.
这个 displayValue 变量也一样
All it's doing is converting
它只是负责转换类型
the display from a double to a string and
把 display 的值类型在浮点类型和字符串类型相互转换
back. That's all it does.
它就只做这些
It has nothing to do with being a calculator.
也没有参与到计算过程
That's just the UI for this particular calculator. So
这些都是计算器的用户界面

English: 
the only thing we actually      
have to change is this method,  
performOperation. Now,          
we know that this part in here  
does not belong in here. And    
in fact, I'll throw it over     
here in my model. Even though   
it's not gonna work there.      
But we'll throw it over there   
for now just to get it out of   
the way, okay? So now we        
need to somehow use this        
API over here in this           
implementation. So,             
let's look at all three         
parts of what has to do,        
what we have to do in perform   
operation. First of all,        
if we're in the middle          
of typing a number,             
we need to set that number      
as an operand, okay?            
Because obviously, the user     
typing in a number and          
they perform an operation       
that number they were typing    
needs to be an operand.         
So, right off the bat here.     
I'm gonna say, if the user      
is in the middle of typing,     
then I'm going to set           
the operand. Now, how do I      
communicate to my brain here?   
Where is my brain? [LAUGH] I    
don't have a var for my brain.  
So let's create a var, and      
it will be private. Because     
the model is almost always      

Chinese: 
the only thing we actually have to change is this method,
实际上我们只需要改动这个方法
performOperation. Now, we know that this part in here
performOperation。现在，我们知道这部分代码
does not belong in here. And in fact, I'll throw it over
其实并不属于这里，我会把它丢到 model 里去
here in my model. Even though it's not gonna work there.
尽管丢过去之后不能编译
But we'll throw it over there for now just to get it out of
但为了规范，还是先把它丢过去再说
the way, okay? So now we need to somehow use this
然后在这方法内部
API over here in this implementation. So,
使用 model 的应用程序接口
let's look at all three parts of what has to do,
我们需要修改 performOperation 方法
what we have to do in perform operation. First of all,
的三个地方。第一个
if we're in the middle of typing a number,
如果输入某个数字的过程中开始计算
we need to set that number as an operand, okay?
必须要把数字存成操作数
Because obviously, the user typing in a number and
因为很明显，用户输入一个数字
they perform an operation that number they were typing
然后执行计算，那么输入的数字
needs to be an operand. So, right off the bat here.
肯定是操作数，所以在这里
I'm gonna say, if the user is in the middle of typing,
我会判断，如果用户在输入过程中计算
then I'm going to set the operand. Now, how do I
那么我会把输入的值设置为操作数
communicate to my brain here? Where is my brain? [LAUGH] I
那我怎么和 CalculatorBrain 沟通呢？
don't have a var for my brain. So let's create a var, and
我需要，但又没有 CalculatorBrain 的实例，那就创建一个
it will be private. Because the model is almost always
创建一个私有变量。因为在 controller 中，model 几乎

English: 
private to the controller. Cuz  
you don't want someone else     
reaching in and messing with    
this controller's model. So     
I'm gonna make it               
a private var.                  
I'm gonna call it brain. Its    
type is CalculatorBrain, okay?  
That's good. Now, as soon as    
I put this line of code in,     
look what I get. The old, you   
don't have any initializers.    
That's because this             
is not initialized.             
So I'm gonna initialize it by   
creating a CalculatorBrain.     
And you create                  
a CalculatorBrain in exactly    
the same way that you           
create as a class.              
With the name of the type and   
then the parentheses.           
Now we have no arguments        
in here. Because we have no     
uninitialized var. Since we     
made this be an optional,       
it's initialized to nil         
automatically for us for free,  
remember? So we have no         
uninitialized vars, so          
we just do open parentheses,    
closed parentheses. And         
of course, we don't             
need this type, right?          
Because it gets inferred. So    
if we ask what type is this?    
It says, that's a calculator    
brain. Has to be cuz that's     

Chinese: 
private to the controller. Cuz you don't want someone else
都是私有的，因为其他地方不会，你也不希望它们用到
reaching in and messing with this controller's model. So
controller 里面的 model 实例
I'm gonna make it a private var.
所以定义私有变量
I'm gonna call it brain. Its type is CalculatorBrain, okay?
变量名为 brain，类型为 CalculatorBrain
That's good. Now, as soon as I put this line of code in,
很好，我刚写完这行代码
look what I get. The old, you don't have any initializers.
就提示有错误了：你需要构造器
That's because this is not initialized.
因为这里没有初始化
So I'm gonna initialize it by creating a CalculatorBrain.
这里我通过构造一个 CalculatorBrain 来初始化
And you create a CalculatorBrain in exactly
和创建类实例一样
the same way that you create as a class.
结构体也需要这么创建
With the name of the type and then the parentheses.
名字，类型，然后是括号
Now we have no arguments in here. Because we have no
这里没有参数，因为我们
uninitialized var. Since we made this be an optional,
没有未初始化的变量，因为这里定义为可选的
it's initialized to nil automatically for us for free,
它默认会自动初始化为 nil
remember? So we have no uninitialized vars, so
所以我们没有未初始化的变量
we just do open parentheses, closed parentheses. And
我们只需要左括号，右括号
of course, we don't need this type, right?
当然，这个类型也可以去掉
Because it gets inferred. So if we ask what type is this?
因为代码会自动推断类型。如果问这是什么类型？
It says, that's a calculator brain. Has to be cuz that's
代码会自动推断出是 CalculatorBrain 类型

English: 
what you set it to. All right,  
so now that we have a model,    
our controller. This is the     
green arrow, talking from our   
controller to the model.        
We can say, brain set your      
operand to be whatever          
the display value is. And       
of course now we are not in     
the middle of typing, so I'll   
put that in here. So that's     
all we need to do to set        
the brain's operand. We only    
need to do if these are in      
the middle of typing            
something new,                  
and they hit                    
an operation button.            
We need to give them            
that operand, okay?             
Now, what about the stuff       
that was in here, okay?         
We get this mathematical        
symbol of the operation to do.  
Now I'm just gonna              
let the brain do it.            
So I'm just gonna say           
brain perform operation,        
the mathematical symbol.        
That's it.                      
I'm just handing that off to    
the model. Because that's,      
this is not my job as a         
controller to do calculation.   
Okay I'm a UI guy.              
Now of course after the         
operation is done I need to     
set my display value equal      
to the brain's result.          
But of course I can't do        
this because displayValue       

Chinese: 
what you set it to. All right, so now that we have a model,
现在在 controller 中已经实例化了 model
our controller. This is the green arrow, talking from our
这是绿色通道，连通
controller to the model. We can say, brain set your
controller 和 model。我们可以这样来使用
operand to be whatever the display value is. And
brain.setOperand(displayValue)
of course now we are not in the middle of typing, so I'll
当然，用户已经没有在输入某个数字了
put that in here. So that's all we need to do to set
把这一行移上来。这就是设置
the brain's operand. We only need to do if these are in
brain 操作数的步骤。只需要判断用户
the middle of typing something new,
是不是正在输入一个新值
and they hit an operation button.
然后点击的运算符按钮
We need to give them that operand, okay?
是我们就设置操作数为输入的值
Now, what about the stuff that was in here, okay?
这一块怎么处理呢？
We get this mathematical symbol of the operation to do.
我们获取到了计算运算符号
Now I'm just gonna let the brain do it.
我需要通知 brain
So I'm just gonna say brain perform operation,
我只需要输入
the mathematical symbol. That's it.
brain.performOperation(mathematicalSymbol)
I'm just handing that off to the model. Because that's,
我把这些都交给 model
this is not my job as a controller to do calculation.
因为计算不是 controller 的工作
Okay I'm a UI guy.
controller 属于用户界面
Now of course after the operation is done I need to
在操作过后，我需要设置
set my display value equal to the brain's result.
displayValue 等于 brain.result
But of course I can't do this because displayValue
但我不能这么写，因为 displayValue

Chinese: 
is a double. And the result, might be
类型是浮点，但 brain.result
not set cuz it's an optional. So I'm gonna say here,
是可选类型，可能缺省值。所以这里需要写
if I can let the result equal the brain to results.
如果我可以让 result 等于 brain.result
In other words, if the brain's result is determined. Then I
换句话说，如果 brain.result 是有值的
will let the displayValue equal the result. That's it.
那么 displayValue 就等于这个值
Okay, so that little piece of code to input has completely
OK，这一小段代码就可以把
taken all calculation out of the controller.
把计算模块分出去
And put you into this other camp the model.
全权交给 model 处理
And now we can spend the rest of this lecture making this
剩下的时间我们都会构建这个
really powerful model.
强大的 model
And nothing is gonna change over here.
这边不会再有任何修改
I'm literally never gonna edit this code ever again. In fact,
我基本上不会再修改这里的代码
I'm just gonna get it off the screen. And
事实上我会隐藏它
we're gonna spend all of our time over here in the model.
我们把时间都花在 model 上
So, let's start by making kind of a really dirt simple
我们先简单处理下
implementation of performOperation here. Which
实现 performOperation
is try to get this code that was already there to work.
让这些代码通过编译就行
And mostly, that's just a matter of changing the names.
首先，需要修改名字
Because this argument is symbol,
因为参数名是 symbol
not mathematical symbol. So, we'll do that.
不是 mathematicalSymbol

English: 
is a double.                    
And the result, might be        
not set cuz it's an optional.   
So I'm gonna say here,          
if I can let the result         
equal the brain to results.     
In other words, if the brain's  
result is determined. Then I    
will let the displayValue       
equal the result. That's it.    
Okay, so that little piece of   
code to input has completely    
taken all calculation           
out of the controller.          
And put you into this           
other camp the model.           
And now we can spend the rest   
of this lecture making this     
really powerful model.          
And nothing is gonna            
change over here.               
I'm literally never gonna edit  
this code ever again. In fact,  
I'm just gonna get it           
off the screen. And             
we're gonna spend all of our    
time over here in the model.    
So, let's start by making       
kind of a really dirt simple    
implementation of               
performOperation here. Which    
is try to get this code that    
was already there to work.      
And mostly, that's just a       
matter of changing the names.   
Because this                    
argument is symbol,             
not mathematical symbol.        
So, we'll do that.              

Chinese: 
And instead of setting a display value cuz we're not in
然后替换 displayValue
a UI any more.
因为已经不再处理用户界面了
Now we're just setting the accumulator to that double pi.
现在要设置 accumulator 等于 pi
Right, and the same thing here we're setting the accumulator
同样，这里也需要设置 accumulator
to be the square root of the accumulator. Okay,
等于根号 accumulator
now this is a problem right here.
又报错了
This line, why? Accumulator is an optional.
这里是为什么出错呢？accumulator 是可选类型
You can't take the square root of an optional. So I could say
你不能对一个可选类型开根号
for example, if let operand equal the accumulator.
我会写，如果让 operand 等于 accumulator
So if my accumulator is set, then I can tap the accumulator
也就是如果 accumulator 有值，我再让 accumulator
be the square root of the operand, okay? Now,
等于操作数的平方根
we have another warning right here on both of these lines.
这两行还有另外的错误
Why do you think, does anyone know why this is? We seen it
谁知道为什么吗？
before, five minutes ago. This
我们5分钟前遇到过的
modifies this CalculatorBrain. So this method,
这里修改了 CalculatorBrain 的私有变量
performOperation, also needs mutating in front of it,
所以 performOperation 方法需要增加 mutating 关键字
okay? So I'll fix that, add mutating.
加上就好了，不报错了

English: 
And instead of setting a        
display value cuz we're not in  
a UI any more.                  
Now we're just setting the      
accumulator to that double pi.  
Right, and the same thing here  
we're setting the accumulator   
to be the square root of        
the accumulator. Okay,          
now this is a problem           
right here.                     
This line, why?                 
Accumulator is an optional.     
You can't take the square root  
of an optional. So I could say  
for example, if let operand     
equal the accumulator.          
So if my accumulator is set,    
then I can tap the accumulator  
be the square root of           
the operand, okay? Now,         
we have another warning right   
here on both of these lines.    
Why do you think, does anyone   
know why this is? We seen it    
before, five minutes ago. This  
modifies this CalculatorBrain.  
So this method,                 
perfomOperation, also needs     
mutating in front of it,        
okay? So I'll fix that,         
add mutating.                   

English: 
Adding this mutating takes      
a little bit getting used to.   
But it's great because its      
compiler notices it. And it's   
gonna always be reminding you   
to do that. So believe it or    
not we now have an MVC version  
of this calculator and if we    
run it should just work.        
All right,                      
here we go. Let's see.          
7, 8, that's still working.     
Okay, that was in               
the controller. Pi, woah,       
that's working.                 
It's going off to the model.    
And this is actually            
executing. And it's causing     
the accumulator to get set      
to that double pi. And          
then flicking at the result     
and putting it in display. How  
about 81 square root, square    
root? All right, excellent,     
okay. So now we're starting in  
a place where exactly where we  
were before. But we split off   
all of our calculating code     
into this little class          
right here. So this is          
a great opportunity now to      
enhance this to the max.        

Chinese: 
Adding this mutating takes a little bit getting used to.
你有时候可能会忘记添加 mutating 关键字
But it's great because its compiler notices it. And it's
但没关系，因为编译器会提醒你
gonna always be reminding you to do that. So believe it or
它一定会提醒你添加
not we now have an MVC version of this calculator and if we
OK，不管你信不信，MVC 版的计算器已经写完了
run it should just work. All right,
如果你运行它，它肯定会工作的
here we go. Let's see. 7, 8, that's still working.
我们来试试，7，8
Okay, that was in the controller. Pi, woah,
controller 部分正常。试试 pi
that's working. It's going off to the model.
正常工作着，值传递给 model 了
And this is actually executing. And it's causing
实际执行的是这一行
the accumulator to get set to that double pi. And
把 accumulator 设置成 pi 的值
then flicking at the result and putting it in display. How
然后把结果显示到 display 上
about 81 square root, square root? All right, excellent,
那么81开根，再开根呢？好的，没错
okay. So now we're starting in a place where exactly where we
我们代码恢复到了之前的可用状态
were before. But we split off all of our calculating code
并且我们把负责计算的代码分离出到
into this little class right here. So this is
这里的一小块
a great opportunity now to enhance this to the max.
这是我们优化这部分代码的好机会

Chinese: 
So we are gonna use all kinds of cool, Swift stuff that you
我们将会使用一些你从没见过的
probably did not see in other languages.
Swift 语言仅有的特性
To make this a much more extensible calculator.
让这个计算器更容易扩展
Cuz right now, man, if I wanna add more operations.
因为现在，如果我们要增加运算符
I just get this huge switch statement case, this case,
我需要增加 switch 代码块，添加 case 声明
that case. I'm gonna have to do if let operand equals
而且每次我都必须要添加判断
accumulator every single time.
如果常量 operand 等于 accumulator 之类的
For the things that are unary operations like square root.
而且这些只是想平方根之类的一元计算
Imagine when I have the binary case like five times three
想象下，如果我有二元操作，像“5 x 3 =”
equals. I'm gonna have to do the figuring out how to deal
我需要考虑怎么处理
with the times and the equals for every single case.
单个计算中出现的乘称号和等于号
Forget it. I can't do that. I need to build an engine here.
算了，想都别想。我需要的是构造一个计算引擎
That can deal with constants.
既可以处理常量
That can deal with these unary operations like square root.
又可以处理像开根号之类的一元计算
That can deal with binary operations like multiply and
还可以处理像加减之类的
plus and things like that. Okay? So that's exactly what
二元计算。这是
we're going to do. We're going to enhance this model. Now,
接下来要做的。我们继续优化我们的 model
as we do all this enhancement, we're not going to change it
所有的优化，都不会影响外部
externally at all. And so the controller will not change.
调用，controller 不需要任何修改
That's what's really cool about this. We can do our
这是非常酷的
model development independent of our UI.
在把用户界面的功能基本完成之后
Once we have the UI, that kind of does the basics, all right.
就可以脱离 UI 只修改 model 的内部实现了

English: 
So we are gonna use all kinds   
of cool, Swift stuff that you   
probably did not see            
in other languages.             
To make this a much more        
extensible calculator.          
Cuz right now, man, if I        
wanna add more operations.      
I just get this huge switch     
statement case, this case,      
that case. I'm gonna have       
to do if let operand equals     
accumulator every single time.  
For the things that are unary   
operations like square root.    
Imagine when I have the binary  
case like five times three      
equals. I'm gonna have to do    
the figuring out how to deal    
with the times and the equals   
for every single case.          
Forget it. I can't do that. I   
need to build an engine here.   
That can deal with constants.   
That can deal with these unary  
operations like square root.    
That can deal with binary       
operations like multiply and    
plus and things like that.      
Okay? So that's exactly what    
we're going to do. We're going  
to enhance this model. Now,     
as we do all this enhancement,  
we're not going to change it    
externally at all. And so the   
controller will not change.     
That's what's really cool       
about this. We can do our       
model development               
independent of our UI.          
Once we have the UI, that kind  
of does the basics, all right.  

English: 
So what are we going to do      
here? Let's focus first.        
Let's get rid of this code,     
cuz we know that's a mess.      
We're not going to do that.     
Let's focus on constants.       
Wouldn't it be kind of cool if  
I could like, build a table.    
Okay, I'll do square brackets   
to hold my table. And           
in this table, I had, like pi   
and double dot pi. And then,    
maybe I had e's does everyone   
know what the constant e is.    
Mathematic 2.71 one something.  
We have a nice symbol for       
that and not quite as nice as   
Double.pi. But it's called      
M under bar E. So, and I put    
all my constants in a table.    
And then here in                
performOperation,               
I'll just look up the symbol    
in that table and               
get the value. Wouldn't that    
be a lot more extensible for    
constants? Right, I could add   
all the constants I want.       
I just, one line of code each.  
That would be a lot better      
than putting extra case this    
blah blah blah. Okay, so        
how can we do that?             
We need to create a table.      
So how do we create             
a table in Swift?               
We use the struct called        
dictionary, okay? So            
dictionary is how you create    
a hash table of things. And so  

Chinese: 
So what are we going to do here? Let's focus first.
接下来我们要做什么呢？我们看这里
Let's get rid of this code, cuz we know that's a mess.
我们先去掉这些代码，因为这写得不好
We're not going to do that. Let's focus on constants.
我们换种方式。先看看常数
Wouldn't it be kind of cool if I could like, build a table.
有没有其他更好的方式来实现呢？比如用某种参照表？
Okay, I'll do square brackets to hold my table. And
OK，我用中括号定义表格
in this table, I had, like pi and double dot pi. And then,
在表格里，我定义 "π" : Double.pi
maybe I had e's does everyone know what the constant e is.
然后，应该还有常数 e
Mathematic 2.71 one something.
一个无理数，约等于 2.71
We have a nice symbol for
Swift 有专门的符号来表示它
that and not quite as nice as Double.pi. But it's called
但不像 Double.pi 那么优雅
M under bar E. So, and I put all my constants in a table.
它叫 M_E。好了，假设我把需要的常量都放在表格里了
And then here in performOperation,
然后在 performOperation 方法里
I'll just look up the symbol in that table and
我只需要在表格中查找符号
get the value. Wouldn't that be a lot more extensible for
找到对应的值。这是不是更具有可扩展性？
constants? Right, I could add all the constants I want.
我可以加入任何我想要的常量
I just, one line of code each. That would be a lot better
一行一个，这肯定会比
than putting extra case this blah blah blah. Okay, so
很多很多个 switch 的 case 要好
how can we do that? We need to create a table.
OK，那我们怎样实现呢？首先要创建一个表格
So how do we create a table in Swift?
那 Swift 怎么创建一个表格呢？
We use the struct called dictionary, okay? So
Swift 有个结构体，叫 Dictionary（字典）
dictionary is how you create a hash table of things. And so
字典是你创建哈希表的方法

Chinese: 
I'm gonna create a private var.
我定义一个私有变量
I'm gonna call it, I could call it constants, but
名字可以叫 constants
I'm gonna call it operations cuz I'm basically, eventually
但我叫它 operations
going to enhance it to work for all of our operations.
因为它最终会适用于我们所有的运算
And it's gonna be of type Dictionary. Now Dictionary,
类型是 Dictionary
you're gonna see a new feature in Swift right here. It, this,
你所见到的又一个 Swift 语言的特性
you have this feature in Java, as well. It is a generic type.
你可能在 Java 中也见过，泛型
So a dictionary, it can be a dictionary that goes from
字典，可以由几乎任何
almost any kind of key to almost any kind of value.
键值对组成
Okay, the key has to implement a certain protocol.
但键必须遵循某个协议
It basically has to be hashable. Okay,
它基本上必须是 Hashable，具有哈希性
so as long as it's hashable, then it can be a key and
所以只要是具有哈希性，就可以成为键
then the value can be any type. So you specify that,
值可以是任何类型。所以你需要指定类型
same as in Java, the key type.
和 Java 一样，指定键的类型
So I'm gonna have my key be a string like pi or e.
字典键的类型用 String，比如 π 或 e
And then the value is going to be a double,
值的类型为 Double
like Double.pi here, or M_E, okay? And believe it or
比如 Double.pi 和 M_E
not, I can actually say equals this syntax and
其实我还可以直接写等于下面这个
it will create one for me with that step in there, okay? So
就能初始化我的字典了

English: 
I'm gonna create                
a private var.                  
I'm gonna call it,              
I could call it Constants, but  
I'm gonna call it Operations    
cuz I'm basically, eventually   
going to enhance it to work     
for all of our operations.      
And it's gonna be of type       
Dictionary. Now Dictionary,     
you're gonna see a new feature  
in Swift right here. It, this,  
you have this feature in Java,  
as well. It is a generic type.  
So a dictionary, it can be      
a dictionary that goes from     
almost any kind of key to       
almost any kind of value.       
Okay, the key has to            
implement a certain protocol.   
It basically has to             
be hashable. Okay,              
so as long as it's hashable,    
then it can be a key and        
then the value can be any       
type. So you specify that,      
same as in Java, the key type.  
So I'm gonna have my key        
be a string like pi or e.       
And then the value is           
going to be a double,           
like Double.pi here, or _E,     
okay? And believe it or         
not, I can actually say         
equals this syntax and          
it will create one for me with  
that step in there, okay? So    

Chinese: 
open square bracket, key colon value comma key colon value,
所以中括号里面，键，冒号，值，逗号
that's how you can put a dictionary.
如此循环，构成字典
Now of course, you can add things to a dictionary and
当然了，你可以向字典
remove things, and get things out of dictionary.
添加、查询或移除内容
I'll show you that in a second. But
这我们马上会讲到
this is a nice way to do this. So
但这种方法更直观
let's do that. Okay, so we have this nice dictionary.
我们就这样创建了一个字典
So now we could use this dictionary of operations and
我们现在结合字典 operation
performOperation. I'm gonna say,
和方法 performOperation
if I can let the constant that I want equal the operation
if let constant = operation[symbol]
that matches that symbol then, now why am I doing if let here
如果能在 operation 中找到 symbol 对应的运算
for operations sub-symbol? This operation sub-symbol,
但为什么要用 if let 呢？这种下标语法
that's how you look up a symbol in a dictionary, right?
意思是在字典中查找 symbol
Operation to the dictionary, click on it, right?
operation 是个字典，对吧
To dictionary, strings and doubles. So you look it up.
Dictionary
When you look it up, it returns an optional of
你查询返回的结果，是包含值的可选类型
the value. Why, anyone think why it would do that?
有人知道为什么是可选的吗？
>> It might not be there.
>> 因为键可能不存在
>> Exactly, it might not be in
>> 没错，正是因为 symbol 可能

English: 
open square bracket, key colon  
value comma key colon value,    
that's how you can              
put a dictionary.               
Now of course, you can add      
things to a dictionary and      
remove things, and              
get things out of dictionary.   
I'll show you that              
in a second. But                
this is a nice way to do this.  
So                              
let's do that. Okay, so         
we have this nice dictionary.   
So now we could use this        
dictionary of operations and    
performOperation.               
I'm gonna say,                  
if I can let the constant that  
I want equal the operation      
that matches that symbol then,  
now why am I doing if let here  
for operations sub-symbol?      
This operation sub-symbol,      
that's how you look up a        
symbol in a dictionary, right?  
Operation to the dictionary,    
click on it, right?             
To dictionary, strings and      
doubles. So you look it up.     
When you look it up,            
it returns an optional of       
the value. Why, anyone          
think why it would do that?     
>> It might not be there.       
>> Exactly, it might not be in  

English: 
the table. Okay, what if        
I say operations sub X,         
that's gonna return not set,    
because there's no              
X in this table. Only pi and e  
are in there, okay? So that's   
why I have to do if let there,  
and if the constant is there,   
now I can set my accumulator    
equal to that constant,         
okay? Because this constant     
is gonna be a Double, because   
this is a Dictionary that has   
Doubles as its values, okay?    
That's cool. Let's go ahead.    
Let's run it.                   
That's all we need to do. So    
now we've built, for constants  
only, a much more extensible    
internal architecture here,     
to our calculator brain.        
So of course, square root's     
not gonna work, okay,           
but pi works, and if I add an   
e button, it would do e. Okay,  
everybody cool with             
what I did there? But           
of course, that's kind of       
useless just for constants.     
We wanna be something like      
this, watch this. Quote,        
do my Emoji & Symbols here.     
There's our square root,        
square root colon,              

Chinese: 
the table. Okay, what if I say operations sub X,
不在字典里。如果我说 operation["x"]
that's gonna return not set, because there's no
那就会返回 nil，因为 x 不在里面
X in this table. Only pi and e are in there, okay? So that's
在字典里的只有 π 和 e
why I have to do if let there, and if the constant is there,
这就是我为什么要用 if let。如果存在这个常数
now I can set my accumulator equal to that constant,
就更新 accumulator = constant
okay? Because this constant is gonna be a Double, because
因为 constant 是 Double
this is a Dictionary that has Doubles as its values, okay?
因为字典的值是 Double
That's cool. Let's go ahead.
好，这就是我们要做的
Let's run it. That's all we need to do. So
现在运行试试看
now we've built, for constants only, a much more extensible
虽然目前只有常数，但我们现在写好了
internal architecture here, to our calculator brain.
CalculatorBrain 内部可扩展的结构
So of course, square root's not gonna work, okay,
当然还不能用平方根
but pi works, and if I add an e button, it would do e. Okay,
但可以用 π。如果我加个 e，那个也能用
everybody cool with what I did there? But
大家都理解我干了什么吗？
of course, that's kind of useless just for constants.
当然，只能处理常数就太没用了
We wanna be something like this, watch this. Quote,
我们想要把这些加上
do my Emoji & Symbols here.
先把我的 Emoji & Symbols 调出来
There's our square root, square root colon,
找到平方根，"√" :

English: 
what do we wanna put over       
here? How about square root?    
Okay, and maybe a cosine.       
Put cosine there.               
And wouldn't that be cool       
if we could do that, okay?      
Because now we'd really         
have an extensible table,       
it can do constant and also     
can do these unary functions.   
But we got a problem here,      
because square root is most     
definitely not a Double,        
right? Square root              
is like a function, so that's   
no good. So we're gonna,        
if we wanna have a dictionary   
that has mixed things in it,    
we need to create a type        
here that represents those      
mixed things. So that's what    
we're gonna do, we're gonna     
create a new type, okay? This   
is gonna have a data type that  
you're gonna be somewhat used   
to, to other languages, but     
you're gonna see it much        
more powerful in Swift.         
I'm gonna make it a private     
type that's embedded inside my  
CalculatorBrain, so you can     
have types within types and     
it's just a scoping issue,      
that's just a naming issue,     
okay? The name of this is       
gonna be CalculatorBrain,       
the dot, what I call it here.   
And it's not gonna be a struct  

Chinese: 
what do we wanna put over here? How about square root?
这边放什么呢？放个 sqrt？
Okay, and maybe a cosine. Put cosine there.
那余弦呢？ "cos" : cos
And wouldn't that be cool if we could do that, okay?
如果能这样做该多好啊
Because now we'd really have an extensible table,
因为这样我们这个多功能的字典
it can do constant and also can do these unary functions.
既能放常数，又能放一元运算符
But we got a problem here, because square root is most
但有个问题，因为 sqrt
definitely not a Double, right? Square root
肯定不是 Double
is like a function, so that's no good. So we're gonna,
因为 sqrt 是个函数，这就不行了
if we wanna have a dictionary that has mixed things in it,
如果我们向要往字典中放不同类型的值
we need to create a type here that represents those
那我们就需要一个新的类型代表它们
mixed things. So that's what we're gonna do, we're gonna
所以我们要做的就是
create a new type, okay? This is gonna have a data type that
创建一个新的类型
you're gonna be somewhat used to, to other languages, but
你们可能接触过这个数据类型
you're gonna see it much more powerful in Swift.
但在 Swift 中它更为强大
I'm gonna make it a private type that's embedded inside my
我会把这个类型定义在
CalculatorBrain, so you can have types within types and
CalculatorBrain 的内部
it's just a scoping issue, that's just a naming issue,
所以可以存在嵌套类型
okay? The name of this is gonna be CalculatorBrain,
只不过会因为作用域导致名字是
the dot, what I call it here. And it's not gonna be a struct
CalculatorBrain.我给它的名字

English: 
or a class, it's gonna be       
an enum. Does everyone          
know what an enum is in other   
classes? It's basically a data  
structure that has              
discrete values. Right,         
it can only be one, like case   
this, case that, whatever.      
It can only be one of           
a discrete value and            
the same thing here in Swift.   
I'm gonna call it Operation,    
and it's gonna have             
case constant and               
case unaryOperation. So those   
are the two kinds of things.    
And then I'm gonna make this    
Dictionary return an Operation  
instead of a Double. Okay, so   
that means I have change all    
of these, to say                
Operation.constant, because     
this is a constant. We'll just  
comment that out for a second.  
And then this is also           
an Operation.constant.          
This one will be                
an Operation.unaryOperation.    
I can just call that            
Operation.unary.                
We'll say unary operation.      
Operation.unaryOperation,       
okay?                           
Cool! Okay, we can't do this    
anymore, of course, cuz now     

Chinese: 
or a class, it's gonna be an enum. Does everyone
它的类型不会是类或结构体，而是 enum，枚举
know what an enum is in other classes? It's basically a data
有谁从其他课程听说过枚举的吗？
structure that has discrete values. Right,
它每个情况都是独一无二的
it can only be one, like case this, case that, whatever.
分别用 case 定义
It can only be one of a discrete value and
变量只能为其中的某种情况
the same thing here in Swift. I'm gonna call it Operation,
Swift 也是一样的。我把它叫做 Operation
and it's gonna have case constant and
它的情况有 case constant（常数）和
case unaryOperation. So those are the two kinds of things.
case unaryOperation（一元运算）两种
And then I'm gonna make this Dictionary return an Operation
接着我把字典的值改为 Operation
instead of a Double. Okay, so that means I have change all
而不是 Double。这意味着我要
of these, to say Operation.constant, because
把这些放进 Operation.constant
this is a constant. We'll just comment that out for a second.
因为它们是常数。暂时先注释这部分
And then this is also an Operation.constant.
e 也是个 Operation.constant
This one will be an Operation.unaryOperation.
平方根是 Operation.unaryOperation
I can just call that Operation.unary.
虽然可以就叫 Operation.unary
We'll say unary operation.
但还是就用 unaryOperation 吧
Operation.unaryOperation, okay?
余弦也是 Operation.unaryOperation
Cool! Okay, we can't do this anymore, of course, cuz now
好！等等，下面就不能这么写了

Chinese: 
it's not a constant that we're pulling out of there.
因为我们获取的已经不是常量了
It's actually an operation, okay? And obviously,
我们获取的是 Operation
we can't do that because this constant here,
当然我们也不能赋值给 accumulator
is now an operation not a double. So we can't say that
因为 Operation 不是 Double
equals that, okay? So this is good. This is getting better.
现在开始慢慢好转了
We've got our table to be able to have both things. But
字典里能同时装两种类型
in doing this, I've lost the fundamental meaning
但我把最基本的功能都丢完了
of all of these things. I commented it out. So
都变成了注释
now this table is kind of useless, right?
这字典就显得很无用了
It knows that pi is a constant.
虽然知道圆周率是常数
It knows that square root is a unary operation.
知道平方根是一元运算
But it's so what? Because we can't do any of them. And
但又怎样？我们什么也干不了
this is where, something you've heard of before,
这下子你们之前听到的
associated values comes in. Remember optional has
关联值就能派上用场了
this thing where when it's in the set stage it has this
还记得可选类型在不为空的时候
associated value that's associated with the set state,
会关联一个关联值吗？
but is not associated with the not set state? Okay, optional
只在有值的时候关联，为空的时候就没有？
is an enum. It's an enum with two cases. The not set case,
可选类型其实是个有两个 case 的枚举

English: 
it's not a constant that        
we're pulling out of there.     
It's actually an operation,     
okay? And obviously,            
we can't do that because        
this constant here,             
is now an operation not         
a double. So we can't say that  
equals that, okay? So this is   
good. This is getting better.   
We've got our table to be       
able to have both things. But   
in doing this, I've lost        
the fundamental meaning         
of all of these things.         
I commented it out. So          
now this table is kind          
of useless, right?              
It knows that pi                
is a constant.                  
It knows that square root       
is a unary operation.           
But it's so what? Because we    
can't do any of them. And       
this is where, something        
you've heard of before,         
associated values comes in.     
Remember optional has           
this thing where when it's      
in the set stage it has this    
associated value that's         
associated with the set state,  
but is not associated with the  
not set state? Okay, optional   
is an enum. It's an enum with   
two cases. The not set case,    

Chinese: 
which is called none and the set case, which is called some.
为空的时候是 .none，有值是 .some
And in the some case, it has a little associated value with
在为 .some 的时候，就有一个关联值
it. And we can do the exact same thing, okay? In our enum,
我们也能这么做
when the case is a constant, we can have an associated
在我们枚举为 constant 时，可以有个关联的 Double
Double. And that's, we just put it right there and
就把 (Double) 接在后面
we can actually could have multiple associated values.
如果想的话我们还可以有多个 Double
We only need one for constants. But we can have
这里我们只需要一个就够了
this associated value. Okay, so associated values
所以 constant 可以有 Double 作为关联值
are something not specific to optionals. It's for
所以不只是可选类型有关联值
all enums in Swift. So this is super powerful because now
所有的枚举类型都有。这样我们就能
when I add a constant into this table, for example,
在把常数加到字典里时
I can just associate Double.pi with it.
把它和 Double.pi 关联起来
Same thing with this constant, I'll just associate the value
这个常量同理，关联 M_E
of e with it. Okay, now we'll get to these ones in a second.
下面两个再稍等一下
A little more complicated there. All right, so
稍微有些复杂
now I've got a table with got constants in there and
现在我的字典已经有常量了
I actually know the values.
并且我也知道具体是多少

English: 
which is called none and the    
set case, which is called sum.  
And in the sum case, it has     
a little associated value with  
it. And we can do the exact     
same thing, okay? In our enum,  
when the case is a constant,    
we can have an associated       
Double. And that's,             
we just put it right there and  
we can actually could have      
multiple associated values.     
We only need one for            
constants. But we can have      
this associated value.          
Okay, so associated values      
are something not specific      
to optionals. It's for          
all enums in Swift. So this     
is super powerful because now   
when I add a constant into      
this table, for example,        
I can just associate            
Double.pi with it.              
Same thing with this constant,  
I'll just associate the value   
of e with it. Okay, now we'll   
get to these ones in a second.  
A little more complicated       
there. All right, so            
now I've got a table with       
got constants in there and      
I actually know the values.     

Chinese: 
So down here, when I get the operation out of here, right,
所以下面从字典 operation 提取的时候
this is a type Operation,
我要如何从这个枚举 Operation 中
it's one of these enums. How do I look at each of these,
确定究竟是哪一种情况
and like get this associated value? Well, how would you
然后获得它的关联值呢？
look at the values of an enum in another language?
你在其他语言中是如何判断枚举类型的值的？
You would probably switch on them. So
你一般会用 switch 语句
I'm gonna switch on this operation and
所以我用 switch 判断 operation
I'm gonna do a case for when it's a constant. And
用一个 case 判断是否是常数
I'm gonna do a case, we'll do colon and break.
case .constant(Double): break
And I'm gonna do a case for when it's a unaryOperation,
然后看是否是一元运算
and break on that case, okay? And I don't even have to
case .unaryOperation: break
say default here, because these are the only two values
我这里 default 都不用，因为这两种
that an operation can be, cuz it's an enum,
就是 operation 所有可能的情况了
it only has one of these two values. Now here, you can see,
作为枚举只有可能是这两种中的一个
it already put this in parentheses right here.
你可能注意到这里已经把 Double 放到括号里了
Okay, it wants to help you get that associated value out.
它这是在帮你把关联值提取出来
Okay, awesome, how do we do that?
好啊，那具体怎么做呢？我们用
We say let associatedConstantValue or
let associatedConstantValue
whatever we wanna call this variable. And
let 关联值，或是更好的名字
that means inside here, associatedConstantValue
结果就是 associatedConstantValue

English: 
So down here, when I get the    
operation out of here, right,   
this is a type Operation,       
it's one of these enums. How    
do I look at each of these,     
and like get this associated    
value? Well, how would you      
look at the values of           
an enum in another language?    
You would probably              
switch on them. So              
I'm gonna switch on             
this operation and              
I'm gonna do a case for         
when it's a constant. And       
I'm gonna do a case,            
we'll do colon and break.       
And I'm gonna do a case for     
when it's a unaryOperation,     
and break on that case, okay?   
And I don't even have to        
say default here, because       
these are the only two values   
that an operation can be,       
cuz it's an enum,               
it only has one of these two    
values. Now here, you can see,  
it already put this in          
parentheses right here.         
Okay, it wants to help you get  
that associated value out.      
Okay, awesome,                  
how do we do that?              
We say let                      
associatedConstantValue or      
whatever we wanna call          
this variable. And              
that means inside here,         
associatedConstantValue         

English: 
is gonna be that associated     
value. Now we would never call  
it associatedConstantValue.     
We'll rename it in a second.    
But now what are we             
gonna do with it? Well,         
in the constant case we're      
just gonna set our accumulator  
to that associated value.       
Now, why we wouldn't call this  
associatedConstantValue? Well,  
first of all, anyone reading    
this code knows that this       
is the associated value,        
so you don't need to say        
associated. And we know i's     
a constant because we're        
in the constant case, so        
i's really a waste              
to say that.                    
So, we would just say value     
here. Cuz that's what it is,    
i's the constant value that's   
associated with it, okay?       
We don't need break.            
Everybody got that?             
By the way, switches are        
slightly different in Swift in  
that they don't fall into each  
other. When you have constant,  
it does this, and it's done.    
It doesn't go down, fall down   
to the next case, okay? So you  
don't need break at the end     
of every single one, which      
is really nice. All right?      
So this is great. So            
should this work? I think so.   

Chinese: 
is gonna be that associated value. Now we would never call
会被赋值为关联的值。当然我们要重命名
it associatedConstantValue. We'll rename it in a second.
不可能叫 associatedConstantValue
But now what are we gonna do with it? Well,
现在暂时就先这样
in the constant case we're just gonna set our accumulator
在是常数的情况下，我们就更新 accumulator
to that associated value. Now, why we wouldn't call this
accumulator = associatedConstantValue
associatedConstantValue? Well, first of all, anyone reading
为什么不叫 associatedConstantValue 呢？
this code knows that this is the associated value,
因为每个读这段代码的人都知道那是关联值
so you don't need to say associated. And we know i's
所以可以省略掉代表关联的 associated
a constant because we're in the constant case, so
因为我们已经知道是常数了
i's really a waste to say that.
所以可以省略代表常数的 constant
So, we would just say value here. Cuz that's what it is,
所以叫它 value 就可以了
i's the constant value that's associated with it, okay?
它就是作为常数的关联值
We don't need break. Everybody got that?
注意这里不需要 break，大家记住了吗？
By the way, switches are slightly different in Swift in
Swift 中 switch 的不同点在于
that they don't fall into each other. When you have constant,
并不会自动进入下一个 case
it does this, and it's done. It doesn't go down, fall down
常数情况的代码执行完就直接跳出
to the next case, okay? So you don't need break at the end
并不会去下一个 case，所以不需要 break
of every single one, which is really nice. All right?
不用每个情况都加，是件很棒的事情
So this is great. So should this work? I think so.
很好，那现在能用了吗？

English: 
Let's try it. All right.        
So. Pi, okay, square root we    
haven't done anything with,     
but pi should work.             
Let's try. Bingo, okay.         
So you see how pi               
is working here?                
We're saying to look up pi      
in this table. It finds that    
it's a constant operation with  
this as the associated value.   
We switch on that operation.    
Find out that it's a constant.  
We let value equal              
the associated value,           
and then we just set            
that to the accumulator.        
And now that's our result, the  
next time they ask for result   
that's what we got. Okay,       
now let's do unary operation.   
Okay, this one's                
a little tougher, okay?         
Cuz really what I wanna         
do is this. Right?              
The associated value wants      
to be those functions.          
Can I do that in Swift?         
Of course!                      
We wouldn't be here if          
we couldn't do that.            
How do we make an associated    
value be a function?            
Well the cool thing about       
Swift is that functions         

Chinese: 
Let's try it. All right.
我们运行试试看
So. Pi, okay, square root we haven't done anything with,
好，圆周率，平方根还没有做好
but pi should work. Let's try. Bingo, okay.
但圆周率是没问题的。让我们试试
So you see how pi is working here?
好诶！想明白为什么圆周率可以用了吗？
We're saying to look up pi in this table. It finds that
我们在字典里找到 π
it's a constant operation with this as the associated value.
值是 .constant，关联值是 Double.pi
We switch on that operation. Find out that it's a constant.
然后我们用 switch 判断，得知是个常数
We let value equal the associated value,
然后把 value 赋值为关联的值
and then we just set that to the accumulator.
最后赋值给 accumulator
And now that's our result, the next time they ask for result
那就是我们计算的结果，现在 result
that's what we got. Okay, now let's do unary operation.
的值就是 Double.pi。接着实现一元运算
Okay, this one's a little tougher, okay?
这个稍微困难一些
Cuz really what I wanna do is this. Right?
因为我想要做到的
The associated value wants to be those functions.
是把函数作为关联值
Can I do that in Swift? Of course!
Swift 允许我这样做吗？当然！
We wouldn't be here if we couldn't do that.
如果不行的话我自然是不会这样讲的
How do we make an associated value be a function?
怎么样把函数作为关联值呢？
Well the cool thing about Swift is that functions
Swift 中很牛的是

English: 
are normal types. Just          
like a double, any struct,      
a class, no difference          
between that and a double.      
So how do I go back up          
to my enum, and it have         
an associated type here be      
a double? How do I say,         
the type which is a function    
that takes a double and         
returns a double? Cuz           
that's what I want in here.     
This is a unary operation, so   
I need this to be a function    
that takes a double and         
returns a double. We just       
type it, function that takes    
a double, returns a double.     
Just type it right in there.    
This is a type.                 
Just a type, just like string,  
but it happens to be            
a function. Now I'm             
going to take a time-out right  
here just to show you a little  
bit more about this             
function types,                 
to make sure you're getting     
this. And what I'm gonna do is  
I'm gonna create a new          
thing called a playground.      
So a playground is just a       
place we can play around with   
iOS code. Okay? So              
you just say new playground,    
this is gonna be an iOS         
playground. I'm gonna call it   
my CalculatorPlayground,        
I can call it anything I want.  
Just gonna save it on disk so   
that what I                     
type in here when I'm playing   
gets saved for the next time.   

Chinese: 
are normal types. Just like a double, any struct,
函数也是一种普通的类型，和 Double
a class, no difference between that and a double.
以及所有的类和结构体一样，没有区别的
So how do I go back up to my enum, and it have
我们回到上面定义枚举的地方
an associated type here be a double? How do I say,
常数的关联值是 Double
the type which is a function that takes a double and
但我要怎么描述接受一个 Double 作为参数
returns a double? Cuz that's what I want in here.
返回一个 Double 的函数的类型？
This is a unary operation, so
这就是括号里的一元运算的类型
I need this to be a function that takes a double and
这个函数接受一个 Double
returns a double. We just type it, function that takes
返回一个 Double，那就直接打出来呗
a double, returns a double. Just type it right in there.
(Double) -> Double
This is a type. Just a type, just like string,
这就是它的类型，就像是 String 那样的
but it happens to be a function. Now I'm
只不过这个类型代表函数
going to take a time-out right here just to show you a little
为了让你们能更好的理解
bit more about this function types,
函数这种类型
to make sure you're getting this. And what I'm gonna do is
我这里稍微花时间讲讲
I'm gonna create a new thing called a playground.
我现在 File > New 一个 Playground
So a playground is just a place we can play around with
playground 是实验 iOS 代码的好地方
iOS code. Okay? So you just say new playground,
这里选 Playground 之后
this is gonna be an iOS playground. I'm gonna call it
Platform 选 iOS
my CalculatorPlayground, I can call it anything I want.
Name 叫 CalculatorPlayground
Just gonna save it on disk so that what I
当然叫什么都可以，然后 Next
type in here when I'm playing gets saved for the next time.
找个地方保存我将要写的代码

Chinese: 
You can put it anywhere you want.
其实放哪里都可以
I recommend the same place, home directory, Developer.
但我建议放到 ~/Developer 下
Okay, don't put it inside another project or whatever.
当然不要放到另一个项目里面去
And you can see the playground looks like this. On the left,
playground 就长这样
you can type any iOS code you want. And on the right,
左边你可以写 iOS 代码
it's going to evaluate what's on the left and show you not
右边会执行你的代码
only, well, it's basically gonna show you the result or
给你展示包括结果
the value of any var that it finds.
和其他所有变量的值
So here it found this var string, str, and it's
它这里找到了字符串变量 str
showing you the value of str over here. Okay? So I can say,
于是就把字符串的内容显示出来了
for example, let i = 27 and it's gonna say that 27 is what
我可以写 let i = 27，右边就会显示 27
it sees there. But I'm gonna create a new var.
就像你看到的这样。但我要另外定义个变量
I'm gonna call it f. Its type is gonna be a function that
var f，接受一个 Double 返回一个 Double
takes a double and returns a double. Okay, that's its type.
类型是 (Double) -> Double
I could have said f, var f string, but
虽然我可以让 f 作为字符串
I said it's a function that takes a double and
不过我就是想要这样一个函数
returns a double. And I'm gonna set the value of f.
然后我要把这个变量 f 的值
I'm gonna set it equal to square root. Okay,
设为平方根 sqrt
I mean it's a function that takes a double and
函数 sqrt 也是接受一个 Double

English: 
You can put it                  
anywhere you want.              
I recommend the same place,     
home directory, Developer.      
Okay, don't put it inside       
another project or whatever.    
And you can see the playground  
looks like this. On the left,   
you can type any iOS code       
you want. And on the right,     
it's going to evaluate what's   
on the left and show you not    
only, well, it's basically      
gonna show you the result or    
the value of any                
var that it finds.              
So here it found this var       
string, str, and it's           
showing you the value of str    
over here. Okay? So I can say,  
for example, let i = 27 and     
it's gonna say that 27 is what  
it sees there. But              
I'm gonna create a new var.     
I'm gonna call it f. Its type   
is gonna be a function that     
takes a double and returns a    
double. Okay, that's its type.  
I could have said f,            
var f string, but               
I said it's a function          
that takes a double and         
returns a double. And           
I'm gonna set the value of f.   
I'm gonna set it equal          
to square root. Okay,           
I mean it's a function          
that takes a double and         

English: 
returns a double. So I can say  
f = square root. Now how do I   
actually call this function?    
Well I'm gonna let x equal f    
of 81, for example.             
Okay, so I call this variable,  
right here, which is a double   
that takes a double,            
just like it was a function.    
And if I were to go back and    
change this to cosine,          
look what happens. Okay,        
so now f is cosine so now I'm   
getting the cosine of 81.       
I can even write                
my own function,                
how bout func changeSign,       
let's say it takes              
a double and                    
returns a double, okay.         
So it's a regular function,     
returns the changeSigned        
operand, right,                 
operand changed sign. So        
now I could go down here and    
change this to be changeSign,   
function I wrote. And           
now I'm getting minus 81.       
Okay? So everyone's seeing how  
this type functions as a type?  
They're just normal type.       
Absolutely, you can use         
a function as a type anywhere   
you can use any other type.     
Argument to a method,           

Chinese: 
returns a double. So I can say f = square root. Now how do I
返回一个 Double，所以可以 f = sqrt
actually call this function? Well I'm gonna let x equal f
那我怎么调用这个函数呢？
of 81, for example. Okay, so I call this variable,
let x = f(81)，就是这样
right here, which is a double that takes a double,
这里我把接受一个 Double 返回一个 Double 的变量
just like it was a function. And if I were to go back and
像普通函数那样调用了
change this to cosine, look what happens. Okay,
我把 f 改为余弦 cos 看看会发生什么
so now f is cosine so now I'm getting the cosine of 81.
现在 f 就是 cos，然后得到了 81 的余弦
I can even write my own function,
其实我还可以用自己写的函数
how bout func changeSign,
比如变号 changeSign
let's say it takes a double and
接受一个 Double 作为参数
returns a double, okay. So it's a regular function,
返回值是一个 Double
returns the changeSigned operand, right,
像普通函数一样 return -operand
operand changed sign. So now I could go down here and
现在到下面
change this to be changeSign, function I wrote. And
把 f 改为我写的 changeSign
now I'm getting minus 81. Okay? So everyone's seeing how
就得到了 -81
this type, functions as a type? They're just normal type.
大家看到表示函数的类型了吗？
Absolutely, you can use a function as a type anywhere
和普通的一样，函数类型可以
you can use any other type. Argument to a method,
在你任何其他使用类型的地方用

Chinese: 
associated value in an enum, local variable, anything.
比如方法的参数，枚举的关联值
No restriction on it, okay? I'm even gonna take the,
局部变量，等等，没有限制
note also, by the way, the change sign has an external
稍微注意一下，changeSign 的参数
name, operand. When you tall, call change sign,
有 operand 作为参数名，所以调用
looks like this. See? We've got this operand. It's okay,
会是 changeSign(operand:)
when I call it down here, I don't have to say f(operand).
我在 f 这里的时候并不需要 f(operand:)
In fact, I can't say that. And that's because f
更准确地说是不能这么调用
is just a function that takes a double, returns a double.
因为 f 只是接受一个 Double 返回一个 Double
It can be any function that takes a double and
任何一个这样的函数都是可以的
returns a double, so you can't have those external names in
所以这里并不能有实参标签
there, cuz it can be any function.
毕竟可以是任何函数
As you change it you can't be changing this, so, anyway,
改变 f 不应该改变其调用的方法
just a minor note there. So I'm gonna take changeSign,
这是我想稍微提一下的地方
actually, and copy and paste it back into my code up here,
其实我要把 changeSign 复制粘贴
so I just made a new function, it's even a nice global
作为一个新的全局函数
to this file, function called changeSign. And
加到计算器的这个文件里
I can go back here and say, changeSign, let's do something
然后把它加到字典里
for changeSign. I think I can remember how to do this,
让我们找个合适的符号
there, Ctrl + C, Cmd + Ctrl + Space, something like that,
command + control + 空格

English: 
associated value in an enum,    
local variable, anything.       
No restriction on it, okay?     
I'm even gonna take the,        
note also, by the way, the      
change sign has an external     
name, operand. When you tall,   
call change sign,               
looks like this. See? We've     
got this operand. It's okay,    
when I call it down here, I     
don't have to say f(operand).   
In fact, I can't say that.      
And that's because f            
is just a function that takes   
a double, returns a double.     
It can be any function          
that takes a double and         
returns a double, so you can't  
have those external names in    
there, cuz it can               
be any function.                
As you change it you can't be   
changing this, so, anyway,      
just a minor note there.        
So I'm gonna take changeSign,   
actually, and copy and paste    
it back into my code up here,   
so I just made a new function,  
it's even a nice global         
to this file, function          
called changeSign. And          
I can go back here and say,     
changeSign, let's do something  
for changeSign. I think I       
can remember how to do this,    
there, Ctrl + C, Cmd + Ctrl +   
Space, something like that,     

Chinese: 
let's go here. Edit, Okay, we need something for
或者 Edit > Emoji & Symbols
changeSign, I think I have one here, this one, okay?
找一个符号代表 changeSign
It's not really change sign [LAUGH] but,
就 ± 吧，虽然并不是这个意思（笑）
it's all right we'll use it for that. And, so
就决定是你了，所以这是
this is an operation, an Operation.unaryOperation(chan-
Operation.unaryOperation(changeSign)
geSign). Okay? Perfectly legal. Okay, everybody got
这样做是可以的，看到了吗？
that? So now, down here in our switch, in the same
接下来到 switch 里
way that we grabbed the constant value with let value,
就像我们获取常量值一样
let's grab that associated function with let function.
我们也把关联的函数用 let function
And again we can call, this doesn't have to be a function.
当然不一定要叫 function
This could be f. It could be func. Can't be func, because
可以是 f，`func`。不能直接是 func
that's a keyword, but function it could be. Okay? So we got
因为那是个关键字，但 function 是可以的
this unary operation. What are we gonna do? Well we just want
现在我们得到了这个一元运算，下一步呢？
to call this thing with the accumulator. Okay?
我们调用 function(accumulator!)
But of course we'd better, I'm sorry, we want our accumulator
哦，忘了，最后赋值给 accumulator
to equal, calling that function with the accumulator.
accumulator = function(accumulator!)
We'd better check though to make sure this is not nil. So
最好再确认 accumulator 是否为空
I'm actually gonna do something a little different.
这里我用个不同的方法

English: 
let's go here. Edit, Okay,      
we need something for           
changeSign, I think I have      
one here, this one, okay?       
It's not really change          
sign [LAUGH] but,               
it's all right we'll use        
it for that. And, so            
this is an operation, an        
Operation.unaryOperation(chan-  
geSign). Okay? Perfectly        
legal. Okay, everybody got      
that? So now, down here in      
our switch, in the same         
way that we grabbed the         
constant value with let value,  
let's grab that associated      
function with let function.     
And again we can call, this     
doesn't have to be a function.  
This could be f. It could be    
func. Can't be func, because    
that's a keyword, but function  
it could be. Okay? So we got    
this unary operation. What are  
we gonna do? Well we just want  
to call this thing with         
the accumulator. Okay?          
But of course we'd better, I'm  
sorry, we want our accumulator  
to equal, calling that          
function with the accumulator.  
We'd better check though to     
make sure this is not nil. So   
I'm actually gonna do           
something a little different.   

English: 
Instead of if let, I'm gonna    
say if the accumulator does     
not equal nil. Then we'll       
do this. This is another        
way to protect against this     
crashing your app. Okay,        
somewhat similar to if let      
operand equal accumulator,      
but I'm just actually checking  
to see if accumulator is in     
the not set state,              
accumulator isn't optional,     
so it can be equal to nil or    
it's equal to something else,   
and it has an associated value  
like these things. All right?   
That's all we need to do.       
Let's take a look. Whoops,      
we, we have errors there?       
No, we don't. Okay. All right.  
So, pi, still good.             
81, square root.                
Working like a charm. Okay,     
and again if we add cosine and  
those which we are going to     
add those in a second, but for  
time I'm not adding them in.    
But we'll add cosine and        
all, actually I'm,              
forget it, let's do it.         
Let's go back to our UI right   
here and let's add those other  

Chinese: 
Instead of if let, I'm gonna say if the accumulator does
我不用 if let，而是用 if accumulator
not equal nil. Then we'll do this. This is another
!= nil 那就进行计算
way to protect against this crashing your app. Okay,
这是避免程序崩溃的另一种方式
somewhat similar to if let operand equal accumulator,
和 if let operand = accumulator 是类似的
but I'm just actually checking to see if accumulator is in
只不过这里是直接判断
the not set state,
accumulator 是否为空
accumulator is an optional, so it can be equal to nil or
既然 accumulator 是可选的，那就可能是 nil
it's equal to something else, and it has an associated value
也有可能是其他的关联值
like these things. All right? That's all we need to do.
就像是 Operation 的 case 有关联值一样
Let's take a look. Whoops, we, we have errors there?
我们要干的就这些。啊哦，有错？
No, we don't. Okay. All right.
啊，虚惊一场
So, pi, still good. 81, square root.
看看圆周率，没问题。81 开根
Working like a charm. Okay, and again if we add cosine and
完美解决。如果我们把余弦
those which we are going to add those in a second, but for
和其他的那些等会儿加进来之后
time I'm not adding them in. But we'll add cosine and
虽然我没有时间把所有的按钮都加进来
all, actually I'm, forget it, let's do it.
但是我至少可以，啊，其实我们有时间
Let's go back to our UI right here and let's add those other
让我们回到 Storyboard，加些按钮

Chinese: 
buttons. Let's put cosine in here. Cosine,
把余弦放在这里，cos
and let's even put our little change sign that we did there.
然后把变号的那个加到这里
Ctrl+Cmd+Space, there we go. Change sign.
control + command + 空格
Put the change sign in there. So we'll put those in there
把 ± 放在这里，这就是
and that's all we need to do in my UI.
目前对 UI 做出的改动
It can just run again, because my brain,
让我们再运行一遍
my model already knows how to do those operations.
我的模型已经知道如何处理这两个了
So I can put any operation my brain knows how to do
所以我可以把所有支持的运算
into my calculator's UI and it'll just work.
加到 UI 里，因为都可以直接用
So here we got, you know, how about pi cosine, -1.0,
我们试试 cos(π) = -1
all right? Change sign, positive 1.0. All right, so
没问题。变号得正一
this is really looking nice, because our calculator brain,
看起来不错，因为并没有
still hardly any code in here, and yet
给 CalculatorBrain 加很多代码
now it's fully extensible for both constants and
现在已经支持加常数
unary operations. What's next? Binary operations.
和一元运算了。那接下来就是二元运算
5 times 3 equals, okay, much more difficult, right?
5 * 3 = 这样更复杂的

English: 
buttons. Let's put              
cosine in here. Cosine,         
and let's even put our little   
change sign that we did there.  
Ctrl+Cmd+Space, there we go.    
Change sign.                    
Put the change sign in there.   
So we'll put those in there     
and that's all we               
need to do in my UI.            
It can just run again,          
because my brain,               
my model already knows how      
to do those operations.         
So I can put any operation      
my brain knows how to do        
into my calculator's UI and     
it'll just work.                
So here we got, you know,       
how about pi cosine, -1.0,      
all right? Change sign,         
positive 1.0. All right, so     
this is really looking nice,    
because our calculator brain,   
still hardly any code in here,  
and yet                         
now it's fully extensible for   
both constants and              
unary operations. What's next?  
Binary operations.              
5 times 3 equals, okay,         
much more difficult, right?     

English: 
Because there's actually two    
operations there when we do 5   
times 3 equals. There's the     
times, which puts you in this   
weird pending state, and        
then there's the equals which   
actually finishes the 5 times   
3 equals, right? So I'm         
gonna need some data structure  
to remember the 5 times         
until the equals comes along.   
Okay, so let's do that,         
let's add a data structure for  
that. Actually, before we even  
do that, let's back up here     
and talk about all this mess.   
What's this gonna be like for   
binary operations? So we need   
a binary operation here.        
And what's its type gonna be?   
What's its associated value     
gonna be? What do you think?    
How about a function            
that takes two double and       
returns a double? All right,    
and we're also gonna need       
an equals operation as well.    
And so                          
we can just go down here and    
do, for example, times,         
let's do times.                 
Oops, space, there we go.       

Chinese: 
Because there's actually two operations there when we do 5
因为这里同时会进行两个运算
times 3 equals. There's the times, which puts you in this
5 * 3 = 中有乘法，会让你进入一个
weird pending state, and then there's the equals which
奇怪的等待期，又有一个等于
actually finishes the 5 times 3 equals, right? So I'm
这才结束 5 * 3 =，是吧？
gonna need some data structure to remember the 5 times
所以直到按下等号之前
until the equals comes along. Okay, so let's do that,
我需要一个数据结构保存 5 *
let's add a data structure for that. Actually, before we even
让我们这就添加一个数据结构
do that, let's back up here and talk about all this mess.
不过在那之前
What's this gonna be like for binary operations? So we need
我们先让 Operation 支持二元运算
a binary operation here. And what's its type gonna be?
所以我们先加一个 case binaryOperation
What's its associated value gonna be? What do you think?
你觉得它关联值的类型是什么呢？
How about a function that takes two double and
是接受两个 Double 返回 Double 的 函数
returns a double? All right, and we're also gonna need
(Double, Double) -> Double
an equals operation as well. And so
同时还要有个 case equals
we can just go down here and do, for example, times,
然后我们到下面把乘号
let's do times. Oops, space, there we go.
command + control + 空格

English: 
I've got a nice mathematical    
times symbol here. Okay,        
we have to enter in             
Operation.binaryOperation. And  
we need multiply basically      
here. So I'm gonna make my own  
multiply function.              
We'll just put multiply there.  
Also of course, I need equals   
which is Operation.equals.      
Okay, put those on my table.    
So this multiply,               
where's that? There's no        
function called multiply.       
Well, just like I did           
changeSign up here,             
I'm gonna create my             
own little func,                
multiply. It's gonna take op1,  
which is a Double,              
and op2,                        
which is a Double. And          
it's gonna return a Double,     
of course. Oops, and            
it's just gonna return          
op1 times op2, okay?            
So I got this nice function     
up here. Fits in here nice,     
no error, everything's          
fine there, got that. So        
now we have the hard part of    
what do we do with the case     
here that is binary operation?  
We still have a function,       
but now it's a function that    
takes two doubles and returns   

Chinese: 
I've got a nice mathematical times symbol here. Okay,
用数学里这个漂亮的乘号 ×
we have to enter in Operation.binaryOperation. And
值是 Operation.binaryOperation
we need multiply basically here. So I'm gonna make my own
这里我们要有一个实现乘法的函数
multiply function. We'll just put multiply there.
所以我就自己写一个，叫 multiply
Also of course, I need equals which is Operation.equals.
还需要一个 "=" : Operation.equals
Okay, put those on my table. So this multiply,
把这些都放进字典里
where's that? There's no function called multiply.
但 multiply 是从哪里来的呢？
Well, just like I did changeSign up here,
没有那就像 changeSign 一样
I'm gonna create my own little func,
在上面自己写一个 multiply 函数
multiply. It's gonna take op1, which is a Double,
第一个参数是为 Double 的 op1
and op2, which is a Double. And
第二个参数 op2 也是 Double
it's gonna return a Double, of course. Oops, and
返回值是一个 Double
it's just gonna return op1 times op2, okay?
然后就 return op1 * op2
So I got this nice function up here. Fits in here nice,
multiply 就写好了
no error, everything's fine there, got that. So
没有编译错误
now we have the hard part of what do we do with the case
现在就可以开始解决难题了
here that is binary operation? We still have a function,
在 case .binaryOperation 时究竟做什么
but now it's a function that takes two doubles and returns
我们仍然可以用 let function 获取关联值

English: 
a double. All right, so what    
are we gonna do here? Get,      
like I said, we're gonna need   
some kind of data structure     
to remember five times and      
wait till we get another        
case which is equals, okay?     
And we're gonna have to         
do something in here. So        
let's take a time out here and  
create another data structure   
to remember five times          
while we're waiting for         
three equals to happen.         
So I'm gonna make it a struct.  
It's also gonna be an embedded  
private struct, just like this  
was embedded private enum.      
So the name of this enum,       
its full name is                
CalculatorBrain.Operation, but  
as long as I'm using            
it inside this struct,          
we can just call it operation,  
like we did right here.         
Okay, so same thing here.       
I'm gonna call this one         
PendingBinaryOperation.         
Okay, it's gonna be             
a PendingBinaryOperation.       
And it's gonna have two vars.   
One is the function which is    
gonna be, it takes two          
Doubles, returns a Double. And  

Chinese: 
a double. All right, so what are we gonna do here? Get,
不过是接受两个 Double 返回个 Double
like I said, we're gonna need some kind of data structure
我们现在需要的是一个数据结构
to remember five times and
用来记忆 5 *
wait till we get another case which is equals, okay?
直到我们等到 case .equals
And we're gonna have to do something in here. So
这里先补个 break 占位
let's take a time out here and create another data structure
那我们就来定义这个类型
to remember five times while we're waiting for
来保存 5 * 直到 3 =
three equals to happen. So I'm gonna make it a struct.
我会用一个结构体
It's also gonna be an embedded private struct, just like this
这会是个嵌套的私有结构体
was embedded private enum. So the name of this enum,
就像这个嵌套的私有枚举一样
its full name is CalculatorBrain.Operation, but
它名字叫做 CalculatorBrain.Operation
as long as I'm using it inside this struct,
但只要我们在这个类里面调用
we can just call it operation, like we did right here.
就可以只叫它 Operation
Okay, so same thing here.
这里同理
I'm gonna call this one PendingBinaryOperation.
我把它叫做 PendingBinaryOperation
Okay, it's gonna be a PendingBinaryOperation.
因为它是即将完成的二元运算
And it's gonna have two vars. One is the function which is
里面有两个变量。其一是二元函数
gonna be, it takes two Doubles, returns a Double. And
let function: (Double, Double) -> Double

English: 
it's going to have the first    
operand, which is a Double.     
So it's just gonna be a struct  
that holds those two things.    
Now never forget that structs   
in Swift can have methods and   
things like that. In fact,      
I'm gonna put a method on here  
just to remind us of that.      
I'm gonna have a func           
called perform which will       
perform this binary operation.  
Now what does                   
it need to perform it?          
It needs a second operand.      
Okay? And it's gonna            
return a double. Okay,          
now, notice the naming here.    
Why did I use this naming,      
with as my external and here    
secondOperand as my internal?   
Well, secondOperand             
is the internal,                
because that's what             
this argument is.               
And in my code here,            
I want the firstOperand and     
secondOperand to have           
the right names. But            
I'm using with because when     
someone calls this, they're     
gonna say perform(with: 5.0).   
And of course,                  
if they're performing           
a pending binary operation, so  
this makes perfect sense.       
If you say binary operation,    

Chinese: 
it's going to have the first operand, which is a Double.
另一个是 let firstOperand: Double
So it's just gonna be a struct that holds those two things.
所以就是有两个变量的这么一个结构体
Now never forget that structs in Swift can have methods and
不要忘了结构体里也可以有方法
things like that. In fact,
以及其他的那些
I'm gonna put a method on here just to remind us of that.
我现在就写一个提醒大家
I'm gonna have a func called perform which will
就叫 func perform
perform this binary operation. Now what does
执行这个二元函数
it need to perform it? It needs a second operand.
那它需要什么参数？它需要第二个算子，并返回 Double
Okay? And it's gonna return a double. Okay,
(with secondOperand: Double) -> Double
now, notice the naming here. Why did I use this naming,
注意这里的命名。为什么
with as my external and here secondOperand as my internal?
实参标签是 with，形参名称是 secondOperand
Well, secondOperand is the internal,
secondOperand 是内部使用的
because that's what this argument is.
因为这个参数就是我的第二个算子
And in my code here, I want the firstOperand and
并且我希望 firstOperand 和
secondOperand to have the right names. But
secondOperand 的命名风格类似
I'm using with because when someone calls this, they're
但我还要求调用时加一个 with 作为实参标签
gonna say perform(with: 5.0). And of course,
也就是类似 perform(with: 5.0)
if they're performing a pending binary operation, so
因为这是在完成未完成的二元运算
this makes perfect sense. If you say binary operation,
所以这段代码用英文读起来很通顺

English: 
perform(with: 5.0). It makes    
sense, right? And these         
internal names, even though     
they're only used internally,   
you can think of them as        
part of the documentation.      
Cuz anyone who sees the         
documentation of this method,   
he's gonna see both with and    
secondOperand, see? So they're  
kind of getting a little bit    
of documentation that that      
with is with the secondOperand  
to this binary operation.       
Okay, and how would we perform  
this? Well, we would just       
return the firstOperand times   
the secondOperand, okay? But    
we're not doing times here,     
we're doing this function.      
So I'm gonna call it that       
function with the firstOperand  
and the secondOperand. Okay,    
this is a really simple little  
method, but I just              
wanted to make it clear.        
Notice this method doesn't      
have mutating on it. Because    
it doesn't actually change      
the PendingBinaryOperation,     
right? It just returns to the   
evaluation of the function,     
but it doesn't change any       
internal values. Also notice,   

Chinese: 
perform(with: 5.0). It makes sense, right? And these
用 5.0 完成二元运算，能理解吧？
internal names, even though they're only used internally,
而形参名称虽然只是内部使用
you can think of them as part of the documentation.
但你需要把它视为注释文档的一部分
Cuz anyone who sees the documentation of this method,
因为所有查阅这个方法文档的人
he's gonna see both with and secondOperand, see? So they're
都能同时看见 with 和 secondOperand
kind of getting a little bit of documentation that that
所以他们可以知道计算二元运算
with is with the secondOperand to this binary operation.
with 的是 secondOperand
Okay, and how would we perform this? Well, we would just
那我们要怎么计算呢？
return the firstOperand times the secondOperand, okay? But
返回它们相乘就好了
we're not doing times here, we're doing this function.
但这里不该用乘法，而是调用这个 function
So I'm gonna call it that function with the firstOperand
return function(firstOperand, secondOperand)
and the secondOperand. Okay, this is a really simple little
perform 这个函数挺简单的
method, but I just wanted to make it clear.
但这样能让代码更简明
Notice this method doesn't have mutating on it. Because
但这个方法并没有 mutating 修饰
it doesn't actually change the PendingBinaryOperation,
因为它并没有改变 PendingBinaryOperation
right? It just returns to the evaluation of the function,
它只是返回了 function 的计算结果
but it doesn't change any internal values. Also notice,
并没有修改变量的值

Chinese: 
these are lets. That's because I'm gonna create this
更何况这两个是 let
PendingBinaryOperation in a moment with these two things
因为创建 PendingBinaryOperation
set and I'm never gonna change them.
之后就不会改了
So they are constants in this struct. Now, also notice,
所以我选择用常量
no error that says you don't have an initializer and you
还有注意到这里没有构造器
have these two uninitialized vars. Again, this is a struct.
但却没有报错说有两个未初始化的变量
Structs automatically get a free initializer
这是因为结构体会自动提供构造器
which will initialize all of these things. And
并通过那个构造器初始化所有属性
in fact, let's use that right now.
我们现在就用来看看
I'm gonna create a private var, which I'm gonna call pbo,
我定义一个 private var pbo
PendingBinaryOperation, but only temporarily, because
PendingBinaryOperation 首字母简写
this is a bad name. I'm mostly doing it so things won't
但这个烂名字只是暂时的，为了避免换行
wrap, cuz I'm using a big font so you can see here. I'm gonna
我为了你们能看清，把字号调得很大
go actually change this back to a better name in a second.
之后我们再改为一个更好的名字
But this pbo is a PendingBinaryOperation,
pbo 是 PendingBinaryOperation
and optional.
而且是可选的
Why is this an optional PendingBinaryOperation?
为什么是可选的 PendingBinaryOperation？
Cuz we're not always in the middle of a binaryOperation.
因为我们并不总是在等待的过程中
Only when the person taps five times. Okay,
只有在按如 5 * 时才会有值
if we'd said five square root,
如果计算根号五

English: 
these are lets. That's          
because I'm gonna create this   
PendingBinaryOperation in       
a moment with these two things  
set and                         
I'm never gonna change them.    
So they are constants in this   
struct. Now, also notice,       
no error that says you don't    
have an initializer and you     
have these two uninitialized    
vars. Again, this is a struct.  
Structs automatically           
get a free initializer          
which will initialize           
all of these things. And        
in fact,                        
let's use that right now.       
I'm gonna create a private      
var, which I'm gonna call pbo,  
PendingBinaryOperation, but     
only temporarily, because       
this is a bad name. I'm mostly  
doing it so things won't        
wrap, cuz I'm using a big font  
so you can see here. I'm gonna  
go actually change this back    
to a better name in a second.   
But this pbo is                 
a PendingBinaryOperation,       
and optional.                   
Why is this an optional         
PendingBinaryOperation?         
Cuz we're not always in the     
middle of a binaryOperation.    
Only when the person            
taps five times. Okay,          
if we'd said five square root,  

Chinese: 
we're not in the middle of a PendingBinaryOperation, so
我们就没在这个等待过程中
this has to be not set. Are you starting to get a feel for
所以这就会是在未赋值的状态
how we use optionals all over the place,
感受到为了准确表达
to be semantically exactly what we mean? And here,
使得可选无处不在了吗？
if we're not in the middle of PendingBinaryOperation,
如果我们不是在等待的话
this is not set. So it's an optional. All right, so
pbo 就是未赋值的，所以它是可选的
when you've pressed the times,
当你按下乘号（和其他二元运算）的时候
5 times, all I'm gonna do here is remember, or create,
我就新建一个 PendingBinaryOperation
a PendingBinaryOperation.
把按下的 5 * 存储下来，也就是
So I'm gonna say pbo = PendingBinaryOperation.
pbo = PendingBinaryOperation
Now when I tab here, and I do the open parentheses. Look,
按制表符键，然后左括号
it's showing me that there's already an initializer,
自动提示了构造器，再按 tab 键补全
one that, tab, takes function and firstOperand.
它接受 function 和 firstOperand
Woo-hoo! So this is that free initializer I get,
啊哈！这就是我免费得到的构造器
because I'm a struct down here, not a class. So what is
原因是我用的是结构体，不是类
the function? Well, that's just this function right here,
那 function 是什么？
that we got as our associated value.
就是 binaryOperation
That's the function in the binaryOperation.
的那个关联值 function
And what's the firstOperand?
那 firstOperand 呢？
Well, it's our current accumulator, right,
嗯，那个就是 accumulator，既然是 5 *

English: 
we're not in the middle of      
a PendingBinaryOperation, so    
this has to be not set. Are     
you starting to get a feel for  
how we use optionals            
all over the place,             
to be semantically exactly      
what we mean? And here,         
if we're not in the middle      
of PendingBinaryOperation,      
this is not set. So it's        
an optional. All right, so      
when you've pressed the times,  
5 times, all I'm gonna do       
here is remember, or create,    
a PendingBinaryOperation.       
So I'm gonna say pbo =          
PendingBinaryOperation.         
Now when I tab here, and I do   
the open parentheses. Look,     
it's showing me that there's    
already an initializer,         
one that, tab, takes            
function and firstOperand.      
Woo-hoo! So this is that        
free initializer I get,         
because I'm a struct down       
here, not a class. So what is   
the function? Well, that's      
just this function right here,  
that we got as our              
associated value.               
That's the function in          
the binaryOperation.            
And what's the firstOperand?    
Well, it's our current          
accumulator, right,             

Chinese: 
five times are equal if it's a five, okay? Now,
那 accumulator 就是 5 吧
here I'm unwrapping it, so I better do if accumulator
这里我用的是强制解包，所以我最好
does not equal nil. Cuz I don't want to crash here and
确认它不为空，因为我并不想程序崩溃
I'm, so that means I'm gonna ignore times. If you've
如果是我就忽略掉
pressed times and you haven't given me an operand,
如果按乘号之前没有输入数字
we're just gonna ignore that. It's like if you start up your
那我就直接忽略
calculator and say, times 3 equals, I'm gonna ignore it,
就像是你一打开计算器就按 * 3 =
because I don't have any operands who times it by.
因为没有第一个算子，所以直接忽略乘法
Okay, so that's good, that's what I want. Also, when I
很好，这是我想要的
have this times, I'm gonna set my accumulator here to nil.
还有，这里要设 accumulator = nil
Because I'm in this weird half state five times,
因为我现在处在这奇怪的等待阶段
my accumulator is waiting for
我的累加器正在等待
the three equals to be set to anything.
完成 3 = 这后面半步
So I'm setting it to nil not set for the moment. All right,
所以现在要暂时设为空
so that's it, that's all I need to do when times is hit.
这就是我按下乘号时要做的
But now when equals is hit, I have the the three, and
现在按下了等号，我得到了 3
I need to calculate five times three.
我需要计算 5 * 3
So I need to actually call this perform down here. So
所以我需要调用 perform(with:)
I'm gonna put this in its own little method. I'm gonna call
我把这部分放到单独的函数里

English: 
five times are equal if         
it's a five, okay? Now,         
here I'm unwrapping it, so      
I better do if accumulator      
does not equal nil. Cuz I       
don't want to crash here and    
I'm, so that means I'm gonna    
ignore times. If you've         
pressed times and you           
haven't given me an operand,    
we're just gonna ignore that.   
It's like if you start up your  
calculator and say, times 3     
equals, I'm gonna ignore it,    
because I don't have any        
operands who times it by.       
Okay, so that's good, that's    
what I want. Also, when I       
have this times, I'm gonna set  
my accumulator here to nil.     
Because I'm in this weird       
half state five times,          
my accumulator is waiting for   
the three equals to             
be set to anything.             
So I'm setting it to nil not    
set for the moment. All right,  
so that's it, that's all I      
need to do when times is hit.   
But now when equals is hit,     
I have the the three, and       
I need to calculate             
five times three.               
So I need to actually call      
this perform down here. So      
I'm gonna put this in its own   
little method. I'm gonna call   

Chinese: 
it performBinaryOperation, actually, we'll even say
叫做 performPendingBinaryOperation
performPendingBinary, oops, BinaryOperation, okay.
performPendingBinaryOperation()
I'm putting it in another method,
放到另一个方法中
you'll see why in a moment. Okay, so I'm gonna do private
等会你就知道为什么了。定义
func which is that, now what am I gonna do in here? Well,
private func performPendingBinaryOperation
here I'm going to perform that pendingBinaryOperation. So
这里我需要进行未完成的那个二元运算
I'm gonna do pbo.perform, and what am I gonna perform with?
而 secondOperand 就是 accumulator
I'm gonna perform with the current accumulator, okay?
所以是 pbo?.perform(with: accumulator!)
Now notice this put a question mark right there, okay?
注意 pbo 后有一个问号
The reason I need a question mark there, really,
这里的问号
what I wanted was exclamation point. Because pbo, here,
我们之前都是用的感叹号
is an optional, and I need to unwrap it.
因为这是个 Optional，所以需要解包
But what's really cool is if instead of exclamation point,
但是很厉害的是，如果不用感叹号
you put question mark, then it will unwrap it, but
而是用问号的话，依然可以解包
it's not set, it will just ignore this line.
如果为空的话，就直接忽略这一行
Ignore the rest of the line, okay? So
更准确的说是忽略这行之后的代码
that's kind of a cool feature. But I'm not gonna do that,
这是很厉害的功能，但我并不会这么用
cuz I didn't really talked enough about it, so
因为我已经讲了够多了，所以直接
I'm gonna unwrap it. So here I need to make sure pbo is not
强制解包。同时我要保证 pbo 不为空

English: 
it performBinaryOperation,      
actually, we'll even say        
performPendingBinary, oops,     
BinaryOperation, okay.          
I'm putting it in               
another method,                 
you'll see why in a moment.     
Okay, so I'm gonna do private   
func which is that, now what    
am I gonna do in here? Well,    
here I'm going to perform that  
pendingBinaryOperation. So      
I'm gonna do pbo.perform, and   
what am I gonna perform with?   
I'm gonna perform with          
the current accumulator, okay?  
Now notice this put a question  
mark right there, okay?         
The reason I need a question    
mark there, really,             
what I wanted was exclamation   
point. Because pbo, here,       
is an optional, and             
I need to unwrap it.            
But what's really cool is if    
instead of exclamation point,   
you put question mark,          
then it will unwrap it, but     
it's not set,                   
it will just ignore this line.  
Ignore the rest of the line,    
okay? So                        
that's kind of a cool feature.  
But I'm not gonna do that,      
cuz I didn't really talked      
enough about it, so             
I'm gonna unwrap it. So here I  
need to make sure pbo is not    

Chinese: 
nil. And I need to make sure that the accumulator is also
同时还要保证 accumulator
not nil, okay? So if those two things aren't true,
也不为空。如果不满足任一条件
I don't really want to be
我并不希望
doing this line of code right here,
执行下面这行代码
right? So I'm performing it, I get the results and
所以我完成运算之后
I'm going to put that in my accumulator, okay?
把结果保存在 accumulator 里
So my accumulator is no longer nil, why is this happening?
accumulator 就不为空了。为什么报错？
It's the third time, mutating, all right, excellent,
第三次了哦？没错，要加 mutating，很好
I love it when people catch on real quick. So, yeah, that
我就喜欢这种一点即通的学生
needs to be mutating, cuz this is changing the accumulator.
所以这个函数是 mutating 的，因为改了 accumulator
So it's modifying the internal state of the calculator brain.
也就是修改了 CalculatorBrain 的状态
Now, the other thing is no longer am I in the middle
现在我也就没有在等待完成二元运算了
of a pendingBinaryOperation, so I have to set that to nil.
所以要把让 pbo = nil
Okay, cuz I wanna be consistent in all my
我这样保证了
code that when that's nil, I'm not in the middle of a pending
当 pbo 为空时，就没在二元运算
operation. I just had the three equals, okay,
过程中。连按三次等号就是个例子
everybody set? Now, I told you I didn't like pbo as a name.
好吧？我之前说了不喜欢 pbo
It's a bad name, okay? Someone looking at it would have to go
这是个烂名字。其他人看到了
look at the declaration to figure out it.
还需要去看实际的定义来理解

English: 
nil. And I need to make sure    
that the accumulator is also    
not nil, okay? So if those      
two things aren't true,         
I don't really want to be       
doing this line of              
code right here,                
right? So I'm performing it,    
I get the results and           
I'm going to put that in        
my accumulator, okay?           
So my accumulator is no longer  
nil, why is this happening?     
It's the third time, mutating,  
all right, excellent,           
I love it when people catch     
on real quick. So, yeah, that   
needs to be mutating, cuz this  
is changing the accumulator.    
So it's modifying the internal  
state of the calculator brain.  
Now, the other thing is no      
longer am I in the middle       
of a pendingBinaryOperation,    
so I have to set that to nil.   
Okay, cuz I wanna be            
consistent in all my            
code that when that's nil, I'm  
not in the middle of a pending  
operation. I just had           
the three equals, okay,         
everybody set? Now, I told you  
I didn't like pbo as a name.    
It's a bad name, okay? Someone  
looking at it would have to go  
look at the declaration         
to figure out it.               

English: 
A better name here would be     
pendingBinaryOperation, so      
I'm gonna change it to that.    
And here's how you can change   
the name of something all       
throughout the context          
that it's in.                   
You just mouse over it,         
I haven't clicked on it,        
I moused over it.               
You see that little arrow that  
appears? If you click on that   
you get a menu and you can      
say, Edit All in Scope. And     
now when you change this, it's  
changing it everywhere. Okay,   
so I changed it from pbo        
to PendingBinaryOperation.      
You can see why I did that,     
because I didn't want           
the wrapping to happen when     
we were first doing it, okay?   
So that's it,                   
that's all we need to do for    
our little                      
Pending BinaryOperation, so     
let's go ahead and add some     
pending, some binary, so let'a  
add some binary operations to   
our UI. In fact, I'm going      
to add a few that we don't      
even have in our table yet.     
So let's do times,              
come up in the space.           
Yeah, so here's times, but      
I'm also going to do the other  
ones here divide and plus and   
it's just so we don't have to   

Chinese: 
A better name here would be pendingBinaryOperation, so
最好叫做 pendingBinaryOperation
I'm gonna change it to that. And here's how you can change
所以我把所有 pbo 改为 pendingBinaryOperation
the name of something all throughout the context
你在当前上下文修改变量名称的方法
that it's in. You just mouse over it,
是通过把鼠标移到变量上
I haven't clicked on it, I moused over it.
我没有点击，就悬停在上面
You see that little arrow that appears? If you click on that
看到右边那个小箭头了吗？点击之后
you get a menu and you can say, Edit All in Scope. And
你会看到一个菜单，点 Edit All in Scope
now when you change this, it's changing it everywhere. Okay,
现在你改这一个地方，其他的都会跟着改
so I changed it from pbo to PendingBinaryOperation.
这样我就把 pbo 改为 pendingBinaryOperation 了
You can see why I did that, because I didn't want
现在你就可以看出我为什么用 pbo 了
the wrapping to happen when we were first doing it, okay?
因为我不希望出现这样换行的情况
So that's it, that's all we need to do for
所以这就是我们针对
our little Pending BinaryOperation, so
未完成二元运算的处理
let's go ahead and add some pending, some binary, so let'a
我们这就去添加一些
add some binary operations to our UI. In fact, I'm going
二元运算符到 UI 界面上吧
to add a few that we don't even have in our table yet.
同时也把字典里补充上
So let's do times, command control space.
添加个乘号吧，按 command + control + 空格
Yeah, so here's times, but I'm also going to do the other
选这个乘号。顺便把其他的也加上
ones here divide and plus and it's just so we don't have to
除号，加号，这样我们就不需要

English: 
come back here again to do      
that. So there's divide, and    
that there, I'll do             
another one, do plus and        
minus here. So I'm doing        
command control space,          
I guess,                        
to get this little emojis and   
symbols thing and               
a plus, okay?                   
And we need one other thing,    
equals, gotta have an equals    
button. So we'll put that down  
there, okay? So now we only     
have times, so times is the     
only one that should work but   
let's see. Actually I'm gonna   
bring back that code so         
you can see it at the same      
time. It's hard to see it all   
at once, but.                   
All right here we go, okay?     
4 square root, that's still     
working, pi, still working.     
How about 8 times 6 equals,     
wahoo, square root?             

Chinese: 
come back here again to do that. So there's divide, and
最后再倒回来加这么几个按钮。选这个除号
that there, I'll do another one, do plus and
复制个放到这里，再复制一个，改成加号
minus here. So I'm doing command control space,
和减号。还是按 command + control + 空格
I guess, to get this little emojis and
调出对话框
symbols thing and a plus, okay?
选择表情符号
And we need one other thing, equals, gotta have an equals
我们还需要另外一个，等号，必不可少的
button. So we'll put that down there, okay? So now we only
把它放到这下面
have times, so times is the only one that should work but
现在我们只实现了乘法的代码，所以应该只有乘号能用
let's see. Actually I'm gonna bring back that code so
我们实际看看吧。我把代码也调出来
you can see it at the same time. It's hard to see it all
虽然不能一次看全，但至少有个对照
at once, but. All right here we go, okay?
好，我们来试试
4 square root, that's still working, pi, still working.
4 的平方根，正常，派，也能用
How about 8 times 6 equals, wahoo, square root?
8 乘 6 等于 ，哇哦，那平方根呢？

English: 
Nice, okay, so times is         
working there beautifully.      
Now the only thing is,          
we have to do divide and        
all that, so                    
I guess what I have to do is,   
I go create this four times.    
And I'm gonna have to go        
here again and Ctrl+Space       
again, we'll do divide. And     
we'll go here and Ctrl+Space    
and we'll do plus. And          
then we're gonna go here and    
we'll do command, space, and    
we'll do minus, okay?           
Now, am I gonna have to write,  
write a method divide and       
go up here and                  
copy and paste this and         
do one with divide? You know,   
if I have to do that, all of    
a sudden, I'm feeling like,     
this whole table business       
really didn't buy me that       
much, right? Cuz I'm still      
having to create a method for   
every single binary operation   
I want to do? I mean, for       
unary operations it was nice    
because I had all these built   
in ones, I did have to make     
this one method. Yeah, I can    
even see with unary operations  
I wanna create a bunch more     
and I'm having to create        
these other functions.          
It's not really                 
working out for me.             

Chinese: 
Nice, okay, so times is working there beautifully.
很好，乘法已经没有问题了
Now the only thing is, we have to do divide and
现在唯一剩下的就是除法那些了
all that, so I guess what I have to do is,
我应该只需要
I go create this four times. And I'm gonna have to go
把这个复制四遍。然后在这里
here again Cmd+Ctrl+Space again, we'll do divide. And
command + control + 空格，替换成除号
we'll go here Cmd+Ctrl+Space and we'll do plus. And
这里再 command + control + 空格 选加号
then we're gonna go here and we'll do Cmd+Ctrl+Space, and
这里再来一次 command + control + 空格
we'll do minus, okay? Now, am I gonna have to write,
选择减号。现在难道我需要
write a method divide and go up here and
写 divide，然后在上面
copy and paste this and do one with divide? You know,
把乘法的代码复制粘贴，乘号换除号？
if I have to do that, all of a sudden, I'm feeling like,
如果我必须这样做的话，我觉得
this whole table business really didn't buy me that
这个列表并不是很好的设计
much, right? Cuz I'm still having to create a method for
因为我还需要写不同的方法
every single binary operation I want to do? I mean, for
分别处理每个二元运算？
unary operations it was nice because I had all these built
对于一元运算来说还好，有现成的函数可以用
in ones, I did have to make this one method. Yeah, I can
虽然我还是自己写了一个
even see with unary operations I wanna create a bunch more
其实我还想加几个一元运算
and I'm having to create these other functions.
我还要写几个函数
It's not really working out for me.
这样表格是没有解决我的问题的

Chinese: 
Okay, so how are we gonna fix this? Well, we're gonna use
那要怎么做呢？其实，我们要用到
a feature in Swift, which is really powerful.
Swift 中很强大的功能
And you're gonna have to get used to it,
你可能需要一段时间适应
cuz it's not in a lot of other languages.
因为其他的许多语言都是没有的
It is in some other languages,
还是有其他语言有这个功能的
I don't wanna make it sound like it's not around,
澄清一下，并不是说这个功能很小众
it's definitely around. But may not be something you've
挺流行的，虽然你们不一定用过
used in any languages you've used and it's called closures.
这个功能叫闭包
Okay, how many people know what a closure is,
有多少人知道闭包？
have heard that before?
或者至少听说过？
See, almost none of you, so a closure is a function
看吧，基本没人知道。闭包是指
embedded right in line of your code, okay? And so,
嵌入代码中的函数
we can actually take multiply right here, select its code.
我们其实可以选中 multiply 的代码
I'm gonna cut it, go down here to where I used it and
剪切，然后粘贴到下面
paste it in there. Now if didn't quite work,
我使用 multiply 的地方。不过还没完
there's two things we need to do. One, this open curly brace
有两个地方要稍微改一下。第一个，这个左大括号
needs to be at the beginning. So, we're going to
要放到最开始的地方
replace this open curly brace with the keyword in, and
我们把左大括号替换成关键字 in
put the curly brace at the beginning. So
然后放一个左大括号到开头
that's how you take a function and put it right in line.
这样我们就把一个函数变成了闭包

English: 
Okay, so how are we gonna fix   
this? Well, we're gonna use     
a feature in Swift,             
which is really powerful.       
And you're gonna have           
to get used to it,              
cuz it's not in a lot           
of other languages.             
It is in some other languages,  
I don't wanna make it sound     
like it's not around,           
it's definitely around. But     
may not be something you've     
used in any languages you've    
used and it's called closures.  
Okay, how many people           
know what a closure is,         
have heard that before?         
See, almost none of you,        
so a closure is a function      
embedded right in line of       
your code, okay? And so,        
we can actually take multiply   
right here, select its code.    
I'm gonna cut it, go down       
here to where I used it and     
paste it in there.              
Now if didn't quite work,       
there's two things we need to   
do. One, this open curly brace  
needs to be at the beginning.   
So, we're going to              
replace this open curly brace   
with the keyword in, and        
put the curly brace             
at the beginning. So            
that's how you take a function  
and put it right in line.       

English: 
Just literally copy and         
paste to write in there.        
Change the curly brace to in    
and move it to the beginning,   
okay, got that? So now we       
don't even need multiply,       
all gone. Now this              
doesn't look much better.       
It's still a lot of             
typing stuff in, but            
let's use Swift's inference of  
type to make this a lot nicer.  
Swift knows that this,          
right here is this,             
the associated value of that    
type. So it knows that this     
down here is a function         
that takes two doubles and      
returns a double. So we don't   
need these types right here,    
get rid of those. Okay,         
now it's starting to            
look better. In fact,           
maybe if I go here and put      
some things on the same line.   
Yeah, now I'm liking it, okay.  
But we can do even better than  

Chinese: 
Just literally copy and paste to write in there.
只需要复制粘贴到使用的地方
Change the curly brace to in and move it to the beginning,
把左大括号换成 in，然后在最开始补一个
okay, got that? So now we don't even need multiply,
清楚了吗？这样我们就不需要 multiply 了
all gone. Now this doesn't look much better.
虽然摆脱了函数，但也没好多少
It's still a lot of typing stuff in, but
还是有很多类型定义
let's use Swift's inference of type to make this a lot nicer.
让我们试试用 Swift 的自动类型推导简化代码
Swift knows that this, right here is this,
Swift 知道这个闭包，是 (Double,Double) -> Double 类型的
the associated value of that type. So it knows that this
属于关联值的类型。所以 Swift 知道这个
down here is a function that takes two doubles and
是一个函数，接受两个 Double 型参数
returns a double. So we don't need these types right here,
返回一个 Double，所以不需要在这里声明类型
get rid of those. Okay,
把这些都去掉
now it's starting to look better. In fact,
这下子看起来好多了
maybe if I go here and put some things on the same line.
再整理下代码，放到一行里
Yeah, now I'm liking it, okay. But we can do even better than
现在看着就舒服多了，但还能更好

Chinese: 
this. Swift also knows that this returns something.
因为 Swift 知道有返回值
So we don't need return, okay. Swift also will let you have
所以不需要写 return。还有，不论有多少个参数
any number of arguments you want. Called $0, $1, $2 $3,
Swift 都允许使用 $0，$1，$2，$3 等等来表示
for however how many. So I don't need that or that.
不论多少都行。所以我不需要 op1，op2
I can say $0 times $1.
我可以直接用 $0 * $1
Okay, now I'm winning. Now,
这下我算是克服难题了
the essentials of what is going on here is right there.
只留下了最关键的部分
And there's no extraneous types and
没有像类型定义那样多余的东西
all that business. And of course, that means for
当然，这个方法也可以
these other cases like divide, I can say divide.
用在其他的地方，比如除法，$0 / $1
And for add, here I can say plus, and for subtract,
加法，$0 + $1，减法，$0 - $1
I can do minus, even for our friend change sign right here.
连这个 changeSign 也行
Okay, we can take this copy it paste,
我们可以复制粘贴这个
get rid of all this junk because this is just -$0,
然后把这些乱七八糟的简化成 -$0

English: 
this. Swift also knows that     
this returns something.         
So we don't overturn, okay.     
Swift also will let you have    
any number of arguments you     
want. Called $0, $1, $2 $3,     
for however how many.           
So I don't need that or that.   
I can say $0 times $1.          
Okay, now I'm winning. Now,     
the essentials of what is       
going on here is right there.   
And there's no                  
extraneous types and            
all that business.              
And of course, that means for   
these other cases like divide,  
I can say divide.               
And for add, here I can see     
plus, and for subtract,         
I can do minus, even for our    
friend change sign right here.  
Okay, we can take               
this copy it paste,             
get rid of all this junk        
because this is just -$0,       

English: 
okay? So, this closures allow   
you to do this thing where      
you get the essentials of what  
you're doing, right in there    
in line. So, you're not having  
to go look at some other        
method somewhere like           
changeSign up here.             
The other thing closures allow  
you to do, is to pass off to    
methods some piece of code to   
execute if something fails,     
or when something completes.    
Or do this and                  
animate it, while you're doing  
it, for example. You're gonna   
see API like that. So, being    
able to pass these methods      
around, you're gonna see.       
Really makes for great, great   
API. So, you're just seeing     
the simplest possible use of    
it here. We just using as the   
associated value, but imagine   
it as function, parameters and  
things like that. It's,         
it's pretty incredible. Okay,   
so let's go see if that works.  
All right, 4 x 5 = 20,          
square root, cosine,            

Chinese: 
okay? So, this closures allow you to do this thing where
总之，闭包能够让你
you get the essentials of what you're doing, right in there
抓住重点，就地解决
in line. So, you're not having to go look at some other
不需要到其他地方
method somewhere like changeSign up here.
去找类似于 changeSign 这样具体实现的方法
The other thing closures allow you to do, is to pass off to
闭包还有个用处是
methods some piece of code to execute if something fails,
传给方法一段在运行失败的时候执行的代码
or when something completes. Or do this and
或者是执行完成时运行的代码
animate it, while you're doing it, for example. You're gonna
又或者在执行的过程中加上动画效果
see API like that. So, being able to pass these methods
你会看到许许多多像这样的 API
around, you're gonna see. Really makes for great, great
你会看到能够传递这些方法，是优秀 API 的基础
API. So, you're just seeing the simplest possible use of
这里你看到的只是最简单的例子
it here. We just using as the associated value, but imagine
我们只是把闭包当作关联值
it as function, parameters and things like that. It's,
你可以想象一下，把闭包这种函数当作参数使用
it's pretty incredible. Okay, so let's go see if that works.
这是很难以置信的。好，来看看这样做行不行吧
All right, 4 x 5 = 20, square root, cosine,
试试 4 乘 5 等于，20 的平方根，余弦

Chinese: 
change sign, pi, cosine, this all working beautifully.
变号，派，余弦，都是能用的
And now, we can add as many new operations as we want,
现在我们就可以很方便地添加运算了
with one line each, okay. So, you see how I built a struct
都只需要一行代码。看到为什么我说可以
here that's extensible without having to do sub-classing, and
构造可扩展的结构体，还不需要依赖子类那些的
all that stuff. I can just add thing, and I could even go
我可以自己添加新的运算
further and make this public. If I make this operations
或者是把 operations 标为 public
table public. I also have to make operation public,
当然这样 Operation 也要是 public 的
then other people can get my calculator brain and
这样其他人就可以
add operations to it, okay? So very,
向我的 CalculatorBrain 中定义新运算了
very sensible, not requiring any subclassing whatsoever.
这是很明智的选择，不需要继承什么的
So, structs can often be just as good,
所以使用结构体至少是和类一样
if not a little bit better design point for
甚至比是类更好的设计
classes. All right, the last thing that I wanna do here.
最后要做的是
Let's go back to our simulator. Is talk about
（先让我把模拟器调出来）
the layout of the UI. You see I have this layout right here.
讲解 UI 的布局。现在你看到的界面是这样的
Let's look what happens if I rotate this into landscape
让我们看看横屏是什么样的

English: 
change sign, pi, cosine,        
this all working beautifully.   
And now, we can add as many     
new operations as we want,      
with one line each, okay. So,   
you see how I built a struct    
here that's extensible without  
having to do sub-classing, and  
all that stuff. I can just add  
thing, and I could even go      
further and make this public.   
If I make this operations       
table public. I also have       
to make operation public,       
then other people can get       
my calculator brain int and     
add operations to it,           
okay? So very,                  
very sensible, not requiring    
any subclassing whatsoever.     
So, structs can often           
be just as good,                
if not a little bit             
better design point for         
classes. All right, the last    
thing that I wanna do here.     
Let's go back to our            
simulator. Is talk about        
the layout of the UI. You see   
I have this layout right here.  
Let's look what happens if I    
rotate this into landscape      

Chinese: 
mode. So, I'm gonna go up here in the simulator, and
在模拟器的菜单中
go to Hardware, Rotate Left. Okay, my calculator is
选中 Hardware，Rotate left
now completely unusable. Okay, cuz there's no equals, so
这下计算器就完全不能用了，看不到等号
I can't even do five times three equals, right? So
我连五乘三都算不了
it's completely useless, I guess I can still do pi,
除了圆周率以外都没什么用了
mm, but it's clear that's not what you want, right?
很明显这不是我们想要的
When you rotate, you wanna use that space in that way, okay?
旋转之后我们要把横向空间利用起来
And I promised you we were gonna build a UI that would
我们一定会做到的
work in all those things, and, in fact,
构建一个响应式 UI
we're gonna do that right now. Let's go back to our UI,
说干就干。我们回到 UI
and doing this is not gonna require any change to
而且我们并不需要去
our controller or our model. Okay,
修改控制器或模型
this is purely something we're gonna do in the view, and
我们仅仅需要修改视图
we're gonna do it with this business up down here. Okay,
主要是通过下面的这个工具
this multiple phones that we'll be able to click here,
我们可以点击这些设备
and see how things look in all these different
和这些不同的屏幕方向
orientations right here. And our basic strategy
查看界面的样子。我们的基本策略
is we're gonna stack all these buttons into rows, and then
是把这些按钮堆到一行里
we're gonna stack all those rows on top of each other.
然后再把这一行行的按钮叠起来
And then we're gonna stack that with the display, to make
最后把 display 也叠到上面

English: 
mode. So, I'm gonna go up       
here in the simulator, and      
go to Hardware, Rotate Left.    
Okay, my calculator is          
now completely unusable. Okay,  
cuz there's no equals, so       
I can't even do five times      
three equals, right? So         
it's completely useless,        
I guess I can still do pi,      
mm, but it's clear that's       
not what you want, right?       
When you rotate, you wanna use  
that space in that way, okay?   
And I promised you we were      
gonna build a UI that would     
work in all those things,       
and, in fact,                   
we're gonna do that right now.  
Let's go back to our UI,        
and doing this is not gonna     
require any change to           
our controller or               
our model. Okay,                
this is purely something we're  
gonna do in the view, and       
we're gonna do it with this     
business up down here. Okay,    
this multiple phones that       
we'll be able to click here,    
and see how things look         
in all these different          
orientations right here.        
And out basic strategy          
is we're gonna stack all these  
buttons into rows, and then     
we're gonna stack all those     
rows on top of each other.      
And then we're gonna stack      
that with the display, to make  

Chinese: 
this kind of block that has our UI. Then we're gonna tie
这么一大块就是我们的 UI
the edges of that block, to the edges of the device. So,
最后把这整块的边界和设备的边界连接起来
that as the device changes, that block of stuff, gets
这样不同尺寸的设备上
stretched out, or whatever. And the stuff inside,
那一个部分会自动伸缩把界面填满
is gonna automatically now how to resize the buttons and
里面的那些控件，会自己相应地调整按钮的大小
stuff to lay out. Okay, so that's all that we need to do
这就是我们要做的
to make that happen. To have nice rows and columns here,
为了让最后的排列更整齐
I'm gonna add one more button which you need for
我再加一个按钮
your homework anyway. Which is a dot button. One of your
反正是你们作业里要有的：小数点
homework assignment items, is to make floating point input
作业的其中一项就是允许输入小数
possible. This is already a floating point calculator.
毕竟计算结果可以是小数
I can say 4, 45. Well, I can't type here, sorry.
我可以计算 4，45。好吧，搞错了，这不是模拟器
But I can type 45 and hit square root. And
但是我们是可以计算 45 的平方根的
it would give me a floating point number, right?
这个结果会是个小数，对吧？
But you can't enter any floating point numbers,
但是你却不能自己输入一个小数
'cuz there's no dot, right? So,
因为没有小数点
that's part of your assignment.
这就是你们在作业中要添加的
So, I'll put that in there for you. Okay, so now,
我就在这里把这个添加上好了
I'm gonna take this row. And I'm gonna put it into a stack.
我选中这一行，然后叠到一起
It's gonna be a horizontal stack on its side. And you do
把它们横着排在一起

English: 
this kind of block that has     
our UI. Then we're gonna tie    
the edges of that block, to     
the edges of the device. So,    
that as the device changes,     
that block of stuff, gets       
stretched out, or whatever.     
And the stuff inside,           
is gonna automatically now      
how to resize the buttons and   
stuff to lay out. Okay, so      
that's all that we need to do   
to make that happen. To have    
nice rows and columns here,     
I'm gonna add one more          
button which you need for       
your homework anyway. Which     
is a dot button. One of your    
homework assignment items, is   
to make floating point input    
possible. This is already       
a floating point calculator.    
I can say 4, 45. Well,          
I can't type here, sorry.       
But I can type 45 and           
hit square root. And            
it would give me a floating     
point number, right?            
But you can't enter any         
floating point numbers,         
'cuz there's no dot,            
right? So,                      
that's part of                  
your assignment.                
So, I'll put that in there for  
you. Okay, so now,              
I'm gonna take this row. And    
I'm gonna put it into a stack.  
It's gonna be a horizontal      
stack on its side. And you do   

English: 
that up here with editor.       
Embed in Stack View, okay?      
So, when I do that, see, it     
stacks them up horizontally.    
And I can inspect that stack,   
it's selected right here.       
And you can see Stack View      
right there, it's horizontal.   
I'm gonna put some spacing in   
there, 10 points of spacing.    
I'm also gonna make sure,       
that they're equally spaced.    
So, I want each of the squares  
in there to be the same width.  
All right, so same thing here.  
Let's go this one.              
Now, there's actually another   
way besides going up here,      
editor, embed in. There's       
a button right here for it. So  
common, there's a button        
right there, Embed in Stack,    
so boom, I'll do that. Again,   
I'll put a space in here.       
Notice that the cosine button   
is wider than the 1, 2, 3.      
So, I'm gonna say               
fill equally and                
make them all                   
the same width again,           
Oops, sorry, again,             
so we'll do 10 and              
fill equally. Same thing here,  

Chinese: 
that up here with editor. Embed in Stack View, okay?
方法是在菜单栏中选择 Editor，Embed In，Stack View
So, when I do that, see, it stacks them up horizontally.
点击之后它们就自动横着堆到一起了
And I can inspect that stack, it's selected right here.
现在选中了它，就可以设置这个栈的属性
And you can see Stack View right there, it's horizontal.
可以看到这个 StackView 是 Horizontal，横向的
I'm gonna put some spacing in there, 10 points of spacing.
把合理的 Space，间距设为 10
I'm also gonna make sure, that they're equally spaced.
最后选择 Fill Equally
So, I want each of the squares in there to be the same width.
这样每一个按钮的的尺寸都是一样的
All right, so same thing here. Let's go this one.
同样的，这一行也这么做
Now, there's actually another way besides going up here,
其实，这里还有另外一个方法
editor, embed in. There's a button right here for it. So
点击下面这个按钮就可以了
common, there's a button right there, Embed in Stack,
因为很常用，所以就有了这个 Embed In Stack 按钮
so boom, I'll do that. Again, I'll put a space in here.
一下子就好了。还是像之前那样设置间距
Notice that the cosine button is wider than the 1, 2, 3.
注意现在 cos 比其他的数字按钮要宽
So, I'm gonna say fill equally and
所以要改成 Fill Equally
make them all the same width again,
这样宽度才会一致
Oops, sorry, again, so we'll do 10 and
同样的，这一行也是间距 10
fill equally. Same thing here,
Fill Equally。这一行也是

English: 
stack. Fill equally, 10 and     
we'll stack this one.           
Oops, dammit. Okay, now I'm     
gonna take these horizontal     
stacks. These five horizontal   
and stack them vertically. So,  
I'm gonna embed.                
Notice that it's pretty smart.  
It noticed they were            
above each other so             
it would automatically put      
it in a vertical stack. But,    
it pushed them all over to      
the left in the stack, and I    
want them to spread out across  
the stack. So, I'm gonna have   
the alignment here, instead     
of leading, be fill, and        
that's gonna fill the whole     
width. And of course I want     
spacing here as well, so we'll  
do that. So look at this,       
I got this beautiful keyboard,  
keypad right here for           
my calculator. Now, I'm gonna   
hook that up to this display.   
I'm just gonna select           
them both, and                  
say stack them. Okay, puts      
them into a stack. The left     
line aligned it again,          
leading aligned it there so     
I'm gonna say fill, I don't     
want fill equally here though.  

Chinese: 
stack. Fill equally, 10 and we'll stack this one.
Embed In Stack，Fill Equally，间距 10。最后这个也是
Oops, dammit. Okay, now I'm gonna take these horizontal
啊哦，不小心输错了。好，接下来选中这些横向的栈
stacks. These five horizontal and stack them vertically. So,
把这五个竖着叠在一起
I'm gonna embed. Notice that it's pretty smart.
点 Embed In Stack。Xcode 挺聪明的
It noticed they were above each other so
它注意到这些是竖着排列的
it would automatically put it in a vertical stack. But,
所以自动生成的是竖着排列的栈
it pushed them all over to the left in the stack, and I
但是却把所有的内容都堆到最左边了
want them to spread out across the stack. So, I'm gonna have
我希望的是把整个空间占满
the alignment here, instead of leading, be fill, and
所以我把这里 Alignment 的 Leading 改成 Fill
that's gonna fill the whole width. And of course I want
这样就会把整个都填满
spacing here as well, so we'll do that. So look at this,
当然我希望每一行之间也有间隔
I got this beautiful keyboard, keypad right here for
看啊，这个键盘多么整齐
my calculator. Now, I'm gonna hook that up to this display.
现在，我把这个和 display 叠在一起
I'm just gonna select them both, and
把两个都选中
say stack them. Okay, puts them into a stack. The left
然后 Embed in Stack
line aligned it again, leading aligned it there so
又变成了左对齐
I'm gonna say fill, I don't want fill equally here though.
同理改为 Fill 填充。但是这里我不能选 Fill Equally

Chinese: 
Cuz if I do fill equally here, it's gonna make this display
因为那样 display
the same height as the whole keypad, so
会和键盘一样高
I don't want that. So I just want fill,
这并不是我想要的，所以保持 Fill 就可以了
I want to fill this space, but I do want the spacing here so
但我还是想要间隔，所以还是设为 10
we'll do 10 points again. So, now that my whole UI in a nice
现在我的整个 UI 就被封装到这么一个长方形中了
whole rectangle here. And I'm just gonna tie the edges,
最后把这些边界
of this UI to the edges of the device basically, okay.
和整个设备屏幕的边界捆绑起来
Now, I'm gonna start here, whoops, I'm gonna start, yeah
我选中这个，选错了，选中整个 UI
be careful a little about that too. If you click on something
你们也要注意，有可能你想选的是一个
and drag it, see you might try to drag the inner one away.
却有可能选中了内部的另一个控件
A trick for not doing that, there's two tricks.
有两个解决方案
One, is you can do command shift I believe it is, yeah.
一个是按住 control + shift
Command shift will let you pick which one you want,
然后选择具体是哪一个
under the mouse. Actually it's control shift.
所有鼠标下面的都会列出来
Control shift under the mouse let's you pick it. But,
control + shift 让你从一个列表中选择具体是哪一个
another easy way is to use drag select,
另一个方法是用拖拽选择
to select the one you want, and then pick it up.
把整个选中，然后再移动
Okay, so I'm gonna use the blue lines, actually, to put
现在我要使用这些蓝色的参考线
this at the proper space on the left edge and top.
放置在左上角合适的位置

English: 
Cuz if I do fill equally here,  
it's gonna make this display    
the same height as              
the whole keypad, so            
I don't want that.              
So I just want fill,            
I want to fill this space, but  
I do want the spacing here so   
we'll do 10 points again. So,   
now that my whole UI in a nice  
whole rectangle here. And       
I'm just gonna tie the edges,   
of this UI to the edges of      
the device basically, okay.     
Now, I'm gonna start here,      
whoops, I'm gonna start, yeah   
be careful a little about that  
too. If you click on something  
and drag it, see you might try  
to drag the inner one away.     
A trick for not doing that,     
there's two tricks.             
One, is you can do command      
shift I believe it is, yeah.    
Command shift will let you      
pick which one you want,        
under the mouse.                
Actually it's control shift.    
Control shift under the mouse   
let's you pick it. But,         
another easy way is             
to use drag select,             
to select the one you want,     
and then pick it up.            
Okay, so I'm gonna use the      
blue lines, actually, to put    
this at the proper space        
on the left edge and top.       

Chinese: 
And now I'm gonna do the magic to hook it to an edge. And
接着我要用一种很神奇的方法添加约束
I do that with the Ctrl key, just like we did dragging into
我按下了 control 键，和拖到代码里是一样的
the code. But here, I'm gonna drag from this selected thing.
但是这里是从选中的这个
Make sure the whole thing is selected. And
要确保把整个都选中了
Ctrl+Drag up to the top. So we can tie it to the top.
按 control 然后拖拽到顶部，这样就建立好到顶部的约束了
And when you let go, it's gonna say,
当你放手的时候，它会问你
what relationship do you want between this big box and
这一整块到顶部的关系是什么？
the top? And, and really it's talking about the outer edge.
这里主要是指外层
And you can try and make them the same width, or
你当然可以选择 Equal Widths 等宽
the same height, which really doesn't make sense here.
或是 Equal Heights 等高，但这两个都不合适
Or you can pin this vertical spacing to the top
所以我们选这个 Vertical Spacing to Top
layout guide.
Layout Guide
So I basically pinned it to the top. And same thing here,
也就是固定离顶部一定距离
I can go to the left and pin the leading space. And
同理，左边选 Leading Space 来固定
I can go to the right and pin, pin the trailing space. And
右边选 Trailing Space
I can go to the bottom and sorry, yes, the bottom, and
底部也是这样
pin the bottom space, the vertical space in the bottom.
选 Vertical Spacing to Bottom Layout Guide
Now we're just seeing pinning it to edges, but you can use
我们只是固定它四周到屏幕的距离

English: 
And now I'm gonna do the magic  
to hook it to an edge. And      
I do that with the Ctrl key,    
just like we did dragging into  
the code. But here, I'm gonna   
drag from this selected thing.  
Make sure the whole             
thing is selected. And          
Ctrl+Drag up to the top.        
So we can tie it to the top.    
And when you let go,            
it's gonna say,                 
what relationship do you want   
between this big box and        
the top? And, and really it's   
talking about the outer edge.   
And you can try and             
make them the same width, or    
the same height, which really   
doesn't make sense here.        
Or you can pin this             
vertical spacing to the top     
layout guide.                   
So I basically pinned it to     
the top. And same thing here,   
I can go to the left and        
pin the leading space. And      
I can go to the right and pin,  
pin the trailing space. And     
I can go to the bottom and      
sorry, yes, the bottom, and     
pin the bottom space, the       
vertical space in the bottom.   
Now we're just seeing pinning   
it to edges, but you can use    

Chinese: 
this mechanism to Ctrl+Drag between any two elements and
但还可以按 control 从一个元素拖拽到另一个
say, make these two the same width, line up the left edges,
让它们等宽，对齐左边界
line up the tops.
对齐顶部等等
You see what I'm saying? And
懂我的意思吧？
once you have that ability to have all your items have rules
当你把所有的内容都约束起来
of their relation to each other, now you can imagine how
定义了相互之间的关系，这个时候
you can rotate the whole thing and have it all look good,
在旋转之后保持美观不再是问题
because it's following rules about what to do.
因为它们可以根据规则调整
Now one thing about these two pins, okay, those I pinned to
不过要注意这两个约束
where I wanted them. But these two pins are not what I want.
它们确实是固定到了正确的地方，但和我想的有出入
It's pinning it this far from the edge. So
它到边上的距离太远了
how do I fix that? You can actually double-click on that.
怎么解决这个问题？你可以双击
If you double-click on this I-beam,
如果你双击这个看起来像 I 的线段
it says, yes, I'm pinning this 113 points from the edge. And
Xcode 告诉你，右边距是 113 点
you can go up here and try to pick Standard Value.
点击这边可以选 Standard Value，标准值
But that's grayed out, so we're gonna use 0.
但是因为是灰色的不能用，所以这里就填 0
So you almost want either Standard Value, if available,
所以一般如果有标准值就用
or 0. So in this case,
没有就用 0。拿这个情况举例
0 means 0 points from this layout guide edge, okay? And
0 是指到右边布局边界线的距离为 0 点
same thing with this one down here, I'm gonna double-click.
同理，下面也这样处理。双击
By the way, we can also see these things, okay?
其实我们还可以这样修改

English: 
this mechanism to Ctrl+Drag     
between any two elements and    
say, make these two the same    
width, line up the left edges,  
line up the tops.               
You see what I'm saying? And    
once you have that ability to   
have all your items have rules  
of their relation to each       
other, now you can imagine how  
you can rotate the whole thing  
and have it all look good,      
because it's following          
rules about what to do.         
Now one thing about these two   
pins, okay, those I pinned to   
where I wanted them. But these  
two pins are not what I want.   
It's pinning it this            
far from the edge. So           
how do I fix that? You can      
actually double-click on that.  
If you double-click             
on this I-beam,                 
it says, yes, I'm pinning this  
113 points from the edge. And   
you can go up here and          
try to pick Standard Value.     
But that's grayed out,          
so we're gonna use 0.           
So you almost want either       
Standard Value, if available,   
or 0. So in this case,          
0 means 0 points from this      
layout guide edge, okay? And    
same thing with this one down   
here, I'm gonna double-click.   
By the way, we can also         
see these things, okay?         

Chinese: 
If we select this, we can go over to the size inspector.
当我们选中了之后，看这个属性检查器
You can see all these things down at the bottom here,
这些约束都能在下面找到
okay, all these connections to the edges, right?
这些和边界的关系
See this one's 301. So I'm gonna double-click on this
所以我们现在是固定底边距为 301。我还是双击
I-beam, and here, standard value is available. So I'm
这条线段，然后这里可以选 Use Standard Value
gonna pick the standard value, okay? And it puts it there.
那就用这个标准值，把下面固定好
Now so they tied it to the bottom and stretched this out.
现在固定到底部之后，把整个都拉伸了
Now it didn't quite stretch out the way we wanted here,
但并不是以我们想要的方式
right? So some of these, rows in the inside,
这应该是我们 StackView
we didn't get the right attributes on.
有的属性没设置好
So let's go back and check them all. We got fill equally,
让我们再都检查一遍
horizontally, and all of them, yeah? We do, right?
我们都设置为了 Fill Equally
And how about this? Here I'm gonna use the Ctrl+Click.
那稍微再大些的这个呢？我按 control 再点击
We'll pick this stack view. See this one, okay,
选中这个 StackView
this is this inner one, wants to also be filled equally,
就是里面的这个，这个也要是 Fill Equally
right? We want all these rows, not including this top guy,
我们希望除了 display 之外
but all these inner interior rows to be the same.
每一行都等高
So I'm gonna go fill equally here to fix that,
所以这里选 Fill Equally 来解决

English: 
If we select this, we can go    
over to the size inspector.     
You can see all these things    
down at the bottom here,        
okay, all these connections     
to the edges, right?            
See this one's 301. So          
I'm gonna double-click on this  
I-beam, and here, standard      
value is available. So I'm      
gonna pick the standard value,  
okay? And it puts it there.     
Now so they tied it to the      
bottom and stretched this out.  
Now it didn't quite stretch     
out the way we wanted here,     
right? So some of these,        
rows in the inside,             
we didn't get the right         
attributes on.                  
So let's go back and check      
them all. We got fill equally,  
horizontally, and all of them,  
yeah? We do, right?             
And how about this? Here I'm    
gonna use the Ctrl+Click.       
We'll pick this stack view.     
See this one, okay,             
this is this inner one, wants   
to also be filled equally,      
right? We want all these rows,  
not including this top guy,     
but all these inner interior    
rows to be the same.            
So I'm gonna go fill            
equally here to fix that,       

Chinese: 
okay? So now I have this thing that can stretch out,
现在我这个就可以随便伸缩了
because it's got these stacks that have rules about
因为这些 StackView 规定了如何填充
how to fill. And then I've hooked them to the edges, so
我也自己把它们关联到了边界
that now when I switch orientations, it adjusts,
现在我换到横屏的时候，它就会自动调整了
even if I go to a smaller device, okay? Or
甚至我用一个小一些的设备都没问题
a large device. Now one thing that's
也可以是大一点的设备
interesting about the very smallest device, an iPhone 4,
不过有趣的是，针对最小的 iPhone 4
is that in this orientation, it can't fit everything. You
在横屏的时候，并不能够装下所有的内容
see that? The display is just, it can't fit it. So this is
看到了吗？display 因为放不下就消失了
why it's great to be able to see this in Interface Builder,
所以在设计的时候就能看到这些问题很有帮助
cuz we can go back here and pick a smaller font, for
因为我们能及时挑选一个小一些的字号
example. We can even, you know, have our font be
或者是定义一个变量存储字体
variable, but there's no way to have the font automatically
不过我们并没有自动缩放字号的功能
squinched down, unfortunately. There's no autoshrink for
很遗憾地，按钮并没有自动缩小
buttons like there is for labels. So sorry about that.
不像是文本框，这没办法
But we would pick a smaller font that would work upon all
但是我们可以挑一个比较小的字号
of our platforms maybe, okay? All right, so we have this.
保证能够适应所有的设备

English: 
okay? So now I have this        
thing that can stretch out,     
because it's got these          
stacks that have rules about    
how to fill. And then I've      
hooked them to the edges, so    
that now when I switch          
orientations, it adjusts,       
even if I go to a smaller       
device, okay? Or                
a large device.                 
Now one thing that's            
interesting about the very      
smallest device, an iPhone 4,   
is that in this orientation,    
it can't fit everything. You    
see that? The display is just,  
it can't fit it. So this is     
why it's great to be able to    
see this in Interface Builder,  
cuz we can go back here and     
pick a smaller font, for        
example. We can even,           
you know, have our font be      
variable, but there's no way    
to have the font automatically  
squinched down, unfortunately.  
There's no autoshrink for       
buttons like there is for       
labels. So sorry about that.    
But we would pick a smaller     
font that would work upon all   
of our platforms maybe, okay?   
All right, so we have this.     

English: 
And, of course, now if we run   
it in the simulator, we can     
rotate it in the simulator as   
well and see it working there.  
And if we had a device, we      
could run it on our device and  
do it there. So here we go.     
Here's our iPhone 7.            
7 times 9 equals.               
It's still working.             
Square root, that's good.       
And when we rotate,             
by the way, I'm gonna           
rotate using Command key.       
Okay, Command left and right    
arrows, you'll see it down in   
the lower left corner here,     
but Command Rotate.             
See that? Okay, so you can      
see we had to do very little    
to make this thing adapt. And   
this is a fairly simple UI,     
a lot of rectangles.            
More complicated UI,            
we'd do a little bit more. And  
in about week five, four or     
five, I'll go into detail       
about how we build these, even  
for complicated UIs how we      
build these rotatable things,   
etc. Okay, so that's it.        
Your homework                   
is basically to reproduce       
what I did in these first two   
lectures and                    
then add a couple of things.    
Add a little label up there,    
add some buttons, change some   
colors, that kind of business,  
pretty straightforward.         
Make it work with               
floating point inputs and       

Chinese: 
And, of course, now if we run it in the simulator, we can
现在我们再在模拟器里运行
rotate it in the simulator as well and see it working there.
旋转之后一样也是正常的
And if we had a device, we could run it on our device and
如果你有自己的设备的话，也可以用自己的试试
do it there. So here we go. Here's our iPhone 7.
好，iPhone 7 出来了
7 times 9 equals. It's still working.
7 乘 9 等于，没问题
Square root, that's good. And when we rotate,
平方根，也正确。现在旋转
by the way, I'm gonna rotate using Command key.
不过这次我用快捷键
Okay, Command left and right arrows, you'll see it down in
command + 左箭头或右箭头
the lower left corner here, but Command Rotate.
具体我按了哪个你可以在左下角看到
See that? Okay, so you can see we had to do very little
看到了吗？我们并没有做太多的修改
to make this thing adapt. And this is a fairly simple UI,
就实现了自适应的 UI。当然我们这个算简单的
a lot of rectangles. More complicated UI,
全部都是长方形。对于复杂一些的
we'd do a little bit more. And in about week five, four or
自然需要做更多的处理。在大约第四、五周的时候
five, I'll go into detail about how we build these, even
我们还会继续讲解
for complicated UIs how we build these rotatable things,
如何让复杂的界面处理好屏幕旋转
etc. Okay, so that's it. Your homework
好，今天的课就到这里
is basically to reproduce what I did in these first two
你们的作业就是完成我们这两节课完成的内容
lectures and then add a couple of things.
然后添加一些其他的功能
Add a little label up there, add some buttons, change some
添加一个额外的文本框，添加一些按钮
colors, that kind of business, pretty straightforward.
改一些颜色，这些小东西，都算简单的
Make it work with floating point inputs and
处理小数的输入

Chinese: 
that's due next Wednesday. I'm here if you have questions,
作业下周三交，有问题的同学下课可以问我
and I'll see you then. >> For more,
下周三见
please visit us at stanford.edu.
>> 更多课程详见 stanford.edu

English: 
that's due next Wednesday. I'm  
here if you have questions,     
and I'll see you then.          
>> For more,                    
please visit us                 
at stanford.edu.                
