本字幕由志愿者义务贡献，采用许可协议
知识共享 署名-非商业性使用-相同方式共享 3.0 美国
Stanford University. >> Okay, well welcome then,
斯坦福大学 >> 欢迎参加
to Stanford CS193P. This is Developing Applications for
斯坦福 CS193P，iOS 应用程序开发
iOS. Hopefully you're in the right place.
希望你们走对了教室
This is fall quarter of 2017. And I'm gonna breeze through
现在是 2017 年秋季学期。我先简单
a few slides here. And then I'm gonna sit down and
讲几页幻灯片，然后坐下来
do a nice involved demo just to show you what it's like
给你们写个程序演示一下
developing apps for iOS. That's the best way to learn,
开发 iOS 程序是什么样的。这是最好的学习方法
it's for me to show you how to do it. So
让我来给你展示怎么做
this will be what I'm gonna talk about briefly first.
现在我先简单讲讲
So what are you gonna learn in this course?
你在这节课会学到什么？
Of course you're gonna learn how to build cool apps.
当然你会学习如何编写很酷的程序
iOS apps are cool. Why are they cool?
iOS 程序都很酷，为什么呢？
Well, they're cool because they live in your pocket, you
因为他们“活”在你的口袋里（的手机上）
can show them to your friends right there, also incredibly
你随时可以展示给你的朋友们看
easy to sell and market your apps online because you have
同时还能很轻松地在在线商店销售，因为
the App Store. And there's a very vibrant community that's
有 App Store。那可是个很活跃的大平台
because Apple is always doing cool new things like virtual
因为苹果公司总是在做很酷的事情
reality and machine learning and all these things.
比如今年的虚拟（增强）现实和机器学习
And there are millions of apps on the app store, so there's
同时 App Store 里有成千上万的程序
a lot of people doing this stuff. But you're also gonna
很多人都在做 iOS 开发。同时你会
learn in this class a little bit of real life
在这节课中学习到实际运用
Object-Oriented Programming.
面向对象编程
You all are taking classes, networking and databases and
你在其他计算机课程中学习到了网络，数据库
graphics, your other CS classes. And here we're gonna
图形等，在这里你将会
do all those things in a real life platform.
在 iOS 平台上实际运用这些
Because over the weeks we are going to do all of those
因为这几周的时间我们会
computer science things for real. And especially
实际运用这些计算机相关的知识
Object-Oriented Programming, cuz iOS is completely and
特别是面向对象编程，因为 iOS
utterly object-oriented. You cannot develop for
是完全面向对象的。除非你掌握了面向对象编程
iOS without being serious object oriented programmer.
否则你不可能开发 iOS 程序
And that brings me to my prerequisite for this course,
正好我可以讲讲上这门课的前提
which is Object-Oriented Programming. You have to be
其中之一是面向对象编程
comfortable with Object-Oriented Programming.
你必须要适应面向对象编程
Definitely CS106 A and B and hopefully CS108,
必须要上了 CS106 A/B，最好是 CS108
which is Object-Oriented Programming here at
这些是斯坦福开设的面向对象编程课程
Stanford. And the other thing you gotta to be comfortable
其他你需要能适应的是
with is writing a lot of code. All your homework in this
写很多代码。这节课所有的作业
class, there's a little bit of reading the first few weeks
前几周还会有些关于我们
about the language that we're gonna develop in.
开发要用的语言的阅读作业
But mostly it's just programming, programming and
但其他的大部分都是写程序，写程序
more programming. So if you're not comfortable writing a lot
写更多的程序。所以如果你不能适应天天敲代码
of code then this class, you might wanna wait until
那你应该等等再上这节课
you've taken some other classes that ask you to
你可以先上其他要写很多代码的课
write a lot of code before you dive in here.
然后再来上这节课
So what's in iOS? What am I gonna be teaching you?
好，那么 iOS 里面都有些什么？我要教你什么？
I've divided it here into four layers.
我们可以把 iOS 分成四层
The bottom layer is near the hardware, and
最下面的一层最接近硬件
the top layer is near the user. So at that bottom layer,
最上面一层最接近用户。所以最底下的一层
you might be surprised to find out that iOS is Unix.
你会很惊奇的发现 iOS 其实是 Unix 系统
It's a BSD variant of Unix. And so all of the stuff
BSD 版本 的 Unix。所以所有的这些
that's going on down there is all happening in C basically.
在这里运行的程序大多都是用 C 语言编写的
Unix is mostly written in C, most of that stuff is in C.
Unix 几乎是用 C 语言写的，大部分都是
I'm not gonna teach you anything at this layer.
我不会教你这个层面的内容
This is an object-oriented class,
这节课是教面向对象的
everything we do will be object-oriented.
我们要写的程序也都是面向对象的
You will not see me teaching you anything down there,
你不会看到我教你这部分的内容
The next layer up is called the Core Services layer.
在那一层之上是 Core Services 层
all right?
是吧？
This is an object-oriented layer on top of those lower
这一层是对下面那层服务的面向对象封装
services. This I will be teaching you. So if we wanna
我会教你这一层的内容。如果我们想要
do things like find out where the phone is on the planet or
做比如这个手机在地球上的什么位置
find out its orientation or access some files in the file
或者设备的方向，或者访问文件系统
system, we're gonna be using this layer right here and I'll
我们就需要用到这层，我会
be teaching you all about this layer. Core Services layer.
教你使用这一层，Core Services 层所有的功能
The next layer up, this is kind of not a strict layering,
再上面一层，这不是很严谨的分层
but is the Media layer. Don't forget that your iPhone
但这层是媒体（Media）处理层，不要忘了你的 iPhone
is essentially, originally an iPod with a phone in it. So
原本是可以打电话的 iPod
it's got all kinds of media, video, audio,
所以它能够对各种媒体，比如视频，音频
many different kinds, images, all this stuff. And
以及众多格式的图片等进行处理
unfortunately this is a layer I'd love to teach you but
虽然我很想教你们这些内容，但不幸的是
I have to cut something, so I'm not gonna talk much about
我必须要消减一些内容，所以我不会讲太多
this layer, unfortunately. So I know some of you might be
这层的内容，真的很不幸。我知道你们中的有些人
wanting to write a cool game that has 3D sound with TIE
会想要编很酷的程序，有 3D 环绕声伴随
fighters ripping around from the back of you to the front.
（星球大战里的）钛战机从后面飞到前面
And that's all possible, and quite straightforward to do,
这些都是可能的，而且实现很简单
but in ten weeks I have to pick what I'm gonna teach you,
但是我必须要选择十周的时间我应该教你们什么
and so I'm gonna focus on Core Services. And then this layer,
所以我会更加注重 Core Services 层的内容。最后一层
which is Cocoa Touch. So Cocoa Touch is the UI layer of iOS.
 也就是 Cocoa Touch 层，它负责 iOS 的用户界面
This is where the buttons and
这一层是比如按钮
the sliders, all those things are in. And
滑杆（Slider）等控件定义的地方
there's also, really powerful objects here, like the Map Kit
这一层还有其他强大的对象，比如 Map Kit
has a single object that you can just drop in your app
有个对象，你可以直接把它加到程序里
that gives you pretty much the entire functionality of
然后你就有了整个
the map's app inside a rectangle, inside your window.
地图程序的功能，呈现在窗口里的某个矩形里
So, you're talking about a wide variety of UI stuff here
所以你会遇到各种 UI 控件
and I'm gonna try and cover as much of this as I can. So
我会尽量多地讲解这一层的内容
that's what you're gonna learn in this class.
这就是你会在这节课中学习到的内容
The platform we're gonna develop on is Xcode 9, so
我们的开发平台是 Xcode 9
you're all gonna need to download Xcode 9,
你需要从 Mac App Store 免费下载 Xcode 9
it's free and it only runs on your Mac.
（千万别从百度云等第三方下载）注意只支持 Mac
And, there's this other little app, Instruments, but it's
同时还有一个程序，Instruments
really kind of just an add-on to Xcode 9. We're gonna do
Xcode 附带的程序，更像是插件。我们会
everything in Xcode 9, source code, editing, debugging,
在 Xcode 9 中做所有的事情，写代码，编辑，调试
all that stuff is gonna happen in Xcode 9. You're also gonna
这些都是在 Xcode 9 中完成。你同时还要
have to learn a new language. iOS has two languages you can
学习一门新的语言。开发 iOS 有两种语言可以选择
develop in, Objective-C and Swift.
一个是 Objective-C，一个是 Swift
Swift is the newer one, that's the one I'm gonna teach you.
Swift 是更新的一个，同时也是我会教你的语言
Everything you learn though in Swift, all about iOS,
所有你用 Swift 学到的关于 iOS 的知识
will apply if you later wanna go learn Objective-C and
如果你之后决定学 Objective-C 都是可以用到的
work for a company that is still writing in Objective-C,
也可以用在还在使用 Objective-C 的公司的程序里
which is perfectly valid language to write in.
因为 Objective-C 也是可以独当一面的语言
But Swift kind of a cool new language,
但是 Swift 是更潮的新语言
I think you're really, really gonna like it.
我相信你会喜欢上它的
If you're a serious Computer Scientist another language is
如果你是个认真的程序员的话，学习一门新语言
like big yawn whatever. Just tell me what the syntax is,
你听了应该觉得这很简单，你告诉我语法
tell me what they key fundamental mechanisms for
告诉我那些基本的，关键的
designing with it are, and I'll learn it.
程序设计方法，然后我就去把它掌握了
So, if you don't have that attitude towards languages,
如果你不能这样接受学习新语言
you're gonna be kind of having trouble out in the real world
你在现实生活中就会有麻烦了
being a programmer. And then of course,
不容易当好程序员。当然
there's millions of what we call Frameworks in iOS.
iOS 里有很多被称为框架（Frameworks）的东西
Frameworks are just collections of objects.
框架就是对象的集合
Like the biggest one is UIKit, that's where buttons, and
最大的一个是 UIKit，里面有按钮
sliders, and all that stuff is. Foundation is another
滑杆等那些控件。Foundation 框架
big one. That's where a lot of that core services stuff I was
也不小，里面主要是 Core Services 层的内容
talking about is. But there's the Map Kit, Core Motion,
但同时还有 Map Kit、Core Motion
Core Data, Object Orient, Database, all kinds of them.
Core Data（面向对象数据库）等等框架
And I'll try and get to as many of them as I can. And
我会尝试讲到尽量多的框架
last but definitely not least, there is a Design Strategy for
最后一个，同样重要的，设计模式
building iOS apps that you have to use.
用来开发 iOS 程序必须要用的
This is not like an optional, here's a good idea, why don't
这并不是一个选项，或者某个很好的点子
you design this way? You must design this way. It's called
建议你这样设计。不，你必须这样设计。它叫做
MVC, Model View Controller. How many people have,
MVC，即 Model（模型）-View（视图）-Controller（控制器）
some experience doing MVC in any other? Okay, it's not so
这里有多少人有使用过 MVC？好吧
many this quarter. Usually I get half the people but
这学期没有那么多人。通常会有一半的人
I'll be teaching all about MVC.
但我会教你们 MVC
The start of lecture on Wednesday is gonna be a full
星期三一开始会详尽地
coverage of MVC. What it is, how it works, all that stuff,
讲 MVC，包括它是什么，怎么工作的，等等
all right? So now, I'm gonna dive right into a big demo
好吧？现在，我会开始一个大型的示例程序
that's the best way to learn how to do iOS development is
最好的学习 iOS 开发的方法
with a demo. Seeing it happen, we're gonna build
就是看实例。看着如何做的，我们会
an application from scratch. This slide right here,
从头开始写一个程序。这页幻灯片
is a slide for you to look at later, and
是给你们之后看的
see, did I learn all these things, because I should have
对照检查下我是否学会了这些，因为我
learned them today. This is not a slide to read now.
在今天的课上学了。你们不用现在看
Since I'm not gonna get back to the slides,
因为我不会再回到幻灯片
let me just say what's coming up real quick. You are gonna
我快速地讲讲之后的安排
have a reading assignment that goes out today.
我今天会布置给你们阅读作业
It's basically starting to read the manual on
要求基本就是开始阅读 Swift 的说明书
Swift. So you can learn this new language. It'll be all
以此来学习这门新语言
spreaded out over three maybe four weeks, so you don't have
我会给你们大概三到四周读完整本书
too much reading all at once. But
我不会一次要求你读太多
those reading assignments are gonna be in addition to
但是不止是阅读作业
programming assignments. The reading assignments are going
你们还会有编程作业。阅读作业是周一布置
to go out on Monday, they come back on Monday,
下周一交
they're due the next Monday. And
阅读作业是下周一交
then the program assignments go out on Wednesday and
编程作业是星期三布置
then they're due the next Wednesday generally.
一般来说会是下周三交
Okay, at least we'll start the quarter that way.
好，至少我们一开始是这样安排的
On Friday, we have an optional section,
星期五的课是选修课
it means optional that you don't have to go there.
你可上可不上
The topics we're gonna cover are kind of additional, but
讲的主题也会是额外的内容
this Friday is one is a big one, it's tips and
但这周五的很重要，是关于
tricks of Xcode, including how to use the debugger.
Xcode 使用的提示和技巧，包括如何使用调试器
So if you've never used the debugger in Xcode,
如果你从没有使用过 Xcode 的调试器
this is a good one to go to, so
我推荐你来参加
you can see how to use the debugger for your problem.
你能见识到如何用调试器解决问题
If not, you know, it's a debugger, if you used other
如果你不想来的话，嘛，就是个调试器，如果用过了其他的
debuggers, you could probably figure it out, but anyway, it
调试器的话，你应该能够自己琢磨出来
says right there that it's in Hewlett 205, but I don't think
这里写着会在 Hewlett 205，但我并不觉得
there's such a room. I think it might be in Hewlett 105.
有这么个教室。我认为应该在 Hewlett 105
I don't know, watch Piazza and we'll tell you where it is.
我记不清了，注意看 Piazza 上我告诉你们的地址
But it is gonna be 11:30 to 12:20. And so next week we'll
但时间是 11:30 到 12:20。下一周
talk more about Swift and then launch into all of iOS,
我们会更多的讲 Swift，然后就完全是 iOS 了
all right? So let's jump right into the demo here.
好吧？我现在就开始演示写程序
And I apologize in advance for going fast on this demo,
我这里提前道歉，这个演示我会过得很快
because we have a lot to cover, and
因为我们要讲的实在是太多了
you're gonna find that in this course, in general,
而对于这门课来说，你会发现这是普遍现象
I tend to go pretty quick, cuz I wanna teach you as much of
我一般讲得很快，因为我想要教你们更多的内容
this stuff as I possibly can. All right,
能教多少教多少。好
Xcode. Here's Xcode. I went to the Mac App Store.
打开 Xcode。这就是 Xcode，去 Mac App Store
I searched Xcode, I found it. I downloaded it.
搜索 Xcode，找到并下载
It was free, it doesn't cost me a dime to develop for
Xcode 是免费的，不用花一分钱就可以开发
iOS. When you launch Xcode for the first time,
iOS 程序。当你打开 Xcode 的时候
you're gonna get this thing right here. So
你就会看到这个欢迎界面
we need to build an app. Now, I decided to show you the app
我们需要构建一个程序。我准备先给你们展示
that I'm gonna build here in real life. So you see these
我这个程序在现实生活中是怎么玩的。你看到这些
cards that I've very artfully taped up here? These cards
卡片，就是我粘在这里的这些？这些卡片
are going to let me play a game called Concentration.
可以用来玩一个叫做翻牌（Concentration）的游戏
How many people have heard of the game Concentration?
有多少人听说过翻牌这个游戏？
Not too many. Okay, so Concentration is just a card
不是很多。好吧，翻牌这个游戏就是个卡牌游戏
game. Behind these cards that are all face down,
这些正面朝下的卡片上
there are some pictures, and the goal is for
都有某张图片，我们的目标是
you to match the pictures up. So there's 12 cards,
找到相同的图片。这里有 12 张卡
6 pairs of pictures, so I get to pick two cards at a time,
6 对图片。所以我一次挑选两张
and if they match, I win, and
如果是相同的，我就赢了，然后
the cards go away. If they don't match,
牌放一边。如果不一样
I have to turn them back down and pick two other cards, and
我就需要把它们放回原处，然后重新选两张
it's called Concentration cuz I have to concentrate on
这个游戏叫做 Concentration 是因为要集中注意力
the ones that didn't match, so that later I can go back and
关注那些没有配对上的，然后之后来
match them. So, let's just flip some cards over here.
配对。让我们翻开这里的某些卡片
I'm gonna start with this one right here.
我先从这个开始
I really don't know what's behind there, but let's see.
我并不知道后面印的是什么图案
Okay, this one is a pair of purple bats.
好，这个是一对紫色的蝙蝠
So now I'm trying to find another pair of purple bats,
我们需要找到另一对紫色蝙蝠
let's try right here. I found them right away, okay.
让我们试试这里的这个。啊，马上就找到了
So this is a match, I get some points.
所以这是相匹配的，我就得分了
These come off the board. So now I'm searching for
然后就拿下来。现在我要找到更多能配对的
more matches. All right, let's try this one right here. It's
让我们来试试这里的这个
a ghost. I got the ghost right there. Let's try this one.
这是个鬼。我这里有个鬼，让我试试这个
No, no match. That looks like a Rorschach thing, but
啊，不一样，那看起来像罗夏墨迹测验
it's a witch. Turns out that's a witch on her broom,
但其实是女巫，骑着扫把的女巫
if you can see right there. So, I don't get any points for
如果你能看到的话。所以我没有得分
this and I have to turn these back down and pick two other
然后需要放回去，然后另选两张
cards. All right, so I'll turn these down.
好，让我们翻回去
Hopefully you guys are concentrating, and
希望你们注意了
you can remember what these things are. I'm gonna try this
然后能记住这些都在哪里。让我试试这个
one. It's a cat, kind of a cute cat right there, and
是只猫，可爱的猫
let's pick another one, how about this one. A pumpkin!
让我们再选另外一张，这个怎样？是个南瓜！
Okay, well, in some ways, this is bad,
某种意义上说，这很不好
because we have another non match,
因为我们又没有配上对
but it's kind of good in that supposedly,
但同时也有好处
if we we're concentrating we know where four cards are. So
如果我们注意了，我们就知道这四张卡在哪里
turn these back down. Pick two new ones, and
然后我们又翻回去。选两张新卡
I'm gonna pick cards that I haven't seen before,
我要挑还没有翻过的卡片
because I already know where these cards are.
因为我已经知道这些是什么了
All right, that doesn't fall down.
好，这个没掉下来
All right, how about this one. This one is, The witch,
让我们选这个。这个是女巫
the witch! Okay, so now if I was concentrating,
女巫！如果我注意了的话
I remember where the witch was, now where was it? Was it,
我会记得另一个女巫在哪里，在哪里呢？
I think, was it this one? Yeah? Witch, yes, okay!
我觉得是这个？是的！另一个女巫！
So we match these, and these come off the board, and this
我们找到了配对的，就把这对拿开
just continues, and obviously the fewer things you choose,
然后继续重复。显然你应该尽量少挑选
okay, the fewer times that you pick, like here is a cat.
你应该尽量减少挑选的次数。比如这是个猫
Where's that cat? I think it's down here.
另一只在哪里？我记得在下面这里
No, that's not a cat. Now this kind of a mismatch
不，那不是一只猫。像这种没配对的
I should be probably get a big penalty for,
我应该得到严重的处罚
because the cat I've seen before, it's right here.
因为我之前看到猫就在这里
So I should have matched it, and I didn't,
我应该是能配对的，但是我并没有
I wasn't concentrating. So this is the game we're gonna
因为我注意力并没有集中，所以这就是我们要
build an app to do. All right, make sense? Simple game.
编的游戏。这个游戏简单吧？
All right back to Xcode right here. Now this Xcode portal,
我们回到 Xcode。这个 Xcode 的首页
the splash screen that pops up here.
显示的是这个启动页
It has all the apps that you've been working on all
右边这里会显示这学期你所有的程序
quarter. Right here, and then it lets you create a new app
就在这里。你还可以新建一个程序
over here where it says create a new Xcode project. So,
在写着 Create a new Xcode project 这里
we're gonna create a new Xcode project.
我们要新建一个 Xcode 项目
I just click that button. When you create a project,
于是我们点这个按钮。当你新建一个项目的时候
it asks you what kind of project do you wanna build?
它会问你是什么样的项目？
And we wanna build an iOS app, you see up here at the top.
我们要编的是 iOS 程序，就是最上面这里选的
We could build a watch app, or an Apple TV app,
我们还可以编写 Apple Watch，Apple TV 程序等
but we're building an iOS app, and
但我们这节课是编写 iOS 程序
this is saying what kind of iOS app would you like?
接着又问你是什么样的 iOS 程序？
So here's a game, augmented reality. We're always gonna
可以是 Game（游戏），Augmented Reality（增强现实）
pick this one in the upper left corner, single view app,
但我们要选的是左上角这个，Single View App
because it's the simplest starting template, and I wanna
因为单一视图程序是最简单的模版
teach you how to write the code to do all those
我会教你如何编写其他的这些模版
other ones. I don't want you just click a template, and
我不希望你只是点击一个模版
it just shows you the infrastructure for a game, or
然后就有了整个游戏的基础结构
whatever. I wanna show you how to do that.
或者其他什么的；我想要教你如何实现那些
So we're always gonna pick single view app.
所以我们总是选 Single View App
When we pick the kind of app we want it's gonna ask us some
当我们选了程序的类型之后，Xcode 会问
questions like what do you wanna call this app?
你想要把这个程序叫做什么
Well this game is called Concentration, so I'm gonna
这个游戏叫做 Concentration，我就叫
say Concentration. The next one down here is Team.
这个程序 Concentration。下一个是 Team
That's the development team working on it. That's you. Now
这个是你工作的开发团队，也就是你自己
when you are on it it's gonna say Add Team or Make Team right
你的 Xcode 会显示 Add Team 或是 Make Team
there. To me, it knows it's me, and when you do that,
但是我的 Xcode 已经知道我是谁了。对你而言
all you're gonna need to create a development team is
要创建一个开发团队，你只需要
an Apple ID. You don't have to pay any money.
一个 Apple ID。这不需要交钱
Any Apple ID will do, go through the process.
任何 Apple ID 都可以，跟着步骤走
You'll create a development team. Next,
创建了开发团队之后
is this Organization Name. That can be anything you want.
是 Organization Name。这组织名称随便填
It just shows up in the copyright in your Swift files,
它会显示在 Swift 文件的版权声明里
all right? But this one, very important that this be
但 Organization Identifier 很重要
uniquely identifying you. So a real easy way to
这个是你独一无二的标识符。最简单的方法
do that if you're a Stanford student is
如果你是个斯坦福的学生，就用
edu.stanford.cs193p, your SUNet id.
edu.stanford.cs193p.你的SUNetID
Instead of lecture there, put your SUNet ID.
不填 lecture，而是你的 SUNet ID
That's clearly gonna identify you. If you're not a Stanford
那就可以识别出是你了。如果你不是斯坦福
student, you have to figure it out on your own, and
学生，那你需要自己想一个（惯例是网站域名的反写）
then the language I told you about, the two languages,
最后 Language，我之前说的那两个
we're gonna do all our development in Swift. You can
我们的开发全部会用 Swift。你还可以
mix Swift and Objective-C even in the same application.
在同一个程序里混用 Swift 和 Objective-C
They're very interoperable. Swift was designed fully with
它们是能协同工作的。在设计 Swift 时候充分
Objective-C in mind, so it's not a problem. So we'll always
考虑了 Objective-C，所以这不会是个问题。所以我们总是
pick Swift here, and we're not gonna do any of these
在这里选择 Swift 语言。我们不会用到
things down here in the first two weeks,
下面的这些，至少前两周不会
but we will eventually get it, object-oriented databases, and
但我们最终会讲到面向对象数据库
testing, we'll eventually do that stuff.
和测试这些，都是会讲的
So I'm gonna click next.
接着点 Next
Now it's asking me where do you wanna store your project?
现在问我要把项目放在哪里
I strongly recommend you put it in your home directory,
我建议放在你的用户根目录下的
in a folder called Developer, that's the kind of a canonical
Developer 文件夹里（~/Developer）。这像是个钦定的
place that people put their projects.
人们经常放他们项目的地方
All your projects will collect here, okay, concentration, and
你所有的项目都会在这里，今天是 Concentration
then the other ones we're gonna do later in the quarter.
然后是这学期之后的项目
This source control,
这个 source control
we'll talk about that later in the quarter as well, but
源码（版本）管理我们也会在之后讨论，但是
we're not doing that for the first week. Okay here it is,
我们在第一周不会做这件事
your first iOS app. Now what we're seeing in the middle of
这里是你的第一个 iOS 应用。现在你正在看 Xcode 的中间
Xcode, how many people have done something in Xcode
有多少人之前用 Xcode 做过一些东西
before? Okay, so about half of you, so that's pretty common.
好吧，大约有一半的人，这是很常见的
So you know that in Xcode, this middle area is your main
所以你知道在 Xcode 中，中间的部分是你的主要编辑器
editor, and right, we're seeing right now,
右边你正看到的
in this main area, is our project settings.
在这个主要区域里，是我们的项目设置
We answered some of these in those previous little things
我们之前回答了它们中的一小部分的功能
that came up, and the reason it's showing our project
它之所以显示我们的项目设置
settings is because on the left here in this blue area
是因为在左侧的蓝色区域
we have the project selected, see the dark blue selection at
我们选中了项目，就是在上方的深蓝色选中的部分
the top. That's the project selected, and
那就是我们选中的项目
this whole blue area on the left is called the navigator,
左侧这整片蓝色区域叫做导航栏（navigator)
and the navigator let you navigate through your project,
导航栏让你巡览整个项目
and in this particular tab it's showing me the files in
这个选项卡展示了我的项目中的文件
my project. I have six files right here,
我一共有六个文件
they were given to me when I chose that template, the single
当我选择这个模板我就有了它们
view template, but I can also now navigate by searching,
即单视图模板，但是我仍能通过搜索导航
right here. If I'm debugging I can navigate through my break
如果我想调试，我可以巡览我的断点
points, etc. So you'll get real familiar with using this
所以你将马上熟悉
blue thing right here,
使用这个蓝色区域
and you can say how much space you want it to have to
你还能决定你需要多大的空间来导航
navigate through your application.
你的应用
Now on the right hand side, this over here,
在右手边的区域
you can actually see a little area that has a top and
你可以看到一个有上方和底部的
a bottom. This is called the utilities pane, and
小区域，它叫做 Utilities pane (工具栏)
I'm gonna show you all about that in five minutes.
我会在五分钟内展示它的所有
So I'm gonna hide it right now.
现在我会先把它隐藏起来
You see this button in the very upper right.
你可以看到在最右边的这个按钮
That hides that, and this one hides the navigator. So if you
它隐藏工具区域，这个隐藏导航栏
wanna give more space to your main window, you can do that.
如果你想要给你的主要窗口更多空间，你可以这样做
There's another button here, you see that one?
这里有另一个按钮，你看到了么？
That hides your debugger and console window.
它隐藏你的 debugger（调试器）和 console（控制台）窗口
So this is the debugger right here where you're looking, I
这个就是调试器
think, going on your debugger, and this is the console.
这个是控制台
Now, the console is just a place where there's a function
在控制台，我们可以打印
in Swift where we can print text out there.
一个 Swift 函数的文本
It's really great for lightweight debugging.
它是非常好的轻量调试的方式
We're just printing out what's going on. Inside my app.
我们就是打印出应用里正在进行的东西
And that's what I'm going to do today,
这就是我今天要做的事情
I'm not going to show you the debugger today, that's for
今天我不会给你们展示调试器
Friday. I'm just going to show you using print to debug and
那是周五做的。我仅仅要展示使用打印来调试
you can also move this up and down as high as you want. So,
并且你可以上下移动它来调整高度
it's very nice to be able to, kind of, organize your space.
所以它对于组织你的空间十分友好
I have a fairly low resolution screen here. So
我有一个比较低分辨率的屏幕
I'm going to be trying to hide things as much as possible to
所以我会尽可能隐藏一些东西
make the text really big so you can see what I'm doing.
来让文本尽可能大到让你看见我在做的事情
All right, one last thing I want to show before we dive in
好了，在进入演示程序之前我想展示最后一件东西
here, is this area up here, you see this, this is how you
是这个区域，你能看到的，是你如何运行你的应用
run your application. Okay so, when you run your application,
当你运行你的应用时
you have to decide where are you gonna run it. You can run
你必须决定你要在哪里运行它
it on a device, so you can hook up a device to your Mac.
你可以在一台设备上运行，所以你必须将设备与 Mac 连接起来
And you can hook it up wirelessly actually or
事实上你可以无线连接或者
with a little USB cable or whatever. And I don't have any
用一根 USB 线或其他方法。我这里
hooked up, so I can't do that. But I can also can run on all
没有可以连接的东西，所以我不能这么做。但是我仍可以在所有的
of these simulators. So, these simulators simulate these
simulators（模拟器）中运行。这些模拟器模拟各式的设备
various device like an iPad or iPhone 8+ or whatever. And
像 iPad，iPhone 8 plus 以及其他设备
you can run your app on any of these that you want and
你可以在任意模拟器上运行你的应用
in fact, the simulator will open both of these,
事实上，模拟器可以在同一时间打开两个
multiple of these as a time, if you want. So I'm gonna
或者多个，如果你想的话
do the latest and greatest here which is the iPhone X.
所以我会用最新也是最好的模拟器，即 iPhone X
Okay I'm gonna run my app on IPhone X and
好的，我会在 iPhone X 上运行我的应用
let's go ahead and run it. We haven't done anything, so
让我们直接运行它。我们还没有做任何事情
it's just a blank app and let's just run it for fun.
所以它仅是一个空白的应用。让我们仅仅为了乐趣运行它
You see this play button right here? That's how you run, so
你看到那个播放按钮了么？那就是你运行它的按钮
I'm gonna click that play button. Now it is compiling my
我会按下那个按钮，现在它正在编译
app as you can see at the top, it's it building into
我的应用，正如你在上方看到的，它正在被编译成一个
a binary. It's loading it onto the device, or
二进制文件。它正在加载到设备中
in this case, simulator. And it runs it. Okay so
在这个情况下，是模拟器。然后运行它
here it is. It looks like an iPhone X and
它就在这里了。它看起来是一台 iPhone X
it's running my app and it's completely blank.
正在运行我的应用，它看起来是完全空白的
Well because I haven't done anything,
因为我还没有做任何事情
I haven't built any UI. But if I press the home button
我还没有构建 UI，但是如果我按下 home 键
on the iPhone X, everyone know how that works? You slide up
在 iPhone X 上，每个人都知道它如何工作么？你从底部
from the bottom. Sliding up from the bottom is like
向上滑动。从底部向上滑动就像
the home button because there is no home button in iPhone X.
home 键的功能一样，因为在 iPhone X 上并没有 home 键
And you can see there's our app concentration right there.
你能在那里看到我们的应用 翻牌
But all other apps are there too.
其他的应用也都在那里
Settings, right, you can go into the settings app. And
设置，如果你想的话
if you want, you might have your app needs to set some
你可以进入设置应用，你的应用可能需要一些
setting like, I don't know, text size or something like that.
设置，比如文本大小或其他的事情
So these simulators are truly simulating the device, they're
所以这些模拟器就像真的设备一样，它们不仅仅
not just running your app only. So that's kinda cool.
是运行你的应用而已。这很酷的
And we can always go back to our app. Just go back here and
我们随时都可以回到我们的应用。只要
say Concentration, here's Concentration. All right,
点一下 Concentration，这就是翻牌应用了。好了
so now we're familiar with Xcode and kind of
现在我们熟悉了 Xcode 和所有组件
all its pieces right here. Let's take a look at the files
的一部分。让我们看一下那些 Xcode
that were created for us. Now, There are six files but
为我们创建的文件。这里有六个文件但是
actually we're only gonna look at two of them. For example,
实际上我们仅仅需要看其中两个。举个例子
this one, assets, right here, that's your images,
这个, assets, 是你的图片
including your app icon, which we haven't set,
包括你的应用图标，我们还没设置
I don't really need that. Your launch screen right here, I'm
我并不太需要它。你的启动屏幕
selecting that as well. This app delegate up here, we don't
我也一同选中。还有 AppDelegate
need to touch any of these to make our Concentration app. So
我们在编写翻牌应用时不需要碰这三个文件
I'm selecting them all and I'm going to right-click on them,
所以我选中然后右键他们
and go down to new group from selection, and put them in
选中 New Group from Selection，把它们放到
a group. And I'm going to call that group Supporting Files,
一个组里，然后我会把它叫做 Supporting Files
because that's what they are,
因为那就是它们的本质
they're supporting files. By the way, I would not
他们是支持性文件。顺便说一句，我不会
put your info.plist in your Supporting Files,
把 info.plist 放到 Supporting Files 里
leave that at the top level. It seems to be better. So
把它留在第一级，这看起来更好
this other file here, ViewController.swift,
剩下的文件，ViewController.swift
is just some Swift code, we'll get to that in a second. And
是一些 Swift 代码，我们会过一会儿研究它
right here, Main.storyboard, that's your UI.
Main.storyboard 里是你的 UI
Now you're gonna build your UI in Xcode graphically,
你将要在 Xcode 中图形化地构建你的 UI
okay you're not gonna code it up, you're gonna do it
你不会用代码构建它，你将用
graphically. And not only that the way you're gonna build it,
图形的方式。不仅仅是你要以这样子的方式构建它
you're gonna drag out buttons and
你要拖拽按钮
text fields and sliders and things like that.
文本输入, 滑杆等其他控件
And it's going to actually put real buttons and
它将把真正的按钮
real sliders live on the screen at a time. And
滑杆放置到屏幕上
you're going to edit them and set them up the way you want.
你可以用你喜欢的方式编辑他们
And then when you run them on your app,
然后当你运行你的应用时
it kind of freeze dries them, brings them over and
就如同冰冻了他们，然后给他们
adds water and they come back to life. And then they run. So
添加一些水，他们就恢复了生机。然后他们就运行了起来
when you run, it's not like you don't click a button here
所以当你运行的时候，它不像是，你没有点击按钮
and it generates a lot of code to put those buttons there.
它生成许多代码来将那些按钮放置到哪里
It's actually editing these buttons live. Now,
它实际上是编辑那些按钮，让它们活过来
notice that I got this, sort of, iPhone shaped rectangle.
现在，注意我有了这个，像 iPhone 一样形状的矩形
Can you all see that? Yeah, it looks pretty good. This iPhone
你们都能看到么？好的，它看起来很不错。这个 iPhone
shaped rectangle is where I'm going to edit my UI. And in
形状的矩形就是你要编辑你的 UI 的地方
particular this is an iPhone 8 sized rectangle, you see that?
特别的，这是一个 iPhone 8 尺寸大小的矩形，你们看得到么？
It says view as iPhone 8 down here. I can click on this and
这下面写着 view as iPhone 8。我能单击这里
actually look at other iOS devices. So I can look at
然后查看其它的 iOS 设备。所以我能看到
my UI, how it would look let's say on an iPad.
我的 UI，它是如何在一台 iPad 上呈现的
Now an iPad is huge so maybe I wanna zoom down a little bit
一台 iPad 是大的所以我想缩小一点点
to see it better. I can also look at it in landscape mode.
让它看起来更好。我还可以在横屏模式下查看
So here's portrait and landscape of an iPad, for
因为 iPad 有横屏和竖屏，就像这样
example. I could go to a different kind of iPhone,
我可以用不同种类的 iPhone
like here's my iPhone X, all right? So I can look at
就像这是 iPhone X。我能用
all possible iOS devices and see how my UI looks.
所有可能的 iOS 设备来查看我的 UI
Now our goal eventually, once we learn enough about iOS,
现在我们最终的目标是，我们学习足够多的关于 iOS 的知识
is to build UIs that look good even if they're in landscape
去构建 UI，让它无论在哪里看起来很都很棒
or portrait, iPad, iPhone 8, iPhone 8+, which is big,
不管它是在横屏还是竖屏，iPad, iPhone 8 还是大一点的 iPhone 8 plus
iPhone X, it doesn't matter. Okay that's our goal.
iPhone X, 都没关系。那就是我们的目标
Now in the first week, I can't teach you any of that, so
如今在第一周，我还不能教你这个事情
we're gonna have our UI just
所以我们将会让我们的 UI 仅仅
try and look good on an iPhone X.
在 iPhone X 上看起来不错
But next week, not to worry we'll try to make it so
但是下周，我们将会尝试
it looks good on other iPhones as well. And
让它在其他 iPhone 上也看起来不错
your assignment two is gonna really ask you to make
你们的作业二将会要求你制作一个
an app that just looks good on all possible iOS devices.
能够在所有的 iOS 设备上看起来都很好的应用
Now on the left over here, when we brought up this,
如今左边的区域，我们所在的
this area in Xcode by the way is called Interface Builder
这片区域在 Xcode 中叫做 Interface Builder
because we're building our user interface,
因为我们将要在这里搭建我们的用户界面
so Interface Builder. This area over here is essentially
所以叫做 Interface Builder。这片区域
all the things that are here but
包含基本上所有这里的东西
in text form, like a text outline.
只不过是以文本的形式，像一个文本大纲
And I'm gonna hide that,
我会通过下方的这个小按钮
you do that with this little button down here,
来隐藏它
see it says hide document outline.
看它上面写着 Hide document outline
I'm gonna click that to hide that. We'll go and hide this
我会点击它，把它隐藏。我们也要隐藏
phone chooser as well and we have our little UI here.
这个设备选择器，这样我们有了我们的 UI 界面
We'll look at that document outline later in the quarter.
我们会在这学期之后的时间查看这个文件大纲
I want to build my UI, how do I build a UI?
我想要搭建我的 UI，我该如何搭建我的 UI 呢？
Okay I'm trying to build Concentration here.
我想要制作翻牌应用
So I'm going to need some cards. And I'm going to
所以我会需要一些卡牌
use a button to represent a card, which is kind of cool,
我会用一个按钮来代表一张卡牌，那是蛮酷的
because you tap on a button and
因为你轻击一个按钮
it does something. And that's good,
然后它做出一些反应，那很棒
because when you tap on a button I want it to flip over.
因为当你轻击一个按钮，我想要让它翻转
Okay, I'm going to have my cards flip over. So
好的，我想要我的卡牌翻转
that's the first thing you do. Let's build one card that will
这是你需要做的第一件事情。让我们制作一张卡牌
flip over when we click on it all right. So
当我们点击它，它就会翻转
I'm going to zoom in, by the way, you can hold down alt.
我会缩放一些，顺便说一下，你可以按住 alt 键
You see in the lower left I have a thing here that shows
你可以看到在左下角我放了一个东西来展示
when I'm pressing alt, and control, and command,
我正在按的键位，如 alt， control，command
and all that stuff. If you hold down alt and
和其他任何键。当你按住 alt
use your mouse wheel you can zoom in and out, on your
用你的鼠标滑轮滑动，就可以缩小和放大
UI, which is kind of cool. Otherwise your mouse wheel
你的 UI, 那是蛮酷的。若不按住 alt 键，滑动鼠标滑轮
moves it up and down, which is also kinda cool. All right so
会让它上下移动，这也很酷
we have our UI here, how do we put a button in this UI? Okay,
我们有了 UI, 该如何放一个按钮到 UI 上呢？
as promised, we go over to this thing that had a top and
正如承诺的，我们来到这个有着一个顶部和底部
a bottom, called the utilities pane.
的东西，它叫工具栏
And we're going to look in the bottom to start, and
我们将要从底部开始
specifically, in this object library tab. And
明确说，是这个 object library (对象库) 表格
we're going to see a whole bunch of objects, remember,
我们将会看到全部的对象类型，记住
and I mean objects like in an object-oriented sense,
我说的对象就是面向对象里的对象
this is all object-oriented. And all these objects,
这些全部都是面向对象的。所有的这些对象
like labels and buttons and text fields and switches,
像标签，按钮，文字输入和开关
even web views and table views and text views and even ARKit.
甚至网页视图，表视图，文本视图甚至 ARKit
Here's a little ARKit of augmented reality views.
这是 ARKit 中的一个小的增强现实视图
These things can all be dragged out,
这些东西全都可以被拖拽
multi touch gestures, dragged out to build your user
还有多触控手势，拖拽来搭建你的用户界面
interface. Okay and I'm going to cover the vast majority of
我将会涉及在这个非常大的列表里的
the stuff in this very large list right here.
很多的主要控件
But we're going to start with a simple one which is towards
但是我们将以一个非常简单的开始
the top, which is buttons. So
那就是上面的按钮
I just wanna drag a button into my UI, and
我将会拖拽一个按钮到我的 UI 上
I just drag it in, I pick it up with mouse, and
我仅需要拖住，点击我的鼠标
drop it in my UI. Now, when I move this around,
然后把它丢到我的 UI 上。现在，当我四周移动它
look at these blue lines, see these blue lines.
看这些蓝色的线，看这些蓝色的线
They're trying to help me put it exactly in the middle, or
它们尝试帮我把它放置到正中间的位置
exactly in the middle on the bottom edge,
或者底部边缘正中间的位置
or up in the upper right corner.
或者右上角的位置
These blue lines are critical to building a UI that will
这些蓝色的线对于构建你的 UI 来说非常的重要
work when you rotate or on a bigger device or whatever. But
当你旋转屏幕或者到一台更大的设备上时，它们会起到重要作用
we're gonna ignore the blue lines for now
但是我们暂时忽略这些蓝色的线
because I said I'm gonna teach you that next week,
因为我说过我会在下周教给你们
all right? So here's my button, it's very, very small.
好么？所以这是我的按钮，非常非常小
I want it to be bigger. Well, I can just grab these handles
我想让它大一点。好的，我可以抓住这些边缘上的柄
on the edge here and resize it to whatever size that I want.
然后缩放到我想要的尺寸
Maybe make it a little more card shaped or
把它的大小设置成卡牌那么大
something like that. And I could also edit the text on
我还可以编辑文本
here by double-clicking on this.
通过双击这个东西
I don't want Button maybe, but let's do the back of the card,
我可能不太想要这个按钮，让我们做卡牌的背面
let's see what the back of the card looks like.
让我们看看卡牌的背面是什么样子
So I'm just gonna delete it,
所以我只要删除它
so now my button has no text on it, all right,
现在我的按钮没有了文字
which is fine. How about setting the background color
这是不错的。把背面颜色设置成
to orange, these cards orange, and our Halloween theme here,
橙色怎么样，那些卡牌是橙色的，我们还有万圣节主题
they have orange background. How do I do that?
他们会有橙色的背景色。我该如何做呢？
Well, that's the top of this utilities pane. Notice that
好吧，那在我们工具栏的顶端。注意
when I select a button, I get this UI over here that is
当我选中一个按钮，我得到了这个页面
specific to setting the attributes of a button. And
这是具体设置这个按钮的属性的地方
not only that, it's object-oriented. So
不仅仅是这样，它是面向对象的
I have the button stuff here and as I scroll down, look,
所以我有一个按钮的对象，并且当我下滑，看
I get UI for a control because button inherits from control.
我得到了一个关于 Control 的界面，因为 UIButton 继承自 UIControl
And then control inherits from view. So
而 UIControl 继承自 UIView
I get UI to enter to view because a button is a view,
所以我又得到了一个 view 的界面，因为一个按钮就是一个视图
right? It inherits from view in the object-oriented sense.
对吧？通过面向对象来讲，它继承自 UIView
So the background of any view is settable here in this UI.
所以任何一个视图的背景都可以在这个界面里设置
It's right here under View, it says Background.
它就在这里，在 View 下，它叫做 Background (背景)
Right now the background is clear, that little line
现在背景是透明的，那条
through a thing means clear. So there is no background, so
穿过的线意味着透明。所以这里没有背景
it's showing the white from behind is showing through. But
所以它才会展示它后面的白色
I can easily change this to orange by clicking there and
但是我能轻松的改变它为橙色，通过点击哪里
going down here. You know,
然后向下，你看
there's a lot of preset colors here.
这里有许多预先设置好的颜色
I can go to Other and pick it by name, I could pick orange.
我可以点击 Other 然后通过名称选中橙色
I could pick a crayon that looks orange,
我能够选中一个看起来像橙色的蜡笔
color wheel, whatever. But here I want orange, so
颜色转盘，无论什么。但是我想要橙色
I'll just pick it by name. And
所以我仅仅需要通过名字来挑选
now I've set the background of my card to be orange, so
现在我已经设置卡牌的背景是橙色
that's good. That's looking pretty much exactly like this,
那是不错的。那看起来和这个非常像
I'm happy with it so far. And in our Halloween theme,
迄今为止我非常开心。在我们的万圣节主题里
to make it even scarier, let's make the background here
为了让它看起来更可怕，我们设置这里的背景
be black. So I'm gonna change this to be black.
为黑色。所以我要把它改成黑色
And the way I do that is I just click on it and
方式也是我仅仅需要点击它
now this right-hand side doesn't say button on the top.
现在右手边的顶端就不是写着 button
It say view because this big space is just a blank view.
它写着 view 因为这个大的空间是一个空白的视图
It's not a button view or anything. It's just a view,
它不是一个按钮或其他东西。它就是一个视图
but it's got this background thing, same way. So
但是它设置背景的方式是一样子的
I click on it, and here I'll just pick it from this list of
所以我点击它，然后从列表里选中
predefined things. Black color, and now, I have a nice
之前定义好的东西，黑色，现在我有了一个好看的 UI
orange on black UI. Looking pretty cool. Now, what about
橙色的卡牌在黑色的背景下。它看起来很酷。现在
when the cards are face up? Well, when they're face up,
当卡牌面朝上的时候是什么样子。好的，当它们面朝上
they're white. And then they have an image on them.
它们是白色的，并且有一个图案
Now I could have the cat or the spider web here or
我能放一只小猫或者蜘蛛网
whatever be some JPEG image or something. But
或任意一张 JPEG 图片或其他东西。但是
I got a really cool idea to make this be real easy, let's
我有一个很酷的想法让它很简单，让我们
make it be an emoji. Cuz if we just put an emoji in here,
放一个 emoji。因为如果我们仅仅放一个 emoji 在上面
then we have a lot of choices. And it's really easy and
我们就有了很多选择。那是非常简单
we don't have to go find the images or anything like that.
并且我们不必找图片或者其他东西
So that's what we're gonna do. So
这就是我们将要做的
I'm gonna make this look like the front of the card. So I'm
所以我将在卡牌的正面弄成那样子
gonna go down here and change this orange back to white,
我要向下一点，把这个橙色变成白色
okay, this white color. And I'm gonna put on here,
好的，这个白色。然后我要放到这里
instead of blank, I'm gonna put an emoji. Most Mac apps,
代替白色，我会放一个 emoji。大部分 Mac 应用
if you go to their Edit menu, at the bottom of it,
如果你去到 Edit 菜单，在它的底部
there's this emoji and symbols. I don't know how, how
这里有一个 emoji and symbols, 我不知道有多少
many of you know that. But if you go to emoji and symbols,
你们有多少人知道这个。但是如果你点击 emoji and symbols
you get this window right here that lets you choose
你会立刻得到一个窗口让你选择
all these various emoji. We got a Halloween theme here, so
各种emoji。我们有一个万圣节的主题，所以
let's look for a ghost. Yeah, Mr. Ghost, right there.
我们查找一下 幽灵。好的，幽灵先生就在这里了
Okay, so that's a good, he looks like a fun ghost even.
好的，那是不错的，他看起来甚至像一个有趣的幽灵
We'll double-click right there to put him on the card and
我们要双击这个来把它放到卡牌上
there he is. He's very, very tiny. I could go zoom in and
然后它就在这里了。不过非常，非常的小。我能够放大
look at them. But he's even small compared to the size of
然后看一下它。但是它还是太小了，比起
the iPhone X. If my user was doing this, they'd be like,
iPhone X 的尺寸。如果我的用户在使用它，他们可能会说
what is that. It was just like a little smudge. So
那是什么？那会是一个小的污点
we wanna make this much larger. So again,
所以我们要把它放大一点。在一起
I'm going to the top side, top half of this utilities pane.
我去到顶端部分，工具窗口的上半部分
And if I look down here, look, font, system font 15 point.
如果我往下看，字体，系统字体15号
So I'm gonna make that way bigger,
我要让它大一点
let's make it 50 point.
让我们调到50号字
Now we got a nice big ghost. Awesome,
现在我们有了一个大幽灵，酷
we have got all we needed in terms of design to do our UI.
我们有了有关于我们 UI 设计的一切
Let's go ahead and run and see what happens here.
让我们直接运行看看会发生什么
See if this black background and this ghost and
看是否这个黑色的背景和幽灵还有
all this stuff is showing up in our app when we run.
全部的这些出现在我们的应用里
And of course it will be, here it is. And when I click on it,
当然它会的，这里就是了。当我点击它
can you see that it's flashing a little bit there?
你们刚看到它在轻微的闪烁么？
That's saying, that's giving me a little feedback, yeah,
这意味着，它给了我一点小小的反馈
you touched on that.
是的，你触碰了它
It's nice, but it doesn't do anything, right?
这是不错的，但是它没有做任何的反应，对吧？
And we want it to do something.
我们想要它做一些事情
Mainly we want it to flip over. So let's go do that.
主要的，我们想让它翻转。所以让我们做吧
How do we make it so something in the UI does something?
我们该如何让 UI 里的东西能做什么事情呢？
Well, we're gonna hook it up to some code. Specifically,
好的，我们将把它和一些代码挂钩。明确的讲
we're gonna hook it up to this Swift code right here.
我们会把它和一些 Swift 代码挂钩
Now they gave us these things right here,
现在它们给了我们这些东西
which I'm gonna delete so as not to distract you.
我会删掉它们不要让它们干扰到你
But this is your first look at Swift code.
但这是你看到 Swift 代码的第一眼
Let's look at it real quick, see what it does. Import,
让我们快速看一眼，它做了什么。Import
it's just like include. It's just bringing all of UIKit
它就像是 include，它即是把 UIKit 的全部内容带来
in for our use. UIKit is iOS's framework that has buttons and
为我们所用。UIKit 是 iOS 的框架，包含按钮
sliders and all that stuff.
滑杆和所有内容
Kinda that top cocoa touch layer we're talking about.
就是我们讨论过的顶端的 Cocoa Touch 层
So this is the declaration of a class, in an object-oriented
所以这是定义了一个类，这是面向对象的概念
sense, a class. Of course we use the keyword class.
定义一个类，当然用关键字 class
This is the name of the class, ViewController.
然后是类的名字，ViewController
This is not a very good name, it's very generic. Probably
这并不是什么好名字，太广泛了。最好
this wants to be called ConcentrationViewController or
这个应该叫做 ConcentrationViewController
something like that. Do not change the name of this in
或者类似的名字。不要更改这个类的名字
your homework, okay? Changing the name of
好吗？在你的作业里面更改这个名字
this requires a little more than just changing it
有比仅仅在这里更改它的名字更多的步骤
right here, because it's also showing up in your UI.
因为这个会展示到用户界面上
So you have to change it in a way that it changes in both
如果你要改的话，那两个地方都要改
places. This is its super class. This is
这是它的父类
Object-Oriented Programming. We have inheritance.
这是面向对象编程，所以我们有继承
It's inheriting from UIViewController.
它继承了 UIViewController
Class UIViewController is in UIKit. You can tell because it
UIViewController 是 UIKit 中定义的。你可以从
starts with UI. And what that class does,
它名字以 UI 开头看出来。这个类的作用
it knows everything about controlling a UI like this.
它知道如何控制像这样的用户界面
That's what it does. So by having our ViewController
这就是它的功能。让我们的 ViewController
inherit from that, it inherits all the capability to control
继承它，就继承了所有控制的能力
that thing. So all we have to do is put the code that has
所以我们只需要把代码
to do with the Concentration game in here, so
和翻牌游戏相关的代码放在这里
that's great. Then inside this curly brace, we're gonna
这很不错。在这对大括号里，我们
put all our methods and instance variables. Who
所有的方法（method）和实例变量都放这里
does not know what the word method or instance variable
谁不知道“方法”或者“实例变量”的意思？
means? Okay, good, everybody does. And you should because
好，很好，大家都知道。你应该知道
that's fundamentally an Object-Oriented Programming,
这是面向对象编程的基础
right? So we're gonna put all our instance variables and
是吧？所以我们把所有的实例变量和
methods inside those curly braces.
方法都放在这对大括号里面
That's how we're gonna declare our class. So how are we
这就是我们声明类的方法。那我们
gonna make this button do something here? Well,
怎么才能让这个按钮做些什么呢？
what we're gonna do is we're gonna create a method in here.
我们要做的是，我们在这里创建一个方法
And we're gonna make it so
我们要让它做到
that when you press this button, it calls that method,
当你按下这个按钮，它就调用这个方法
of course. How are we gonna do that?
当然了。那我们怎么做呢？
To do that, believe it or not, we need to get this UI and
不管你信不信，要实现这个，我们需要让 UI
this code over here on the screen at the same time.
和这个代码同时出现在屏幕上
And we do that with this little button right here.
我们按这里的这个按钮
This little circles thing right here,
这个画着圆圈的按钮
this is called the assistant editor. And when I click it,
这是 Assistant（助理）编辑器。当我点击它
they come on screen, both of them on screen, at the same
它们就出现了，同时显示在屏幕上
time. And I can adjust this space however I want.
我可以随意调整它们的大小
Maybe we'll get rid of this now.
我先在可以先隐藏这个
All right, so here's my UI and my code on screen at the same
好，我们的 UI 和代码同时显示出来了
time. Now, why do I want them on screen at the same time if
为什么我想要他们同时出现
I need to hook them up? Because the way I hook them
来关联他们？因为我关联他们的方法
up is I hold down the Ctrl key and drag a line from the UI to
是按住 control 键不放，然后点击 UI 上（的按钮），再拖出一条线
my code. I know that's kinda weird, but
到代码里。我知道这挺怪的
that's how we do it. And when we let go of that drag line,
但这就是我们实现的方法。当我们松开鼠标的时候
it says, you will make a connection between UI and
他会问，你将要建立 UI 和代码的关联
code. No problem, what kinda connection would you like?
没问题，那是什么样的关联呢？
You can make an action, which is a method, or
你可以创建操作（Action），也就是一个方法
one of these two outlet things,
或者这两种出口（Outlet）中的一种
which I'm gonna talk about later in this lecture. So
我这节课之后也会讲到
let's start with this action one. An Action connection
所以我们这里是用 Action 这个选项。关联一个操作
means when this button is pressed, call a method.
的作用是按下按钮的时候，就调用这个方法
And I get to say what the name of the method is.
然后我要命名这个方法
I'm gonna call it touchCard, cuz that's what's happening,
我要叫它 touchCard，因为这就是发生的事情
someone's touching on this card. And this method that's
也就是有人点击了这张卡片。然后这个方法
gonna be created for me, it can have arguments,
要创建的方法可以通过 Arguments 指定参数
it could have no arguments, that's none. Or
也可以没有参数，也就是 None 这个选项
it could have one argument, which is the sender,
也可以有一个参数，也就是 Sender
in other words, the button that is sending me this.
换句话说，就是调用这个方法的按钮
I really need that argument,
我非常需要这个参数
because when this touch card gets sent to me,
因为 touchCard 被调用了
I need to flip it over. So, I have to talk to it, okay, so
我需要把那张牌翻过来，所以我需要能访问它
I want that argument. And really important,
所以我想要这个参数。非常重要的一点
pay attention right now if, if you're dozing right now,
打瞌睡的注意了
is that we do not. This is the type of the arguments.
我们不能，注意这里这个是参数的类型
See it says Type Any? And we want that type to be Button,
看到它写的是 Any 了吗？但我希望参数是按钮的类型 UIButton
okay? Because a button is sending this method to us.
好吗？因为是这个按钮调用了这个方法
Now I don't know why that doesn't default to Button.
我不知道为什么不是默认为按钮的类型
I've been seeing that for years, it should. But
好多年我看到的都是这样，本因该是按钮的类型
it doesn't. And if you don't change that from any to button
但就不是。如果你不把它从 Any 换为 UIButton
the rest of this code is not gonna work. So definitely,
接下来写的代码是用不了的。所以一定
if you remember nothing else from this, remember to change
就算你其他的都记不住，记得
that. All right? So we have this button here and I'm gonna
把类型改了。好吗？所以类型是按钮
hit these other things. But you know, here's obviously,
然后我点……等等，当然
we were sending it to the view controller.
按钮会发消息告诉 ViewController
The event touch up in side just means when you touch
这个 Event，事件是 touch up inside 的意思你
up inside the bounds of the button, send this message.
在按钮的内部点击就调用这个方法
All right, so let's connect. I'm gonna hit Connect.
好，我们点 Connect 来建立关联
It's gonna give me a method.
然后就会创建一个方法
This is your first look at a Swift method right here.
这是你第一次见到 Swift 的方法
And let's look at the parts of it. Interestingly,
让我们来分析它的各个部分。很有趣的是
this is not part of a Swift method, okay. This is just
@IBAction 不是 Swift 方法的一部分，那只是
a special directive that Xcode is putting in there.
Xcode 放在那里修饰方法的特殊指令
That causes it to put this little round circle here where
这样就能让 Xcode 在左边显示一个小圆圈
the line numbers are. You see how line number lucky 13 there
就在显示行号这里。看到这个“幸运”的 13
is a circle instead. If I mouse over that circle,
被换成了个圆圈么？如果我把鼠标移到上面
I'm not clicking just mousing over. If I mouse over that
我没有按下去，只是放在那里。如果我鼠标放上面
it'll show me which buttons send this message,
就会显示是哪些按钮发的消息
which ones invoked this method. So
是哪些会调用这个方法
that's all the IBAction does just cause this circle to
这就是 @IBAction 的作用，就是让圆圈
appear here. Now this is the syntax of a Swift method.
出现在这里。剩下的就是 Swift 方法了
So let's look at it's parts.
让我们来看它的组成部分
Func. It's just a key word that says this is a function.
func，那就是说明这是一个函数（function）的关键字
A method is just a function on a class. It is legal to have
我们知道方法就是定义在类里面的函数。你也可以
functions outside of classes. They're global functions.
在类的外面定义函数，也就是全局函数
We almost never do that cause we're very object oriented,
我们基本不这么做，毕竟是面向对象
but you can do it. This is the name of the method,
但你可以这么做。空格后是方法的名称
touch card. I chose that in the little pop up.
也就是 touchCard，我在之前的小弹窗里决定的
This is a list of all its arguments. Okay,
然后是参数列表
this method has one argument. The type of the argument comes
这个方法有一个参数，参数的类型
at the end with a colon, colon type, which is a UIButton,
是在最后面，用英文冒号隔开——: 类型。这里类型是 UIButton
obviously. We said we wanted one argument,
显然的，我们说我们想要一个参数
which the sender was a UIButton, that's what it is.
也就是类型为 UIButton 的 sender，这就是这个意思
This are the names of this parameter.
然后这些是参数的名称
Names plural. Now, there are two things about Swift that
注意是这些。现在我们讲讲，Swift 有两个
are going to be quite different from what you're
与其他非常不同的地方
used to in other languages. One, every argument has a name
和其他语言不一样，其一是参数有一个实参标签
that you actually include when you call the method. Okay?
你在实际调用方法的时候会用这个标签
So like in Java you would
比如在 Java 里你会用
say touchCard open parenthesis six comma hello
比如 touchCard(6, "hello", 5)
comma five. You would never do that in Swift.
在 Swift 里你不会这样做
Each parameter would have a name in front of
每个实际参数都有一个标签在前面
it. That way if you're calling it and you're reading
这样当你调用了它
the code you don't have to remember that first argument,
你读代码的时候就不需要记住第一个实际参数
what's that again? Because they're each named. And
究竟是什么，因为有标签告诉你
the other thing is it has two names. Okay.
另外一点就是参数有两个名字
The two names are the external name.
其中一个就是之前提的实参标签
That's the name callers use and the internal name. That's
这是调用方法的人用的。另一个是形参名称
the name we're going to use inside of are implementation.
也就是在实现方法的时候使用的形式参数的名称
Now I'm going to write my own method in a second here and
我马上自己写几个方法
we'll talk about this more, but that's what's going on
然后我们再仔细讲讲，但这就是这部分的意思
here. Now if this method had a return value, you show that by
如果这个方法有返回（return）值，你需要
saying arrow Int lets say that would mean this method
通过比如 -> Int 来表示这个方法
returns an Int. Very simple syntax for that. But
会返回 Int 类型的整数。非常简单的语法
this method doesn't return an Int, but you could make it so
但这个方法并不会返回一个整数，但你可以让它
it does. Okay, so let's make sure this is working.
这样做。好，让我们确认下这能用
I'm just gonna use that print function I was talk about this
我就用之前讲的 print 函数
is a global function called print. It just takes a string
print 就是个全局函数。它接受一个字符串参数
and prints on the console. So here I'll print agh! a ghost.
然后打印到控制台里。我输出说这“啊，这是个鬼”
Okay, and we're gonna run our app and
好，运行我们的程序
see if this is working when we press the ghost. So
来看看我们按下这个鬼的时候有没有反应
by the way, when we are gonna print stuff from the console,
顺便一提，当我们要输出到控制台的时候
we probably wanna bring this up from the bottom so
我们最好点这个来显示下面这个面板
we can see our console, we can make our debugger smaller.
这样我们就能看到控制台了。我们把调试器调小点
Here's our console bring it up. There's actually a cool
这就是我们的控制台。其实，很酷的是
thing you can do, I'll show you a Xcode tip.
你还可以这样做。我告诉你个 Xcode 的使用技巧
If you got here to Xcode, Behaviors and Edit Behaviors.
如果你到菜单栏里的 Xcode > Behaviors > Edit Behaviors...
And you go down you can have it so
然后在下面找。你可以让
that Xcode does things, opens windows,
Xcode 做比如新建窗口
does other stuff when certain things happen. For example,
或是在某件事发生的时候做另一件事
if you're running and
比如你运行
it generates some output on the console, you can say
而且会在控制台输出，你可以
show the debugger. Okay, and it will automatically bring
让它显示调试器，Xcode 就会自动
that up from the bottom if it's not there.
把它在下面显示出来
So that's kind of a nice little feature. All right, so
这就是很实用的一个小功能。好
let's run it. Those are the kind of tips and tricks we'll
让我们来运行。像这种使用技巧和提示就是
cover on Friday, by the way. Good reason to come on Friday.
我星期五讲的内容，所以我建议你星期五来
Question, yeah? >> Can you go over again
谁有问题？>> 你能重新演示下
how you link the button to the view controller?
如何把按钮关联到视图控制器的吗？
>> Yeah how we
>> 好的
connect to the button view controller?
我们怎么把按钮关联到视图控制器？
Yeah, I'll show you that in just a second.
好，我等会再演示一遍
So let's make sure it's working and
让我们先确保这可以用了
then I'll show you how we connect to it again. So
然后再展示一下怎么关联的
we have this button here.
我们的按钮显示在这里
I'm gonna click the ghost and look down in our console.
我点一下这个鬼，然后看我们下面的控制台
Look, agh! it's a ghost, okay. So it's working. So
看，输出了 agh! a ghost!。所以是可以用的
we're clicking the button and it's doing that. So
我们按这个按钮，就输出这个句话
the question is, how did we hook it up again?
好，刚才的问题是问如何建立关联
Well what we did is that we held down control, the control
我们做的是我们按住 control 键不放
key, and we dragged from the button into our code.
同时按鼠标，从按钮拖拽出一根线到代码里
And when we let go it asked us all the questions.
然后我们松开鼠标，Xcode 就会问那些问题
What do you want to call it?
比如你要叫它什么名字？
That kind of stuff. All right, so we got this hooked up,
这样的问题。好，我们关联上了
right. Now we need to flip the card over when this happens
现在我们需要把牌反转过来
instead of just saying, agh! a ghost. Okay?
而不只是打印出说这是个鬼
So we're not gonna say agh! a ghost anymore. So
我们不会再打印 "agh! a ghost!" 了
to do that, I'm going to add my own function that flips
要实现这个功能，我要自己写一个函数来翻牌
the card over. So let's create our own Swift function.
让我们来自己写个 Swift 的函数
So we have to say func cuz its a method on a function.
我们用 func 关键字，因为方法也是函数的一种
I'm gonna call this flipCard, okay.
我把它叫做 flipCard，翻牌
And I'm gonna have two arguments.
然后有两个参数
One is the emoji that I want to be on this card,
一个是 emoji，我想要显示在牌上的表情
the ghost or whatever. The other one is the button
比如鬼一类的。另一个参数是按钮
that I want to set the emoji on, or whatever.
我用来显示表情的按钮
So, interestingly here, I'm going to call in these things
很有趣的是，我要取的名字
constrain what you might think are strange names.
你可能会觉得很奇怪
I'm gonna say with emoji, emoji of type string. So
我叫第一个参数 withEmoji emoji: String
this is in external name with emoji internal name emoji. And
实参标签为 withEmoji，形参名称为 emoji，类型是 String 字符串
how about this one on button UIButton. Okay?
然后第二个是 on button: UIButton
Now, these might seem really strange to you as names of
现在看这些，你可能会觉得是很奇怪的
parameters, both internal and external.
参数名，实参标签和形参名称同时出现
And in your reading assignment on the last page, it's gonna
你阅读作业的最后一页会链接到 swift.org 上的
link you to a document you have to read that explains
API Design Guidelines（API 设计准则）
how to pick good names here. Cuz there's a very well
你应该阅读它解释如何挑选好的名字的部分。文档很好地
defined set of rules for picking good names here. But
制定了挑选好名字的规则
the number one rule is when someone calls this function,
但是最重要的是，当有人调用这个函数的时候
it should read like English. That is the number one
应该读起来像普通英语一样。这就是最重要的
requirement of picking these names.
选择名字的要求
So let's call this function in touch card right here,
让我们在 touchCard 里调用这个函数
cuz we want to call it with the ghost. So I'm gonna say
因为我们想要用鬼的表情作为参数，所以我就输入
flipCard. Okay, notice, by the way, as I start to type,
flipCard，注意我开始输入
look at Xcode trying to help me. Xcode's so nice,
Xcode 会想办法帮助我。（没崩溃的）Xcode 多好啊
you see look, it know that I have a flipCard method.
你看看，它知道我有个 flipCard 方法
In fact, I'm just gonna hit tab and it shows me the method
其实如果我按下 tab 键，他就自动补全了方法
with the argument names. And I'm just ready to fill it in.
和实参标签，然后移动到输入实际参数的地方
So this is called, from the caller's point of view,
所以当调用的时候，调用的人所看到的是
flipCard(withEmoji). The emoji is let's say, for
flipCard(withEmoji: 然后是作为参数的表情
example, our ghost. I'll just copy and
比如这里的鬼，我复制粘贴
paste him from right here. On the button and which button?
过来。on，在哪个按钮上操作？
Of course, the sender. That's this sender right here. So
当然是 on: sender)，就是这个形参 sender
you see when I call it, it reads like English.
你看到我调用它的时候，读起来就像英语一样
Flip the card with the emoji ghost on the sender button.
把牌翻过来，显示鬼的表情到发送消息的按钮上
That's our number one thing we're trying to accomplish.
这就是我们要做的第一步
But inside here we wouldn't wanna be saying like, well if
但在 flipCard 里面我们不应该用类似于
the button title equals with emoji that just is weird.
if button.title == withEmoji（如果按钮的标题是使用表情）会很奇怪
It's sending a message to the button that says on.whatever,
或者是用 on.whatever（在上面.无论什么）来调用按钮的方法
that would make no sense,
这都听起来很不正常
so that's why we have these different names.
这就是为什么参数需要两个不同的名字
Now, it is possible and legal to only have one name like
其实是可以，而且完全可以只有一个参数名
just emoji. Then the external internal name would both
比如只有 emoji。这种情况下实参标签和形参名一样
be emoji. And this underbar thing like right here.
都是 emoji。这里的这个英文下划线
That means there's no argument,
意思是没有实参标签
in other words it's just like Java or
也就是像 Java 那样的
some other language. We almost never do that, it is done,
其他语言一样了。我们几乎不会，只有少数时候会这样
the document will tell you when you can do it,
准则里面提到了什么时候你可以或应该这样做
we almost never do it. It's here in this touch card
但基本不会。这里的 touchCard 用了下划线来省略
because that's an iOS thing that's sending this message.
是因为 iOS 系统发来的消息
It's from back in the Objective-C world.
是从 Objective-C 时代就有了
Objective-C doesn't have this internal external name thing.
而 Objective-C 没有这个实参标签的说法
So that's why it's under bar there, okay, but
所以需要有个 _ 来省略参数
we don't really use under bar that much. All right, so
但这并不是很常用
how we're gonna implement this flipCard right here?
那我们怎么实现 flipCard？
Well, this flipCard is essentially gonna toggle it,
flipCard 会把牌翻一个面
and I'm just gonna have this flipCard method,
那么我在 flipCard 方法里
look at the button If it's already the ghost,
判断按钮，看它是否已经显示了鬼了
then I'm gonna have it flip it over to orange with no text.
如果有，那就翻过去，背景色设为橙色，不显示字
If it's not, then I'm gonna put the ghost on it with white
如果没有字的话，那就把鬼显示在白色背景上
background. Just exactly what we played around with earlier.
就像我们之前在白板上玩的一样
So, we need to check to see if the buttons current title
所以我们需要查看按钮目前的标题
is this ghost. So I'm just gonna try and type this in
是否是这个鬼。让我试着输入这段代码
let's see, if the button. Okay, now I need to send
if button，如果按钮……现在我需要
a message to the button asking it what's your current title.
发送消息给按钮问它当前的标题是什么
Well, probably I wanna go look in the documentation, figure
那我应该去查看文档
out what button does. In fact, that's what you want to do.
看看按钮有什么功能。这是最正规的做法
But there's actually a cool way if you just wanna guess
但很酷的是，你可以去猜它叫什么名字
what it is. You can press dot. That's how you send a message
你输入 . 英文句号，也就是 Swift 里发送消息的方法
in Swift to just like Java, right, dot to send a message.
就像 Java 一样，对吧，用点语法来发送消息
And when you do that Xcode is gonna show you all the methods
然后 Xcode 会显示给你所有的方法
and variables that button understands, and let me say,
和变量，这些都是按钮可以接受的。然后我们用
there are quite a few. Okay, I'm scrolling through here,
我看看，不是我说，这里还挺多的
I'm only down to the Cs okay, we got Ds,
我现在还只是在 C 开头的，D 开头的
there's probably a couple hundred. So
可能有好几百个吧
how does this help me? This doesn't help me at all.
所以如何才能用这个帮助我呢？现在这样可没什么用
Well, the cool thing is, if I just type a word here that I
嘛，很酷的是，如果我输入一个词
think might be in the name of the method I want like title.
也就是我猜测的方法的名字，比如我想要 title
I want you to set the title. Now it just shows me things
我想要设置按钮的标题。现在显示的就是
that start with title, or that have title in it, or
以 title 开始的，或者是含有 title 的，或者
have T-I-T-L-E in it, which is not very useful, but
是有字母 T, I, T, L, E 在里面的，虽然这个没什么用
that's why it puts those at the bottom. But anyway,
当然这也就是为什么他们会在下面
we got the title. So now I can start looking around in
总的来说我们有与标题相关的了。现在我可以开始找
a much shorter list here, to see if I can find it.
要找的列表短很多，来看看能不能找到
So here's title color, definitely I don't want that.
这里有 titleColor，标题的颜色不是我想要的
Title rectangle, no. Here's set title.
titleRectangle，不要所在的矩形。这里有 setTitle
I don't wanna set the title right now but
我现在不想要更改标题，但
that's kinda good to know. Look at this one, current
了解这个有好处。看看这个，currentTitle
title. Current title that is displayed on the button.
按钮当前显示的标题
Victory, I found exactly what I want. And when I find what I
赢了呢！这就是我想要的。当我找的了
want here, looks like by the way, returns a string?
我想要的，顺便看看，返回的是 String? 类型
We'll try it anyway. If I double click on it,
管他呢，就用这个了。如果我双击它
it's gonna put that there for me. And now I can just say
Xcode 就会自动补全。如果现在我
is that equal to the emoji that you're asking me to flip
判断是否 == emoji，等于你让我翻过去显示的表情
the card to. This first argument. Notice how I'm using
emoji 就是我们的第一个参数。注意我用的是
emoji and button as my internal names here.
emoji 和 button 来作为方法内部使用的名称
I'm not using with emoji or on. That was for the caller.
而不是 withEmoji 或者 on；那是调用的时候使用的
Okay, so now I found out that the button already here
好，现在我知道了如果按钮
has the ghost on it. So now I wanna make it orange and
已经有鬼的表情在上面了，那就把背景色设为橙色
blank. So now I need to set the button's title, and I saw
然后不显示字。如果我想要设置按钮的标题
before that it was set title. Here it is, set title. Now
我之前看到了有 setTitle 可以实现，所以调用 setTitle
this set title has extra thing here, for UI control state.
setTitle 还有一个参数，for: UIControlState
You see that? It's like, what the heck is that?
看到了吗？你会想，那是什么鬼？
I don't know anything about buttons, so, I'm not sure.
我并不了解按钮，所以我不清楚那是什么
But I don't see any other set title, so I guess I'll have to
但并没有其他类似于 setTitle 的了，那估计
go with this one. Okay, so I double click on it. The title
我只能用这个了。好，我双击它
I want to set here, of course, is empty string because,
我想要设的标题当然是空字符串
I'm trying to do the back of the card here.
因为我想显示卡牌的背面
So I empty it out. And now I'm kind of at this control state
也就是把字清空。然后是这个 UIControlState
impasse, because I don't really know what this means.
陷入僵局了，我不知道那是什么意思
So, here's another cool thing you can do,
这时，我们可以做的另一件很酷的事情是
is hold down option and mouse over anything,
按住 option 键不放，然后把鼠标移动到上面
you see how it's highlighting things with a little question
看到那部分会被高亮，然后鼠标变为一个
mark right there? And you can click on it and it'll show you
问号了吗？你可以点击它，然后就会显示
the documentation for that thing. So here is set title,
那个东西的文档。所以这是 setTitle
the documentation for it. And if I read through this,
这个方法的文档。如果我读了这个
the third paragraph and description says,
第三段的描述说
at a minimum, you should set the value for
至少你需要设置 normal 状态下的标题
the normal state. Okay, sounds good. Now I'd like to
也就是普通状态的标题。好，听起来不错
understand how to get that normal state, so I'm gonna
现在我想知道如何得到那个普通状态
actually click on this link here, you see UIControlState?
所以我点击这个链接，看到 UIControlState 是个链接了吗？
And it's gonna take me to the documentation and
它会带我到文档里
show me control state. So here we go, click brings up
给我展示 UIControlState 的信息。我点下去
the documentation, here's control state, see that? And
文档就出来了，UIControlState，看到了吗？
here it is normal, the very first one is called normal.
这里是 normal，第一个就是普通状态
And we're gonna see later how we use these things but
等会儿我们会看到怎么使用这些
this is a static, you see it's a static var.
但是这里有 static，这是静态变量
So it's kind of a property of the type, and so
就像是属于类型的属性
the way that we will type that in is to say,
所以我们输入这个的方法是
UIControlState.normal. So it's awesome, we found that, but
UIControlState.normal。很好，我们找到了普通状态
while I'm here in the documentation,
但当我还在文档里的时候
let me briefly show you how the documentation works.
让我简单介绍一下文档是怎么用的
Right here, you can see that I'm looking in UI kits
这里说我们看的是 UIKit
at its views and controls at the class UIControl, which
视图（view）和控件（control）
button inherits from. And we're looking at this thing,
也就是按钮继承的父类所在的地方，然后我们看的是
UIControlState. But I can click anywhere here and
UIControlState，控件的状态。但我可以随便点击
go back and maybe look at UIButton if I want. And here's
如果我想的话，比如回去看看 UIButton，然后这就是
UIButton. Now, when you're looking at the documentation,
UIButton 的文档。当你看文档的时候
I super strongly recommend you read these overview sections.
我强烈建议你读读概述的部分
You see where this says Overview?
看到这里写着是 Overview 了吗？
This overview section in each class,
每个类的概述
only take you five minutes to read. And it's really
只需要大概五分钟的阅读时间，但是非常有用
gonna help you understand what the heck is going on here.
能帮助你理解这都是些什么东西
So, I strongly recommend you do that for
所以我强烈建议你这样做
all the common classes that you're using, UIButton later
所有你用到的常有的类，比如 UIButton
we're gonna do array in dictionary. Go read it so
之后的 Array（数组）和 Dictionary（字典），去读读
you understand what the heck is going on in here. Got that?
这样你就理解这些内容了。清楚了吗？
You can also search the documentation of course here.
当然你还可以直接在这里搜索文档
And in addition to overview it has a list of all the methods.
除了概述之外还有方法列表
And here, for example,
比如说这里
here is set title again. Go back and see if it's the same
这是 setTitle 方法，然后点进去还是一样的内容
that shows up in that little box. So now we know that this
和那个小弹窗里的文档一样。所以现在我们知道
control state here is supposed too be UIControlState.normal.
这里控件的状态应该是 UIControlState.normal
It's gonna set the normal control state. We also want to
他会设置普通状态下的标题。我们还想
set the background color so I'm going to do button dot and
设置背景颜色，所以我用 button.
I'm gonna just take a flyer, backgroundcolor.
我就碰碰运气，backgroundColor，背景色
Sure enough, look backgroundColor or something,
没错，还真有 backgroundColor
exactly called backgroundColor that takes a UI color,
就叫做 backgroundColor，类型是 UIColor?
I think? Let's double click that one. And
难道不是吗？让我们双击这个
I'm gonna set that equal to, believe it or not you can
然后赋值为，不管你信不信，你可以
actually put a color literal in here. You just
直接放一个颜色在这里
do that by starting to type the word color, and you're
你只需要输入 color，然后你看
gonna see the first choice is always Color Literal.
第一个选项 Color Literal 就是字面值颜色
If you double click on that,
如果我双击它
it puts a little square in here.
Xcode 就会放一个小方框在这里
If you click on the square you can pick the color you want.
你可以点击这个方框，然后选择一个你想要的颜色
So let's go back and pick our nice orange,
我们就选这个很不错的橙色
cuz that's what we do in the background.
因为这就是我们想要的背景色
And so, we've set our background color to orange.
所以我们就把背景色设为橙色了
And it's really nice to be able to see that in your code.
能在代码里看到实际的颜色是很棒的功能
It really highlights the colors you're using.
能够凸显出你想用的具体是什么颜色
All right otherwise if it's not, doesn't have the ghost
好，那如果没有显示鬼这个表情的话
right now then we want to put the ghost on there.
那我们就把鬼显示出来
So I'm gonna do pretty much exactly the same code here.
我用的基本上是同样的代码
It's just that I'm gonna set the title instead of blank,
还是 setTitle，只不过不是空字符串
like the background. I'm gonna set it to the emoji,
也就是上面的那样，而是设为 emoji
the ghost in this case. And I'm gonna double click on this
这种情况下是鬼的表情。然后我双击
orange square and change it to white, because I want a white
这个橙色的方块，然后改成白色的，因为我想要
background for the front. We got that? Okay,
卡前面是白色背景。看懂了吗？好
let's run, see if our card. Our card should flip over now,
让我们再来运行看看我们的卡片。我们的卡片应该可以翻过来了
which is getting us quite a long way along the path here
虽然我们花了点功夫才实现
to getting concentration working. Right here is
才能玩这个翻牌游戏。这里是
our ghost. Cross your fingers. Whoo, it flips over and
我们的鬼表情。上帝保佑，我要点了。哇哦！翻过去了
back. Okay, excellent. All right, we're on a roll.
很好，我们成功了
Now, let's go and
现在让我们
add another card. Okay, we got one card. Let's go to
添加另外一张卡。这是我们现在的一张卡
the second card. Believe it or not, you can take things in
然后第二张卡，不管你信不信，你可以选择这张卡
Interface Builder that are the way you want it and
选中 Interface Builder 里的这个
just copy and paste them. So now I have two cards and
然后复制粘贴。现在我有了两张卡
this card already is the right shape that I want,
这张卡的形状已经是我想要的了
it's got the right font size all that stuff.
字体大小等也都没有问题
So it's really recommended to copy and paste verses dragging
所以我建议你复制粘贴，而不是
out a new one and trying to set it to all the same thing.
重新拉出来一个，然后尝试修改为一摸一样的
Just copy and paste.
你就复制粘贴就好
Now this one wants a different thing on it, so let's do
但是这个上面的表情应该是不一样的，让我们用
something like pumpkin. Yeah, well we could do a pump and
比如说南瓜怎么样？好，我们可以
now we'll do pumpkin, all right? So we got pumpkin.
我们就用南瓜
So we had pumpkin card and we got a ghost card.
我们有了南瓜卡和鬼卡
Now this pumpkin card, it needs a method.
现在这个南瓜卡需要一个方法
So we're gonna Ctrl+drag to create another method.
所以我们按住 control 拖拽来创建另一个方法
So if you missed it the first time, this is how we do it.
如果你第一次没记住，我再来演示下怎么做
It's an action. I'm gonna call this touchSecondCard.
选择 Action，操作方法，叫做 touchSecondCard
The type, of course, we want a UI button, argument sender.
类型，当然选 UIButton，Argument 是 Sender 作为参数
Connect it, here it is. I'm gonna take this
Connect 来关联它。然后我就把
exact same code from here, put it down here,
这段代码复制粘贴过来
but instead of the ghost right here, I'm gonna use our pumpkin.
但是不是鬼的表情，而是用这个南瓜
Okay, looks good, right? This could not possibly go wrong,
好，很好，是吧？这个可能有问题
this is so simple. It's gotta work,
非常简单，应该可以用
okay, let's do it. All right, here we go,
好，让我们来运行试试
the ghost still working like a charm. And a Pumpkin, pumpkin
鬼这个没有问题。然后南瓜，南瓜，南瓜
not working. Okay, what is wrong with our pumpkin?
并没有用。那南瓜这个有什么问题呢？
How could this pumpkin possibly not be right. Well,
这个换成了南瓜怎么就不行了呢？
we could get in the debugger here, set a breakpoint,
那让我们把调试器显示出来，是一个断点（breakpoint）
it's real easy to set a breakpoint by the way.
顺便说下设置断点很容易
You just click on a line number,
只需要点击行号就可以了
puts the breakpoint there. But
就会在那里设一个断点
we're gonna do a little more lightweight debugging.
但我这会儿用个更简单的调试方法
I'm just going to put a print here in flipCard, to see if
我就在 flipCard 里加一个 print 来看
this is even calling flipCard. It should be calling flipCard,
它是否调用了 flipCard。应该是会调用的
because it's connected here to this method, so it should be
因为它关联了这个方法，所以应该
calling flipCard. So I'm just gonna go in here and
调用 flipCard 方法了的。所以我在这里
say print, that I'm in flipCard withEmoji. And
用 print 函数说我在 "flipCard(withEmoji: 里
now I wanna put this emoji in here. Now,
现在我想要把这个 emoji 表情加到这里
in a lot of other languages, you would probably say %s,
在其他的语言里，你可能会用 %s
comma, emoji, or something like that, right?
%s)", emoji 之类的，是吧？
This would be your, oops, this would be your string.
然后这就是你的字符串
But we don't have this %s business in Swift,
但是 Swift 里不会和 %s 一类的打交道
we have something better, which is\(). So
我们用更好的 \() 来实现字符串插值
\() means put something inside there, it's gonna interpret it
\() 可以让我们在括号里放一些东西，然后把它
as a string, and embed it in this string. So that's exactly
作为一个字符串插入到这个字符串里。这就是
what we want, emoji, and the cool thing about it is,
我们想要的，把 emoji 放进去。更酷的是
I could put, this is a string, so it's easy to embed.
虽然我这里 emoji 是字符串，插入到字符串里并不难
But I could put an Int here, anything that can be converted
但是我还可以放一个整数在这里，任何能转化
to a string, which most things in Swift can, I can put there,
为字符串的都可以，也就是说 Swift 里大部分的我都能放进去
I can even put an array there, or a dictionary.
我设置可以放个数组或是字典在这里
As long as the array only had things that could
当然前提是数组里的内容要能够
be converted to a string, then it can convert the whole
用字符串来表示，那它就会把整个都转换
array to a string. So this is a really cool feature,
把数组变成字符串。这是个很厉害的特性
this\(), all right? So let's run again, and
能用 \() 实现字符串插值。让我们再次运行
see if that pumpkin is calling flipCard, which it should be.
然后看看南瓜卡是否按照预期调用了 flipCard
All right, so the ghost, it's definitely calling it,
好，鬼卡，肯定是调用了的
see flipCard withEmoji, the ghost, how about the pumpkin?
看这个 flipCard(withEmoji: 鬼表情)，那南瓜呢？
It looks like it's calling it, but I didn't press that twice,
看起来是调用了的，但是我并没有按两下
what's going on there? That that's kinda weird,
但为什么多了两行呢？这有点奇怪
let's do it again. No look at that, it's doing both.
让我们再试试。看看，它两个表情都有
Every time I press the pumpkin,
每次我按下南瓜
it's doing the ghost and the pumpkin, ghost and
同时会出现鬼和南瓜，鬼和南瓜
pumpkin. Why is it doing it twice, okay,
为什么会调用两次呢？
that's clearly they're messing things up badly.
我们肯定是搞砸了
Well, let's look and see why it's doing that. We know that
让我们来看看为什么会变成这样。我们知道
this method is being called by the pumpkin. And
touchSecondCard 被南瓜卡调用了
this method is being called by both. that's the problem.
touchCard 被两张卡都调用了，这就是问题所在
And why did that happen, cuz I copied and pasted the ghost.
为什么会这样呢？因为我复制粘贴了鬼
And when I copied and pasted the ghost, it copied and
当我复制粘贴鬼的时候，他还复制
pasted the fact that it was sending that message. So
粘贴了它要发送的消息
this is a common mistake to make,
这是很容易犯的错误
really easy. So I did it intentionally to show you how
非常容易，所以我故意错给你看
to get out of this, which is to right-click on something.
教你如何解决这个问题——那就是右键点击
If you right-click on anything in the UI, it will show you
如果你右键点击 Interface Builder 里的东西，就会显示
all the connections that it has. So this is the pumpkin,
它所有的关联。所以这个是南瓜卡的关联
it's sending touchCard and touchSecondCard, but
它会调用 touchCard 和 touchSecondCard
we only want it to send touchSecondCard. So
但我们只想要它调用 touchSecondCard
I'm gonna disconnect touchCard by clicking right here.
所以我要通过点这个叉来取消关联
Now I fixed it, okay, now the pumpkin is sending this,
现在我解决了问题，南瓜卡只会发这一个消息
and only the ghost is sending this. So right-click is
而这个方法也只有鬼卡会调用。所以右键
an important thing to know, if you ever get in a situation
非常重要的，你需要了解。如果你遇到的
where it seems like,
那种情况你觉得是
I thought I wired that up, why is it not sending it?
你应该关联了却没有发送消息
Or even why is it crashing trying to send something that
或者是尝试发送消息的时候意外崩溃
I didn't intend? Right-click on it, will tell you why.
那就右键点击看看是什么原因
So let's run, see if that indeed fixed our problem here,
让我们再来运行看看是否解决了我们这里的问题
I imagine it will. Okay, it's got the ghost flipping over,
我觉得已经可以了。好，鬼卡翻过去了
we got the pumpkin flipping over, okay, excellent,
我们让南瓜卡也翻过去，很好
all going great. Now before I add yet more cards, I want to
一切正常。但在我加另外一张卡之前，我想要
have some UI that tells me how many times I've flipped cards.
在界面里显示我翻过了多少张牌
Because you notice in this game,
因为注意这个游戏
the fewer times I flip it, the better I am at it, right?
翻牌的次数越少，我就算是玩的越好，对吧？
If I flipped them all over, up and down,
如果我挨个都翻过了，翻过去翻过来
up and down, then I'm not very good, it's easy,
翻过去翻过来，那可不好，太简单了
I didn't have to concentrate. So I wanna have some UI that
我并不需要集中注意力，所以我希望界面
says how many times I've flipped a card, okay? So to do
能够显示我翻了多少张卡了
that I'm gonna start, let's get rid of this print in here,
那开始，我先把 print 删掉
we don't need that debugging anymore. So I'm gonna
我们不需要继续调试了
start by adding an instance variable to my class that
我在类里添加一个实例变量
keeps track of the flip count, okay, real, real simple like.
来记录翻了多少次，非常简单
Move this down here so we can get some space, all right?
让我打几个回车来腾点空间
So what does it look like to add an instance variable to
那如何才能够在类里面添加实例变量呢？
your class? Really simple, you use the keyword var, short for
非常简单，用关键字 var
variable. Then the name flipCount, then the type,
变量 variable 的缩写，然后名字是 flipCount
: Int, that's it. So I have added here a variable called
然后 : Int 说明这是整数。就这样，我就添加了一个变量
flipCount to my class, and I'm gonna keep that flipCount up
我的类里有了叫做 flipCount 的变量，然后
to date as these cards are flipped on. But,
每翻一次牌就更新 更新 flipCount
look what happened here, I had an error. So this red, when
但是看看发生了什么，提示有个错误。所以这个红色的
you have a red error, your app won't even compile and run.
当你看到红色的错误，你的程序不能编译，也不能运行
You can also get a yellow one, then your app will compile and
你还可能遇到黄色的警告，你的程序能编译
run, but do not submit your homework with yellow ones
能运行，但你交的作业两个都不能有
either. Even though they're just warnings,
即使只是警告
they are usually indicator something bad, so
但那说明肯定有问题
don't do that either. But this red, I gotta fix this red.
所以不能有警告。但这个是红色的，我必须解决这个错误
Now what's funny is this red came up on a different line of
但有趣的是红色的这一条出现在另一行
code. I typed this line of code in, and it came up on
我输入的是这一行代码，但是出现在
a completely different line. Well what does this say here,
完全不同的一行。那说的是什么呢？
it says, class ViewController has no initializers.
它说 ViewController 类没有构造器（initializer）
Why is it saying that, what does that have to do with it?
为什么会这么说呢？这和我这行代码有什么关系？
Well, this is happening because Swift requires
其实原因是 Swift 要求
all instance variables, which by the way in Swift,
所有的实例变量，顺便一提 Swift
we call instance variables properties.
把实例变量叫做属性（property)
So when you hear me saying property,
所以当你听到我用 property 属性
I mean instance variable. So all instance variables,
我指的就是实例变量。Swift 要求所有实例变量
all properties have to be initialized,
所有属性都要初始化
you are not allowed to have them like this flipCount int.
你不能只是写 flipCount: Int
What is the value right now? It has no value, okay,
flipCount 的值是多少？没有值
it has to have an initial value,
所以必须要有初始值
it's just not allowed to be sitting out there. Now there's
不能够就只定义就完了
two ways to initialize an instance variable,
有两种办法可以初始化实例变量
one is using an initializer. So that's what this error is
其一是使用构造器，这就是这个错误
trying to tell us, get an initializer here, dude.
想要告诉我们的，写个构造器
An initializer is just this method with a special name,
构造器就是个特殊的方法，有一个特殊的名字
init, short for initializer, and
init，initializer 的缩写
it can have any arguments you want. In fact,
可以有任何类型和数量的参数。事实上
you can have multiple inits, each with different arguments.
你还可以有多个构造器，每个的参数不一样
But each init is responsible for initializing
但是每一个构造器都要负责初始化
all of the variables, okay, that's what the init's job is.
所有的实例变量，这就是构造器的作用
So we could add an initializer here and do that.
所以我们可以添加一个构造器
Now, unfortunately, adding an initializer to a class can be
但是给一个类添加构造器
kinda complicated because of inheritance, right?
可能会因为继承而变得复杂，对吧？
Because your superclass has initializers,
因为你的父类有构造器
you gotta make sure they get called properly.
你需要确保正确调用它们
So I'm not even gonna talk about initializers yet, okay,
所以我先不讲构造器
I'll talk a little bit about them on Wednesday. Next week
我星期三会多讲一些。下一周
we'll really talk more in depth about initializers. And
我们会更深入地讲解构造器。同时
so what's the second way that I can initialize this,
我们还有第二种方法初始化它
since I don't wanna do initializers right now?
毕竟我不想用构造器
And that's just right here to say, = 0, okay,
这个方法就是用 = 0 来赋值为零
if I just, why do I keep pressing v there, okay,
为啥我打了个 v，应该是空格
Int = 0, okay. That initializes this,
好，: Int = 0，就能初始化了
that's gonna cause this error to go away, all is well. And
这样错误就消失了
this is how we initialize most of our instance variables.
这也是我们大部分时间用来初始化实例变量的方法
Now while I'm here, talking about instance variables,
既然我讲到了这里，让我继续讲讲实例变量
I wanna talk a little bit about Swift and typing.
我想多讲讲 Swift 和类型
Swift is an extremely strongly typed language,
Swift 是个非常强类型的语言
I mean extreme. It does have a type which is kind of like
极端的强类型。虽然有类型代表
untyped, but really it's mostly for
没有类型，但那是为了
backwards compatibility with Objective-C. In most cases you
向后兼容 Objective-C。大部分时候
want to be very specific about what types you're using,
你应该明确你用的是什么类型
and some people complain about strongly typed languages. It's
有些人会因此抱怨强类型语言
so much burden to always be typing something. Okay, well
主要是觉得总是要输入类型太恼火了。所以
Swift is also a language that has strong type inference,
Swift 同时还有强大的类型推导
which means it will, if it can, guess the type for you.
也就是能够帮你猜出类型是什么
So in this case, you see I have this : Int type,
比如这个地方，我用了 : Int 来声明类型
that is completely unnecessary in Swift. And
这在 Swift 里是完全没有必要的
not only unnecessary, we would not put it in there, there is
而且不仅是不必要，我们根本就不会放在那里
no reason to put that there. Why is that, because this 0 is
根本没有理由放在那里。为什么？因为这个 0
clearly an Int. Swift treats all literals like this,
说明了它就是整数。Swift 对于所有的字面值都是这样处理的
that don't have any decimal points as Ints. And
这个没有小数点，所以是 Int 类型
so this is an Int, and how do we know that? If we hold down
我们如何确认这是 Int 类型呢？我们按住
Option, just like we did when we clicked on Title down here
option 键不放，然后就像我们点击 setTitle 一样
to get the documentation, we can click on flipCount, and
我们点击 flipCount 就可以得到文档
it'll say flipCount is an Int. You see that, and if I
然后它说 flipCount 是整数类型的，看到了吧
had said flipCount was 0.0, then if I hold down option and
如果我说 flipCount = 0.0，我再按住 option 键
go back here to flipCount, it says flipCount is a double,
点击 flipCount，就会说他是 Double 双精度小数
okay? So into, it infers it, if I said flipCount equals
所以它能推测出来。如果 flipCard = "hello"
"hello", it's going to say okay,
那它就会说
flipCount is a string All right, so it's gonna infer.
flipCount 是个字符串。所以 Swift 能推导出类型
Now, this is easy to infer cause this is a constant but
可以说因为它是常量，所以很容易推测
swift can even infer in the most amazing complicated
但是 Swift 甚至能在非常复杂的情况下
situations. If there's only one type that thing can be,
推测类型。如果只可能是一种类型的话
it'll make it that type and
Swift 就认为它是那个类型
you don't have to put the types.
你不需要声明类型
So it's surprising in Swift. The time you put types in
这是 Swift 很惊人的一点。你输入类型最多的
the most is arguments to functions. Because that you
是声明函数参数的类型，因为
kind of have to say what, what you're expecting there. But
你必须交代你期待的是什么类型
otherwise you rarely are actually putting the types.
其他情况下你都基本不用声明类型的
It's quite amazing, actually. All right, so we have this
这还挺神奇的。好，我们有了
flip count here. Let's go ahead and increment it. K,
这里的 flipCount 来计数，我们这就来增加它
every time someone steps, presses on a card I'm gonna
每次有人点了一张卡
say flip count plus equals one and ug I'm gonna copy and
我就 flipCount += 1 来增加一
paste the code. God. Anytime you're copying and
然后我复制粘贴代码。天呐。每次你
pasting code, you're doing it wrong.
复制粘贴，那就是做错了
Okay, that can't be right. So I just did something that's
不应该是这样的，即使我做了不该做的事
not right but I'm doing it anyway. I could probably put
但我还是要这样。我应该可以
that somewhere else but I'm gonna just.
把它放到其他地方，但是我就
We'll do it this way for now. You'll see why in a second and
我们现在就这样了。你等会就知道为什么了
we'll fix it. But we don't want to complicate the code.
然后我们再来解决它，总之我们不想有复杂的代码
But each time a card is touched,
总之每次点击一张卡片
I'm gonna increment the flip count. Now that's great, but
我就增加 flipCount。这很好，但是
I need this flip count to appear in the UI,
我需要在界面上显示翻的次数
okay. I want the user to see how many flips they've made.
我希望用户看到他们翻了多少次
So I have to have this int
所以我需要有这个整数
appear in the UI. So how do I do that? Well,
出现在用户界面里。我怎么做呢？
I need some sort of other UI element besides a button And
我需要不是按钮的 UI 控件
that's just a little text field. Okay, in fact there's
它只是一个标签显示些文字。那么事实上
a read-only text field which is called the UILabel in iOS.
iOS 里只读的文本框叫做 UILabel
And so of course anytime we wanna add something to UI,
所以每当我们想往 UI 里添加标签的时候
I go here, to the bottom side, in fact right next to button,
我到右边，下面这里，就在按钮旁边
here is label. I'll drag it out and put it in here.
标签就是这个 Label。我把它拖出来放到这里
I'll try and center it or something like that.
我会尝试把它放在中间，就像这样
It's really really small so I'm gonna make it much bigger
现在它太小了，我要把它拉宽一点
cuz I'm gonna be using big font in a second here.
因为等会儿要选一个大一点的字号
Even make it taller. The text is black so
然后拉高一点。因为现在字是黑色的
it's black on black. That's a little hard to see so
黑底黑字，所以很难看见字
I'm gonna go back over to here, go to the top half here,
然我回到这里，右边的上半部分
change the color of the text, okay,
更改字的颜色
which is a label property right here. From this,
也就是标签的一个属性，在这里
to our favorite color, orange. This text is really small, so
把它改为我们最喜欢的颜色，橙色。这个字很小，所以
I'm going to change the font from 17pt,
我要把字从 17 点
which is the default here, to something like 40.
也就是默认值，改为 40
Much better. I don't want it to say label here,
这下好了。还有我不想要它显示 label
I want it to say Flips, let's say we'll start out Flips: 0.
我想让它显示翻了多少次，那一开始就是 Flips: 0
I don't want it left-aligned like that, okay,
我不希望是左对齐
I don't want the text left-aligned,
我不希望字都靠在左边
I want it in the center, so I go over here and hit center.
我希望他们能居中，所以我在这里选择居中
So see how I'm just using this editing inspecting up here to
所以我只用了这个检查器来编辑
kinda get the thing to look the way I want it to look.
让它看起来像我想要的那样
I can even use my dashed blue lines here to
我还可以用这些蓝色的虚线做参考
put it right along the bottom and right in the center. Okay.
把它放到下面的正中央
Even though I said we are not really using those,
虽然我说我们并没有真正用上参考线
it's still useful to do that one.
但还是有意义的
All right, so
好
now I have my UI, how do I talk to it? How do I tell it
现在我的 UI 构建好了，我怎么和它沟通呢？我如何告诉他
when the flips change to show the flips? Well, I'm gonna
当翻的次数改变了之后就更新显示新的翻的次数？
do that also by making connections between my UI and
我可以通过关联 UI 到代码来实现这个
my code. And we know how to do that, Ctrl drag Right?
我们是知道要怎么做的，按住 control 拖拽，对吧？
Ctrl+Drag, put it right here. And this time,
按 control，拖到这里来。这一次
though, I'm not doing an action, I'm doing an outlet.
我不会选 Action，我要选 Outlet，出口
And what an outlet does is it creates an instance variable.
出口就是创建一个实例变量
So action creates a method,
所以 action 创建一个方法
Outlet creates an instance variable or property and
outlet 出口创建一个实例变量，也就是属性
that property is gonna point to this UI label and
那个属性会指向这个 UILabel
I'll be able to talk to it and
这样我就能跟他交流
tell it to update itself when the flips change. All right,
告诉它翻的次数改变了就更新
so what am I gonna call the name of this thing, I'll
那我给他取个什么名字好呢？
call this my flipCountLabel, it got the type right here
我叫它 flipCountLabel。这次类型是对了
didn't see any. Don't worry about this storage week.
并不是 Any。现在不用管 strong 和 weak
I'm gonna talk about that next week. And so
这个我下周讲
I'm gonna hit connect and it's gonna create another var.
现在我点击 Connect，它就创建了另一个变量
Like var flipCount. But this var is gonna be a little
就像 var flipCount 一样，但这个会有些不一样
different. This var is, sorry wrong place there.
这个变量，啊，点错地方了
This var is var flipCountLabel: UILabel!
这个是 var flipCountLabel: UILabel!
Okay? Now you can't infer this type by the way because
这个你不能推测类型
that UILabel is in the UI. So Swift doesn't know how to look in
因为这个 UILabel 是在用户界面上的。Swift 不知道
the UI and infer a label so it can't infer that there.
如何看着你的界面设计就推导出你这是个 UILabel，做不到的
So we do need to explicitly say it to UI label here. Week,
所以这里我们需要明确说明是 UILabel
I told you to look, we'll tell you next week.
weak 就像我说的，下周讲
This is another kind of directive like this one that
@IBOutlet 也是一个修饰变量的特殊指令，就像 @IBAction 一样
puts the little dot there so that we can see that's that,
在这里放了一个小圆圈，看到这个和这个关联
that's that, that's that. Okay, so here's the var,
这两个是关联的，这两个也是。好，回到我们这里的变量
exactly the same as we did with flip count.
就像我们的 flipCount 一样
Notice there's a little exclamation point there. That
注意我们这后面有感叹号
is super important. But I'm not gonna talk about it today.
这非常重要，但我今天不会讲
I can't talk about everything all at once. Notice that this
我不能一次把所有内容都讲完。注意这个
very important thing also has a side effect.
非常重要的感叹号是有副作用的
It's not the primary purpose of it but
虽然并不是它存在的主要目的
the side effect is. It doesn't have to be initialized.
但是副作用是，如果 flipCountLabel 没有初始化
notice this doesn't say equals anything and yet
注意它还没有被赋初值
we don't have an error. Okay? So don't freak out about that.
但我们并没有得到任何错误。你们不用为此担心
I'm gonna talk all about this exclamation point.
我会讲关于感叹号的内容的
It could not be more important,
没有比这更重要的了
probably the most important newish
可能是最重要的
thing that you're going to learn about Swift, okay,
你需要学习的关于 Swift 的新知识
is what its all about. All right, so I got this flip
这就是这段代码的意思。好，我有了
count label right here. Now, all I want to do is,
这里的 flipCountLabel，我想要的是
every time this flip count changes, like, right here.
每次 flipCount 改变了，比如这里
I'm going to talk to the flip count label and I want to set
我想要告诉 flipCountLabel 说
it's text, label. I want to set it's text, so I'm going to
我想要改变它显示的字，设置这个 flipCountLabel 的字
send it a message and I want to set text, so I'm just going
所以给它发消息说我想设置显示的字
to say text. There happens to be something called text,
那就是 text，正好有叫 text 的属性
the very first one there. You see that?
第一个就是，看到了吗？
It says text as a string, so I'm going to double click on
它说 text 是个字符串，所以我双击
that All right and I'm gonna set that text to, Flips:,
好，我把字赋值为 "Flips: "
and then I'm gonna use my favorite feature right here,
然后我要用我最喜欢的特性
\(). And I'm gonna put the flipCount in there. So
\(flipCount) 来插入翻牌的次数到这里
that's gonna change the text on this flipCountLabel here,
所以这就会更改 flipCountLabel 显示的字
and we'll see Flips: 1, so it's going to whatever And
我们就能看到 Flips: 1，然后一直加下去
of course, I have to copy and paste again right
当然，我需要复制粘贴一份
there because I need to update it each time. So,
因为每次更改 flipCount 都要更新
let's see if
让我们看看
this works.
这能不能用
Okay, here we go. Let's try to flipping this card. Ooh, yeah.
好，出来了，我们试试翻这张卡，好
Everytime we flipped over our back.
每次我们翻的时候
It's incrementing the flip count. Okay, fantastic.
它就会把 flipCount 计数器加一。很好
Except this really is nasty. I just copy and pasted.
除了我们的代码很糟糕都好。我只是在复制粘贴
I mean, imagine I really was doing it this way and
假设我就这样做
I had another button called New Game and
然后有了另一个按钮，叫做 newGame
I had to set the flip count back to zero.
开始新游戏要把 flipCount 重置为零
I'm going to have to put this same line of code there to.
我需要把同样的代码放在那里
And what if some day I said, well,
然后如果我有一天决定
I don't want this to say flip, I want it to say flip count.
我不想要它显示 Flips，我想显示 Flip Count
Now I've got to change it all three places.
那我三个地方全都要改
This is just horrendous coding.
这简直是糟糕透了的代码
Luckily, in Swift, there is a way to avoid doing this in
幸好 Swift 有一种方法能避免这个
this case, which is that any property, if you want,
如果你想的话，任何的属性
you can put code after it that says, did set. And it will
都可以放代码在后面的 didSet 里
execute this code every time that thing gets set. Okay?
每次那个变量的值发生改变之后，这些代码就会运行
That's called a property observer. Because this code is
这叫做属性观察器，因为这些代码
observing changes of this. So we can take this outta here,
会观察这个变量的改变。所以我们把这些代码拿出来
put it up here, and we can take it away from here now.
放到上面这里，我们就可以把它从这里删掉了
Every time flip count changes, it's going to Execute that
每次 flipCount 改变之后，就会运行
didSet, and talk to the label, and update it.
didSet 里的代码，然后告诉标签让它更新文字
So now if I add a new game and set flip count equals zero,
如果我添加个 newGame 设 flipCount 为零
it would automatically update it.
他也会自动更新
Property observer is really cool.
属性观察期非常厉害
Obviously we use property observers a lot to keep the UI
显然我们会经常用属性观察器来让 UI
in sync with the instance variables of our class. Okay,
和我们类里的实例变量保持同步
so you'll see that happening all the time. All right, time
你总是会看到他们。好
to get more buttons. We got these two buttons. By the way,
让我们多加一些按钮。我们有这两个按钮
notice that we're driving our UI from the code, right?
注意我们应该是用代码来驱动用户界面的
It's this line of code that's saying what's in the UI.
这一行代码决定了界面上显示什么
So I'm actually gonna change these two buttons to be
所以我让这两个按钮改为
face down.
面朝下
Okay when they start. And what's interesting is if I
一开始的时候是这样的。注意有趣的是
select them both, and go over to the top here of this thing,
如果我两个同时选中，到右边上面这里
notice it notices they're both buttons. So
注意他们都是按钮
I can change things, like here it says multiple values for
所以我可以更改，比如说这里的目前有多个值
the text, ghost and the pumpkin.
的文字属性，鬼和南瓜
I can set that to blank, and I can go down to the bottom and
我可以都设为空白，我可以到下面
set the background color here to orange And it's affecting
把背景色改为橙色，于是同时更改了
both of them. So if you select multiple things,
这两个。所以如果你有很多个东西
as long as they're of the same, they share the same
只要他们是同一类型的
type, then you can edit them all simultaneously.
你就可以所有的一起编辑
Okay. So I have these cards, let's make some more cards.
好，我有了这些卡，让我来创造更多的卡
I'm going to copy and paste these cards. Actually,
我复制粘贴这些卡，但事实上
before I do that, let's do one other thing.
在那之前，我们先做另一件事
I'm pretty unhappy with my architecture here,
我很不喜欢我这里的架构
because if I wanna add more cards I guess I'm gonna have
因为如果我添加更多的卡片的话我需要
to do copy, touch third card, fourth card, fifth card,
复制粘贴出按下第三张，第四张，第五张卡
sixth card, seventh card, eight card, nine, okay.
第六张，第七张，第八张，第九张的方法
That is gonna be the worst code, you would get an F on
那就会成为很糟糕的代码了，然后你的作业会是不及格
your homework if you did that. That's just awful, so we're
如果你的代码是那样的话，那太差劲了
clearly not gonna use that architecture to do that and
所以明显我们不会用这种结构来实现
in fact I want to get rid of this touch second card
其实我也想删掉 touchSecondCard 方法
entirely, and I just want to put everything in touch card.
完全删掉，然后所有的都放到 touchCard 里
And that means I won't have this line of code duplicated
这就是说我不用重复这一行代码
and this line of code duplicated.
和这一行代码
This is gonna be great. This is much better, UI.
这样就很好，好多了
So to do this I'm gonna right click on this one and
那要这样做，我需要右键点击它
disconnect touch second card and instead have this guy
取消关联 touchSecondCard，取而代之
ctrl-drag to here. Look at that you can hook it up to one
按 control 拖拽到 touchCard 方法。看，你可以关联
that already exist by just dragging to it and
已经存在的方法，只需要按 control 拖拽过去
letting go. So now both of these are sending touchCard.
然后在方法上松开。现在两个按钮都发送给 touchCard
Okay, so that's great but inside here we
很好，但是在这里面
obviously can't do this. Have this ghost thing here,
显然我们不能这么做，用这个鬼作为参数
because then it would set both cards to ghost. So how are we
因为两张卡都会被设为鬼，那我们
gonna have code in here in touch card, that works for
怎么样让 touchCard 里面的代码适用于
all the cards? Well what I'm gonna do is I'm gonna create
所有的卡片呢？我要做的是我会创建
an array of all these cards and when touchCard is pressed,
一个这些卡片的数组，当按下去之后 touchCard 被调用了
I'm gonna look in that array, find the button that's being
我就在数组里面找，找到那个被按下的按钮
pressed, and then I'll know which card it is. Then, when I
然后我就知道是哪张卡片了
know which card it is, which index it is in the array.
既然我知道了是哪张卡，知道了它的索引（index）
I'm going to lookup in another array, the emoji to put there.
我就到另一个数组里去找到对应的表情显示出来
So, it's going to be data driven. Right, and so
也就是由数据驱动。好
if I want to add more cards,
我想要添加更多的卡
I just add more cards to my emoji array.
就只用往两个数组里加更多的卡就行了
It's going to be great. All right, so
这样程序会变得很好
let's make more cards. I'm going to copy and
让我们来加上更多的卡，复制
paste to make more cards, so I have four cards and
粘贴出更多的卡，现在我有了四张
now I wanna make an array that includes these cards, okay.
现在我想要一个包含这四张卡的数组
So how do I do an array that include these cards?
那我怎么创建一个包含这些卡的数组呢？
Well, that's a connection between the UI and the codes.
嘛，这需要关联用户界面和代码
So I'm gonna control, drag and create another var right here.
所以我按住 control 拖拽过来创建另一个变量
Okay, but this one's gonna be the third kind which is outlet
但是这个我们选第三中类型，outlet collection
collection. So now outlet collection means an array
出口集合就是一个数组
of the things in the UI. So I'll call this my cardButtons,
里面是些 UI 控件。我把数组叫做 cardButtons
I'm actually gonna make a mistake, okay and
等等，我要来故意犯个错，少个 t
say card butons instead of buttons,
叫他 cardButons 而不是 Buttons
because I want to show you how to fix this mistake if you do.
因为我想像你展示你遇到这种问题怎么解决
And it's got the type right, this is gonna be an array of
类型是正确的，UIButton 数组
UI button. Okay, so I'm gonna connect it right here and
然后点 Connect 建立关联
it created another var for me right here.
然后就创建了另一个变量
This one and look at its type. See that right there. That is
就这个。看看它的类型，[UIButton]
special syntax in Swift that means an array of UI button.
Swift 里表示数组的特殊语法，这是一个 UIButton 数组
This might look more familiar if I use another Swift syntax,
如果我用另一种 Swift 语法表示数组，你估计会更熟悉
array of UI button, that look familiar to
Array，这个看起来像 Java 里
you from Java, right? So array is a generic class, everyone
声明数组的语法吧？所以数组是泛型（generic）
know about generics in Java, hopefully. It means that
希望大家都知道 Java 里的泛型，意思是
you can't have the class array on its own be a type in Swift,
数组的元素可以是 Swift 里任何的类型
because I told you Swift is very strict about types.
因为我告诉过你 Swift 对类型很严格
So when you are putting things in and out of that array,
所以当你从数组里存取的时候
Swift would have a heart attack if it
如果它不知道你要把什么类型的值放进去的话
didn't know the type of thing you're putting in there. So
那 Swift 会吓个半死
when you create an array you have to specify what type of
所以你创建数组的时候要声明
thing is in the array so that Swift can breathe easy, okay.
数组元素的类型，这样 Swift 才能正常工作
Now arrays are so common that instead of using this
因为数组的是很常用的，所以与其用
normal Swift, this is normal Swift syntax right here, but
这个普通的 Array 语法
for arrays, we do this special thing here, where
我们实际是用特殊的 [元素类型] 语法
we say [UIButton]. It's just for arrays that we do this,
比如这个 [UIButton]。这个只是数组的特殊语法
dictionaries also have a special one, I'll show you
字典我们有另外的语法。我会给你看
that on Wednesday. Okay? So that's our array,
就星期三的时候吧？好，这是我们的数组
CardButons is array, now I have this cardButons here
现在我有了这个 cardButons 数组
okay, and this is connected to that one card, I haven't put
它和那一张卡关联上了，我还没有
the other cards in there yet but I will. It's connected to.
关联到其他的卡上，但我之后会的
Now what if I decided no, I don't want Butons,
现在我决定我不想要 Butons 少个 t
I made a mistake, it's Buttons and remember I told you,
我犯错了，其实是 Buttons。还记得我告诉你
you don't wanna edit things in here then also in the UI,
你不能只是更改代码，你需要同时更改 UI
okay like the name of the class and things like that.
比如要修改类的名称一类的
Well if you do that look what happened to the little circle.
如果你只改了代码，看看这个圆圈
Okay it doesn't have a dot in it anymore because
圆圈里的点没了
it's not connected anymore.
因为没有关联了
Because this, if I right click on it, it's connected to
因为我右键它，显示的是
Card Butons there, okay? It's not connected to Card Buttons.
关联的 cardButons 而不是 cardButtons
So, how can I fix this? If I said this Card Butons,
怎么解决这个问题呢？如果我改回 cardButons
okay it's back to being connected now and
它就又关联上了
I want to change this. It's another magic key.
但我想改名字。还有个神奇的按键
The command key. We all ready showed you the alt key for
command 键。我们已经展示了 alt/option 键
getting into the documentation.
可以显示文档
If you command click on something, k,
如果你按住 command 再点击
like this cardButons right here.
比如这个 cardButons
You get another kind of menu here that'll do some cool
你会得到另一个可以干很酷的事情的菜单
things like jump to the definition of this thing,
比如这里的 Jump to Definition 可以跳转到定义它的地方
which happens to be right here so
正好就是这一行
that's not gonna go anywhere. Show quick help,
所以并不会去其他地方。Show Quick Help
just like the option one does, and also rename and
会像按 option 键一样给文档。还可以重命名
when I click rename here, look at what happens.
我点这个 Rename，看看发生了什么
The UI kinda turns a little bit. It looks through my
Xcode 的界面发生了些变化，他会
entire project and finds that cardButons everywhere
从我整个项目里查找 cardButons 出现的每一个地方
including in my storyboard. See that? So now if I change
包括 storyboard 里的，看到了吗？所以现在如果我更改
this to cardButtons here, it changes it everywhere and
为 cardButtons 的话，它每个地方都会被修改了
now, this is not broken. And if I right-click on this,
现在这个就没有断开了，然后我右键这个
it cardButtons. So command click rename. That's how you
关联的是 cardButtons。总结一下，command，点击，Rename
want to rename things that touch both your UI and
这就是你想要同时重命名界面和代码的方法
your code. Right, so I've got this card buttons here. Now,
好，我们有了 cardButtons
I need to somehow in touch card, I need to
我需要在 touchCard 里
look into my card buttons array and find that button.
去 cardButtons 里找到那个按钮
Okay? By the way, before we do that, let me put the rest of
等等，在那之前，让我先把剩下的
these cards in there. I'm going to show you another way
这些卡片关联上。我再给你看看另一种
to connect up your UI to your code. It's this yellow button
关联 UI 到代码的方法。是这个黄色的按钮
right here. You see this yellow button at the top?
就这个，看到这个在顶上的黄色按钮了吗？
It says view controller. This button also represents your
说的是 View Controller。这个按钮也代表了你的代码
code. So, if you want to control drag from here,
所以如果你想从这里按 control 拖拽
you can do that as well and hook up to card buttons.
你也可以这样关联上 cardButtons
Control drag from here. CardButtons and I'm
从这里 control 拖拽，选 cardButtons
intentionally not gonna hook up this card cuz I'm gonna
我故意不关联这张卡，因为我要
show you what happens when we don't hook up a card. So
展示给你看不管连会发生什么
look at cardButtons, got those three cards and not this one,
看看 cardButtons，关联了这三个，但没有这一个
right. All right, so how am I gonna look in cardButtons for
好，那我怎么从 cardButtons 里找到呢？
mine? Well of course Swift array is a fantastic class.
当然 Swift 的字典是很神奇的类（注：结构体）
It's got so much great functionality and
它有很多强大的功能
one thing it knows how to do. Is look inside and
其中一个就是在数组里找到某个元素
tell you what the index is of something inside of it and
然后返回它在数组里的索引
that method is called index of all right. So let's just call
这个方法的名字就是 index(of:)。让我们来调用
that method, I'm gonna create a var called card number
这个方法。我要创建一个叫做 cardNumber 的变量
which I want to be the number the card 0,1,2,3,4 wherever it
也就是是第几张卡，比如 0，1，2，3，4
is in the array. I'm gonna set that equal to cardButtons dot,
就是在数组里的位置。我把它赋值为 cardButtons.
right sending a message card button index. Now interesting,
发送消息给 cardButtons.index 有趣的是
look how many methods are called index in array,
看看有多少数组的方法叫做 index
multiple methods. In Swift, that's perfectly legal. Swift,
Swift 里多个方法是可以重名的
you can have 100 methods all with the same index, but they
你可以有 100 个方法都叫 index，但是
all have to have different arguments. You see how all of
每一个都要有不同的参数。看到所有这些
these index methods have different arguments?
index 方法都有不同的参数吗？
All right, and they get the index after something,
比如某个索引之后的索引
index before something whatever.
某个索引之前的索引这些
I want this one down here index of something which is
我想要的这个 index(of:) 在下面
returns a int, okay, that's gonna be a problem that int,
返回的是 Int?。这个类型会成为一个问题
we're gonna see in a second here but
我们等会儿就会遇到
if I double click that, I've got the index here. So,
但我先双击使用它。我们有了 index 这个方法
I wanna find the index of the sender cuz I'm in touch card
我想要找到 sender 在数组里的索引，因为我按下的卡片
right here, so this sender and I'm just gonna print this out.
就在那里，然后我就直接把这个打印出来
So I'm gonna say card number equals and
print("cardNumber = \(cardNumber)")
we'll do our magic thing here, and
用了神奇的字符串插值
we will just print out the card number, okay.
然后打印出了是第几张卡
So before we go look in up in an array and find the emoji,
在我们到数组里找出表情符号之前
let's just make sure that we're finding the right card
我们先确认我们找到的是正确的卡片
right here. Now, right away I get two warnings here.
注意我马上就有了两个警告
Hm, let's go look at these warnings in depth.
让我们仔细研究下这两个警告
Let's make our whole screen show these warnings.
让我们全屏显示这两个警告
The first one is Variable cardNumber was never mutated.
第一个是说变量 cardNumber 从未被更改
Consider changing to let constant.
考虑改用 let 声明常量
What does that mean? Well indeed, cardNumber,
这是什么意思？确实，cardNumber
we give it an initial value here of looking up the card
我们通过查找给他赋了初值
in the card buttons array but we never change it again.
就没有从在 cardButtons 数组里的索引更改过
So it is not back in fact variable. It's a constant.
所以这就不是个变量，是个常量
Okay, and in Swift we always mark constants as constants.
注意，在 Swift 里常量总是被声明为常量
But we don't use const like in C and
但我们用的不是像 C 的 const
other languages, we use let, L-E-T.
或是其他语言那样的。我们用的是 let
And here's another cool thing. You see this little triangle?
这还有一个很酷的事情是，你看见这个小三角了吗？
If I click on it, oftentimes Swift will fix it for me.
如果我点击它，通常 Swift 会提供 Fix-it 来帮我解决问题
You see that where it says fix. It's saying,
看到这里写着 Fix 了吗？它说
you want me to replace var with let? Like yeah, sure, and
你想用 let 来代替 var 吗？好啊
it did, see? Now why do we use let instead of const?
然后它就这样做了。为什么我们用 let 而不是 const 呢？
Because we want Swift to read like English.
因为 Swift 要读起来像英文
let cardNumber = cardButtons.index of
让卡片序号等于卡片按钮数组里调用函数的按钮的索引
the sender, sounds like English to me, ish, okay? So
听起来像是通顺的英语，好吧？
that's better than const cardNumber =.
这比 常卡片序号 好一些
So you're gonna get used to using let, always use let when
所以你要习惯使用 let，总是用 let 来声明
something's a constant, never use var, all right?
常量，而不是用 var，好吧？
This other warning right here, I'm gonna ignore. And
这里还有一个警告，我先忽视掉
let's just see what happens here when we run.
让我们看看运行会发生什么？
So let's run this guy in our simulator, we're ignoring
让我们直接在模拟器运行，忽视这个
that, pay no attention to the yellow warning there.
不在意这个黄色的警告
Okay, here it is, let's click some of these buttons and
好，出来了。让我们来点这些按钮
see what happens. See, it's going to print.
然后看看发生什么。它应该会打印出来
We'll put this over on the side so you can see the code
让我们把这个放到一边，好能同时看到代码
at the same time. We're just gonna print out the cardNumber
我们只是打印出来 cardNumber
that we found by looking that index up.
通过找它的索引得到的结果
Ready, click. That's kind of weird, look at that,
准备，点。这有些奇怪，看看这个
Optional(1), Optional(2), what's that Optional about?
Optional(1)，Optional(2)，这个 Optional 是什么？
There seems to be seeing the card right, right, 0, 1, 2,
至少卡是找对了，0，1，2
but it's saying Optional, why is it saying Optional? Well,
但它一直在说 Optional，为什么呢？其实
this is that super important thing I was telling you about?
这就是我说的非常重要的知识点
Here it is. Lets option-click on index right here, and
这就是了。让我们按住 option 点击这个 index 方法
go look at it's documentation. And
我们去看看它的文档
the return value of index is not an int,
它的返回值不是普通的整数 Int
the return value of index is an optional,
返回值是可选（optional）的整数
that's what that question mark means.
这就是那个问号的意思
We've seen question marks all over in the documentation,
我们在文档里到处都可以看到问号
right? It means optional. And optional is a different
是吧？意思就是是可选的。可选类型是不一样的
type entirely from int. Okay, has nothing to do with int.
可选整型和整形完全不同，没有关联
Optional is a type that has two and only two states,
可选类型是一种类型，有且仅有两种状态
set and not set. It's an enumeration.
有值和缺省值，这是个枚举类型（enumeration）
You probably seen enumerations in other languages,
你多半在其他语言中看到过枚举类型
enumerations are things that have discreet set of values.
枚举类型是所有可能的值的集合
This one only has two values, set and not set,
可选类型只有两种值，有值和缺省值
that's it. But the cool things about enumerations in Swift,
就这样。但 Swift 枚举类型很酷的是
not a lot of other languages have this. For
并不是很多语言都有这个
each case of an enumeration you can have associated data,
每个枚举的情况都可以有关联值（associated value）
just data that goes along with that thing. Well, an optional,
就是跟随它的数据。那对于可选类型
when it's in the set state, has associated data,
处于有值的情况，就有关联值
which in this case is an int. So this index method is
在我们这里是整型 Int。所以这个 index 方法
returning whether or not it could find that button in
返回是否能找到那个按钮的信息
there by returning set or not set. And if it does find it
是通过返回有值或是缺省值。如果找到了的话
it also gives you the associated data of the int.
那就把索引作为关联值给你
That's what you're seeing down here. It's printing out,
这就是我们看到的下面这里打印出来
when we print cardNumber it says this is an optional.
打印 cardNumber 的时候会输出 Optional
It's in the set case and
它是有值的状态
the associated value is an int. Got that? Now what if we
关联值是整型，理解了吗？如果
click on the button that's not in the cardButton's array?
我们点击一个不在 cardButtons 数组里的按钮呢？
Let's see what that prints, that does right here. Oops,
我们看看会打印出什么，看看会做什么
we stopped, let's go back and run it again. I'm gonna click
我们停止运行了，那重新运行。我要按
on that fourth button that isn't in cardButton.
那不再数组里的第四个按钮
So when index looks it up it's not gonna find it.
当 index 方法在数组里找的话是找不到的
It's gonna return not set.
所以会返回缺省值
Let's see what that looks like? Click nil, N-I-L. So in
让我们看看那是什么样的。点击，出现了 nil
Swift the word nil means the not set case of an optional.
所以在 Swift 语言中，nil 代表可选类型缺省值
That's the only thing it means. In other languages,
这就是它唯一的意思。在其他语言里
it means zero pointer and other things. No, in Swift it
它意思是空指针一类的，但 Swift 里不是
always means an optional that's not set. Got that? All
它总代表可选类型缺省值，理解了吗？
right, so that's no good to me though, to have an optional.
这对我来说是不够好的，有一个可选类型
I can't look that optional up in another array of emoji,
我不能用可选类型来索引表情符号数组
I need the int. So how do I get that associated value in
我需要整数索引。那我如何在有值的情况下
the set state? Well, one way is to put
得到那个关联值呢？其中一个方法是
an exclamation point at the end of it. If you put
在后面加一个感叹号 !
an exclamation point at the end of an optional, it says,
如果你在可选类型的后面加一个感叹号，那意思是
assume this optional is set, and grab the associated value.
假设这个可选类型有值并且赋予关联值
So let's see what that looks like. You're gonna see
所以让我们看一下它是什么样子。你将会看到
this optional syntax is all really simple question mark,
这个可选类型语法的全部就是简单的疑问号
exclamation point, one characters, because it's so
感叹号，一个字符。因为它们（？和！）
common to do these optionals. All right, so
实在是太常见了。好的
here look, cardNumber = 0, 1, 2, excellent,
请看，carNumber 等于 0，1，2，棒极了
it's working. What do you think happens if I press this
它起作用了。你们认为如果我按下这个
one right here? >> Crash.
会发生什么？ >> 程序崩溃
exactly. Why is it gonna crash? Because you're
正是这样子。为什么它会崩溃？因为你正
>> Crash,
returning an option that's not in the set state, so we don't
返回一个可选类型缺省值，我们
have that associated value, so it crashes your program.
没有其关联值，所以它让你的程序崩溃了
And you're gonna see this crash quite a bit, okay,
并且你会看见不少这种崩溃
when you're developing because you'll just accidentally do
因为在你开发的过程中，你经常会做这种事情
this quite a bit of time. And if you look in your console,
并且如果你查看你的控制台
look what it says. It says an error here,
它写了什么，它会这里有一个错误:
fatal error unexpectedly found nil, that is to say not set
fatal error unexpectedly found nil，那是说可选类型缺省值
while unwrapping an optional. Get used to that error,
while unwrapping an optional。 熟悉这个错误
you see it all the time. Now, this might make you say, whoa,
你会一直看到它。现在它会让你说，哇
I'm never using exclamation points,
我绝不会再用感叹号了
gonna crash my program, scary. Yeah,
它会让我的程序崩溃，可怕
it's scary, but crashing your program can be really good,
是的，这是可怕的，但是程序崩溃其实是件好事
because it makes you find problems.
因为它让你找到了问题所在
Like in this case, that fourth button is supposed to be in
像在这个例子里，第四个按钮应该在
card buttons It's a bug that is not in card buttons. And
cardButtons 数组里，但是这是一个 bug，它并不在
if I didn't crash right there, I might not find that bug,
如果它不会立刻崩溃，我可能不会找到这个 bug
cuz I might not have clicked on that one,
因为我可能不会点击那张卡片
I might not have noticed. This way, I'm for sure gonna find,
我可能都不会注意。现在这样子，我确定我会找到这个 bug
it's gonna crash. And now it's gonna crash, it's gonna crash
它会崩溃。现在它会崩溃，它会崩溃
right where it matters, right in the debugger so
就在这个关键的地方，就在调试器里
I can look at it. So don't be afraid of crashes, okay?
所以我能看到它。所以不要害怕崩溃，好么？
Crashes can be good. But let's say you wanted to do this
崩溃可以是件好事。但是如果你想要让你的
code in a way that didn't crash,
代码用一种不会崩溃的方式书写
that kind of conditionally looked to see if it was in
可以用条件语句来判断是否它
the set state.
是有值的
And if it was, then use it, otherwise didn't do it.
如果有值，那么使用它。否则就不使用
To do that, instead of putting exclamation point at the end,
为了这样做，与在结尾放一个感叹号不同
you take that off and put if, at the beginning, okay?
你把它拿掉并且把 if 放到开头
And so now, if this optional right here is in the set state
这样一来，如果这个可选类型是有值的
then this code will execute, otherwise it won't, and won't crash. So
那么这行代码会执行，否则就不会，而且不会崩溃
that's if that's conditional, you can see again,
这是一个条件语句，你可以再看一次
optional minimum possible syntax here.
关于可选类型，最小的语法就在这里了
So now, we can put this print cardNumber inside here,
现在，我们可以把打印 cardNumber 语句放到里面
and we could even, if we wanted to, put an else.
我们甚至可以，如果我们想这样做的话，写一个 else 语句
Could something like chosen card was not in card buttons,
像这样，选中的卡片不在卡片按钮数组当中
or something like that, so we could notice that it happened.
或其他差不多的话，这样子我们能够注意到它发生了
And here we're conditionally doing it, so
这就是我们如何用条件语句来做这件事情
let's go look at this I'm gonna move,
让我们看一下结果，我要把
make this console wide here so you can see what's going on,
控制台弄宽一点以便你们能看到发生了什么
all right? So here this is still working cardNumber 0, 1,
好么? 所以它仍然可以工作 carNumber 0,1
2 because I'm using that if let right there. But now,
2 因为我正在使用 if let 的一个条件语句，但是现在
if I click on this bad button it just says chosen card was
如果我点击这个坏的按钮，它就会写着
not in card buttons, right?
选中的卡片不在卡片按钮数组里，是吧？
It says this, okay? So that's optional is how to unwrap
它是这样写的，对吧？ 所以这就是解包可选类型的方法
them. Super duper important. Really gonna have master this.
非常非常重要。真的需要掌握它
I know that's new to you. We're gonna talk about
我知道这对你们来说是新的。我们将会讨论
these exclamation points up here, that I mentioned before.
这些感叹号，正如我刚到提到的
That made it so you didn't have to initialize your thing,
它们让你不需要初始化你的变量
those are optionals as well. They're a little different
它们也是可选类型。他们只是有点不同的
kind of optional because their exclamation point instead of
可选类型，因为它们是感叹号而不是
question marks. Remember this index one right here?
疑问号。记住这里这个 index
Okay, that was a question mark one. These are exclamation
好么，这是一个疑问号。这些是感叹号
what one's they're slightly different optionals but
是有点不同的可选类型但是
they're still optional. We'll talk about that later.
他们仍然是可选类型。我们会之后继续讨论它
So the last thing I wanna do here is just take this
最后一件事情我想做的是讲讲
cardNumber that I got, and
我得到的这个 cardNumber
go look it up in an array of emojis. So I'm just gonna
并且在一个 emoji 数组中查询。所以我仅仅
make a var, I'm gonna call it emojiChoices. It's going to be
需要声明一个 var， 叫它 emojiChoices
an Array of String emoji strings basically.
是个 String 的数组，一个 emoji 字符串的数组
And you can create arrays right on a fly by doing open
然后你可以飞速创建一个数组，通过
square bracket and just put in the things in the arrays.
中括号，然后把东西放到数组里
So I'm gonna go put my emoji in here, lets go back to our
我将把我的 emoji 放到里面，让我们
emoji chooser, probably its in frequently used.
回到 emojiChoices 中，大概在 frequently used 里面
Here we go, there's the [INAUDIBLE] for
这个是
the pumpkin there, I'll put a pumpkin here.
南瓜，我会放到这里一个南瓜，放到这里一个南瓜
We'll put a ghost here, put a ghost over here,
放到这里一个幽灵，放到这里一个幽灵
all right? Now we've got that, so we're gonna look
好么。现在我们有了数组，我们查看
the cardNumber it's gonna be index 0, 1, 2, 3.
cardNumber, 它将会是索引 0，1，2，3
We're gonna look it up in here. While we're here let's
我们会在这里查询。让我们
go ahead and wire up that last wayward button that's not in
往前，关联最后一个按钮
the cardButtons array.
之前它还没有在 cardButtons 数组里
I'm gonna do that again from up here, Ctrl + drag, down to
我会再做一次，按住 control，向下拖到这里
here to put all four buttons in there. Go back to Automatic
把四个按钮都放到这里。回到 Automatic
here, and one other thing I'm gonna do is note that this,
另一件事情我要做的是，注意
is that necessary? No, because it's clear that
这里是必要的么？不，因为这是足够明确的
this is an array of strings. So if I option click on this,
它是一个字符串数组。所以如果我按住 option，点击这个
on emojiChoices right here, it says array of strings.
emojiChoices，它说这是一个字符串数组
So that again, the inferring. We would never put that colon
所以再说一次，类型推断。我们永远不要把那个冒号
array string there, never. Totally unnecessary. Okay, so
Array 放到那里，永远。完全没有必要。好了
now let's say just printing the cardNumber out right here,
现在让我们把 cardNumber 在这里打印出来
I'm going to call my flipCard. FlipCard with emoji and
我将调用我的 flipCard 函数。参数标签是 withEmoji
the emoji is gonna be emojiChoices sub cardNumber,
emoji 参数是 emojiChoices[cardNumber]
okay, and it's on the sender. Got it, let's run it.
好的，on 的参数是 sender。搞定了，让我们运行它
Okay, here we go. Pumpkin, ghost.
好的，开始吧。南瓜，幽灵
All these considered working.
所有考虑到的都运行良好
Now, we might be very proud of ourselves here because we got
现在，我们可以为自己感到骄傲因为我们
this data-driven architecture. It's really great
实现了这个数据驱动的架构。这是非常棒的
we can add more buttons now. We can make 20 buttons and
我们现在可以添加更多的按钮。我们可以添加20个按钮
all we gotta do is add more things to this array.
我们所有需要做的就是在数组里添加更多的东西
But this is actually not a very good architecture,
但是这实际上不是一个非常好的架构
because this is very fragile, okay. The number of emoji here
因为它经不起折腾。emoji 的数量
has to exactly match the number of buttons in the UI,
必须恰好匹配 UI 上按钮的数量
and you have to put them in there exactly twice.
并且你必须把他们放到那里两次
And they're not in random order,
他们还不是处于随机顺序
so the cards are always gonna be in the same place kinda
所以卡牌总是处在相同的位置
not a very good solution.
这不是一个好的解决方案
So we really need to take another step and
所以我们真的非常需要迈进另一步
have a real concentration engine driving our app, it's
拥有一个真正的翻牌游戏引擎来驱动我们的应用
doing not only all of this, but all this matching and
它将不仅做所有这些事情，还会做所有的匹配
all that stuff. Now to do that we're gonna use this design
和所有其他事情。为了实现这个目标，我们将要使用
paragraph dime I talked about the very beginning model view
我在一开始提到的 Model - View - Controller (MVC)
controller. So I'm gonna start Wednesday's lecture with some
所以我将会在周三的课上用一些幻灯片
slides explaining how model view controller works.
解释 MVC 是如何工作的
Then we're gonna apply model view controller here, and
之后我们将要把 MVC 应用在这上面
you're gonna see wow, that is a way better way, to do this.
你将会看到，哇，这是更好的实现方式
The much more flexible and
更灵活而且
extensible easy to add cards not gonna crash everything. So
扩展性更强，添加卡片更方便，任何东西都不会崩溃
I'll see you on Wednesday. >> For
所以我们下周三再见
more, please visit us at stanford.edu.
>> 更多课程详见 stanford.edu
